summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.clang-format12
-rw-r--r--.github/NPTest.cache4
-rwxr-xr-x.github/mock.sh31
-rw-r--r--.github/monitoring-plugins.spec28
-rw-r--r--.github/os_detect.sh7
-rwxr-xr-x.github/prepare_debian.sh8
-rw-r--r--.github/workflows/test-next.yml78
-rw-r--r--.github/workflows/test.yml3
-rw-r--r--.gitignore16
-rw-r--r--CODING35
-rw-r--r--Makefile.am3
-rw-r--r--NPTest.pm4
-rw-r--r--REQUIREMENTS4
-rw-r--r--ROADMAP117
-rw-r--r--SUPPORT2
-rw-r--r--configure.ac183
-rw-r--r--doc/developer-guidelines.sgml53
-rw-r--r--gl/Makefile.am321
-rw-r--r--gl/_Noreturn.h2
-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.in.h7
-rw-r--r--gl/asnprintf.c2
-rw-r--r--gl/asprintf.c2
-rw-r--r--gl/assert.in.h2
-rw-r--r--gl/attribute.h19
-rw-r--r--gl/base64.c50
-rw-r--r--gl/base64.h54
-rw-r--r--gl/basename-lgpl.c2
-rw-r--r--gl/basename-lgpl.h7
-rw-r--r--gl/basename.c2
-rw-r--r--gl/btowc.c10
-rw-r--r--gl/byteswap.in.h2
-rw-r--r--gl/c++defs.h8
-rw-r--r--gl/calloc.c2
-rw-r--r--gl/cdefs.h46
-rw-r--r--gl/cloexec.c2
-rw-r--r--gl/cloexec.h12
-rw-r--r--gl/close.c2
-rw-r--r--gl/dirname-lgpl.c2
-rw-r--r--gl/dirname.c2
-rw-r--r--gl/dirname.h8
-rw-r--r--gl/dup2.c2
-rw-r--r--gl/dynarray.h2
-rw-r--r--gl/errno.in.h2
-rw-r--r--gl/error.c7
-rw-r--r--gl/error.h66
-rw-r--r--gl/error.in.h216
-rw-r--r--gl/exitfail.c2
-rw-r--r--gl/exitfail.h12
-rw-r--r--gl/fcntl.c2
-rw-r--r--gl/fcntl.in.h7
-rw-r--r--gl/fd-hook.c2
-rw-r--r--gl/fd-hook.h2
-rw-r--r--gl/fflush.c2
-rw-r--r--gl/filename.h2
-rw-r--r--gl/float+.h2
-rw-r--r--gl/float.c2
-rw-r--r--gl/float.in.h2
-rw-r--r--gl/floor.c2
-rw-r--r--gl/floorf.c2
-rw-r--r--gl/fopen.c12
-rw-r--r--gl/fpurge.c2
-rw-r--r--gl/freading.c2
-rw-r--r--gl/freading.h7
-rw-r--r--gl/free.c2
-rw-r--r--gl/fseek.c2
-rw-r--r--gl/fseeko.c2
-rw-r--r--gl/fstat.c2
-rw-r--r--gl/fsusage.c2
-rw-r--r--gl/fsusage.h16
-rw-r--r--gl/ftell.c2
-rw-r--r--gl/ftello.c2
-rw-r--r--gl/gai_strerror.c2
-rw-r--r--gl/getaddrinfo.c2
-rw-r--r--gl/getdelim.c6
-rw-r--r--gl/getdtablesize.c2
-rw-r--r--gl/gethostname.c2
-rw-r--r--gl/getline.c2
-rw-r--r--gl/getloadavg.c2
-rw-r--r--gl/getopt-cdefs.in.h8
-rw-r--r--gl/getopt-core.h2
-rw-r--r--gl/getopt-ext.h2
-rw-r--r--gl/getopt-pfx-core.h4
-rw-r--r--gl/getopt-pfx-ext.h2
-rw-r--r--gl/getopt.c35
-rw-r--r--gl/getopt.in.h2
-rw-r--r--gl/getopt1.c4
-rw-r--r--gl/getopt_int.h2
-rw-r--r--gl/getprogname.c24
-rw-r--r--gl/getprogname.h20
-rw-r--r--gl/gettext.h2
-rw-r--r--gl/gl_openssl.h10
-rw-r--r--gl/glthread/lock.c2
-rw-r--r--gl/glthread/lock.h10
-rw-r--r--gl/glthread/threadlib.c2
-rw-r--r--gl/hard-locale.c16
-rw-r--r--gl/hard-locale.h18
-rw-r--r--gl/ialloc.c2
-rw-r--r--gl/ialloc.h68
-rw-r--r--gl/idpriv-droptemp.c2
-rw-r--r--gl/idpriv.h2
-rw-r--r--gl/idx.h12
-rw-r--r--gl/inet_ntop.c2
-rw-r--r--gl/intprops-internal.h11
-rw-r--r--gl/intprops.h2
-rw-r--r--gl/inttypes.in.h41
-rw-r--r--gl/iswblank.c26
-rw-r--r--gl/iswctype-impl.h22
-rw-r--r--gl/iswctype.c36
-rw-r--r--gl/iswdigit.c26
-rw-r--r--gl/iswpunct.c33
-rw-r--r--gl/iswxdigit.c33
-rw-r--r--gl/itold.c2
-rw-r--r--gl/langinfo.in.h9
-rw-r--r--gl/lc-charset-dispatch.c2
-rw-r--r--gl/lc-charset-dispatch.h2
-rw-r--r--gl/libc-config.h24
-rw-r--r--gl/limits.in.h32
-rw-r--r--gl/localcharset.c4
-rw-r--r--gl/localcharset.h6
-rw-r--r--gl/locale.in.h37
-rw-r--r--gl/localeconv.c47
-rw-r--r--gl/lseek.c2
-rw-r--r--gl/m4/00gnulib.m413
-rw-r--r--gl/m4/__inline.m47
-rw-r--r--gl/m4/absolute-header.m47
-rw-r--r--gl/m4/af_alg.m45
-rw-r--r--gl/m4/alloca.m45
-rw-r--r--gl/m4/arpa_inet_h.m45
-rw-r--r--gl/m4/assert_h.m427
-rw-r--r--gl/m4/base64.m45
-rw-r--r--gl/m4/btowc.m485
-rw-r--r--gl/m4/builtin-expect.m48
-rw-r--r--gl/m4/byteswap.m45
-rw-r--r--gl/m4/c-bool.m48
-rw-r--r--gl/m4/calloc.m428
-rw-r--r--gl/m4/close.m47
-rw-r--r--gl/m4/codeset.m45
-rw-r--r--gl/m4/double-slash-root.m45
-rw-r--r--gl/m4/dup2.m47
-rw-r--r--gl/m4/eealloc.m45
-rw-r--r--gl/m4/environ.m45
-rw-r--r--gl/m4/errno_h.m45
-rw-r--r--gl/m4/error.m422
-rw-r--r--gl/m4/error_h.m4125
-rw-r--r--gl/m4/exponentd.m47
-rw-r--r--gl/m4/extensions.m424
-rw-r--r--gl/m4/extern-inline.m412
-rw-r--r--gl/m4/fclose.m499
-rw-r--r--gl/m4/fcntl-o.m411
-rw-r--r--gl/m4/fcntl.m47
-rw-r--r--gl/m4/fcntl_h.m46
-rw-r--r--gl/m4/fflush.m418
-rw-r--r--gl/m4/float_h.m413
-rw-r--r--gl/m4/floorf.m429
-rw-r--r--gl/m4/fopen.m424
-rw-r--r--gl/m4/fpurge.m415
-rw-r--r--gl/m4/freading.m410
-rw-r--r--gl/m4/free.m411
-rw-r--r--gl/m4/fseek.m45
-rw-r--r--gl/m4/fseeko.m45
-rw-r--r--gl/m4/fstat.m49
-rw-r--r--gl/m4/fstypename.m414
-rw-r--r--gl/m4/fsusage.m414
-rw-r--r--gl/m4/ftell.m45
-rw-r--r--gl/m4/ftello.m430
-rw-r--r--gl/m4/getaddrinfo.m49
-rw-r--r--gl/m4/getdelim.m414
-rw-r--r--gl/m4/getdtablesize.m45
-rw-r--r--gl/m4/gethostname.m49
-rw-r--r--gl/m4/getline.m423
-rw-r--r--gl/m4/getloadavg.m437
-rw-r--r--gl/m4/getopt.m49
-rw-r--r--gl/m4/getprogname.m433
-rw-r--r--gl/m4/gl-openssl.m48
-rw-r--r--gl/m4/gnulib-cache.m42
-rw-r--r--gl/m4/gnulib-common.m4426
-rw-r--r--gl/m4/gnulib-comp.m4100
-rw-r--r--gl/m4/gnulib-tool.m45
-rw-r--r--gl/m4/hostent.m49
-rw-r--r--gl/m4/idpriv.m45
-rw-r--r--gl/m4/include_next.m413
-rw-r--r--gl/m4/inet_ntop.m49
-rw-r--r--gl/m4/intmax_t.m45
-rw-r--r--gl/m4/inttypes.m49
-rw-r--r--gl/m4/inttypes_h.m45
-rw-r--r--gl/m4/iswblank.m439
-rw-r--r--gl/m4/iswctype.m414
-rw-r--r--gl/m4/iswdigit.m4121
-rw-r--r--gl/m4/iswpunct.m449
-rw-r--r--gl/m4/iswxdigit.m4111
-rw-r--r--gl/m4/langinfo_h.m45
-rw-r--r--gl/m4/largefile.m4229
-rw-r--r--gl/m4/limits-h.m431
-rw-r--r--gl/m4/localcharset.m45
-rw-r--r--gl/m4/locale-fr.m4142
-rw-r--r--gl/m4/locale-ja.m417
-rw-r--r--gl/m4/locale-zh.m415
-rw-r--r--gl/m4/locale_h.m411
-rw-r--r--gl/m4/localeconv.m442
-rw-r--r--gl/m4/lock.m45
-rw-r--r--gl/m4/lseek.m445
-rw-r--r--gl/m4/malloc.m414
-rw-r--r--gl/m4/malloca.m45
-rw-r--r--gl/m4/math_h.m460
-rw-r--r--gl/m4/mbrtowc.m4123
-rw-r--r--gl/m4/mbsinit.m47
-rw-r--r--gl/m4/mbstate_t.m45
-rw-r--r--gl/m4/mbtowc.m410
-rw-r--r--gl/m4/memchr.m417
-rw-r--r--gl/m4/minmax.m45
-rw-r--r--gl/m4/mktime.m415
-rw-r--r--gl/m4/mmap-anon.m45
-rw-r--r--gl/m4/mode_t.m45
-rw-r--r--gl/m4/mountlist.m418
-rw-r--r--gl/m4/msvc-inval.m45
-rw-r--r--gl/m4/msvc-nothrow.m45
-rw-r--r--gl/m4/multiarch.m45
-rw-r--r--gl/m4/musl.m421
-rw-r--r--gl/m4/netdb_h.m45
-rw-r--r--gl/m4/netinet_in_h.m45
-rw-r--r--gl/m4/nl_langinfo.m412
-rw-r--r--gl/m4/nocrash.m45
-rw-r--r--gl/m4/off_t.m45
-rw-r--r--gl/m4/open-cloexec.m48
-rw-r--r--gl/m4/open-slash.m45
-rw-r--r--gl/m4/open.m47
-rw-r--r--gl/m4/pathmax.m45
-rw-r--r--gl/m4/pid_t.m45
-rw-r--r--gl/m4/printf.m4931
-rw-r--r--gl/m4/pthread_rwlock_rdlock.m443
-rw-r--r--gl/m4/realloc.m412
-rw-r--r--gl/m4/reallocarray.m410
-rw-r--r--gl/m4/regex.m423
-rw-r--r--gl/m4/servent.m49
-rw-r--r--gl/m4/setenv.m420
-rw-r--r--gl/m4/setlocale_null.m446
-rw-r--r--gl/m4/sha256.m45
-rw-r--r--gl/m4/size_max.m45
-rw-r--r--gl/m4/snprintf.m45
-rw-r--r--gl/m4/socketlib.m419
-rw-r--r--gl/m4/sockets.m45
-rw-r--r--gl/m4/socklen.m45
-rw-r--r--gl/m4/sockpfaf.m45
-rw-r--r--gl/m4/ssize_t.m431
-rw-r--r--gl/m4/stat-time.m414
-rw-r--r--gl/m4/stat.m423
-rw-r--r--gl/m4/std-gnu11.m45
-rw-r--r--gl/m4/stdalign.m4202
-rw-r--r--gl/m4/stddef_h.m420
-rw-r--r--gl/m4/stdint.m418
-rw-r--r--gl/m4/stdint_h.m45
-rw-r--r--gl/m4/stdio_h.m439
-rw-r--r--gl/m4/stdlib_h.m472
-rw-r--r--gl/m4/strcase.m45
-rw-r--r--gl/m4/strcasestr.m45
-rw-r--r--gl/m4/strerror.m433
-rw-r--r--gl/m4/string_h.m418
-rw-r--r--gl/m4/strings_h.m411
-rw-r--r--gl/m4/strsep.m45
-rw-r--r--gl/m4/strstr.m45
-rw-r--r--gl/m4/sys_socket_h.m45
-rw-r--r--gl/m4/sys_stat_h.m45
-rw-r--r--gl/m4/sys_types_h.m45
-rw-r--r--gl/m4/sys_uio_h.m45
-rw-r--r--gl/m4/threadlib.m463
-rw-r--r--gl/m4/time_h.m448
-rw-r--r--gl/m4/time_r.m412
-rw-r--r--gl/m4/timegm.m411
-rw-r--r--gl/m4/ungetc.m425
-rw-r--r--gl/m4/unistd_h.m411
-rw-r--r--gl/m4/unlocked-io.m413
-rw-r--r--gl/m4/vararrays.m414
-rw-r--r--gl/m4/vasnprintf.m4207
-rw-r--r--gl/m4/vasprintf.m45
-rw-r--r--gl/m4/visibility.m413
-rw-r--r--gl/m4/vsnprintf.m45
-rw-r--r--gl/m4/warn-on-use.m49
-rw-r--r--gl/m4/wchar_h.m425
-rw-r--r--gl/m4/wchar_t.m45
-rw-r--r--gl/m4/wcrtomb.m423
-rw-r--r--gl/m4/wctype.m452
-rw-r--r--gl/m4/wctype_h.m49
-rw-r--r--gl/m4/wint_t.m45
-rw-r--r--gl/m4/xalloc.m45
-rw-r--r--gl/m4/xsize.m45
-rw-r--r--gl/m4/zzgnulib.m45
-rw-r--r--gl/malloc.c2
-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.c6
-rw-r--r--gl/malloc/dynarray_finalize.c2
-rw-r--r--gl/malloc/dynarray_resize.c6
-rw-r--r--gl/malloc/dynarray_resize_clear.c2
-rw-r--r--gl/malloca.c41
-rw-r--r--gl/malloca.h35
-rw-r--r--gl/math.c4
-rw-r--r--gl/math.in.h404
-rw-r--r--gl/mbrtowc-impl-utf8.h2
-rw-r--r--gl/mbrtowc-impl.h2
-rw-r--r--gl/mbrtowc.c8
-rw-r--r--gl/mbsinit.c4
-rw-r--r--gl/mbszero.c23
-rw-r--r--gl/mbtowc-impl.h4
-rw-r--r--gl/mbtowc-lock.c19
-rw-r--r--gl/mbtowc-lock.h6
-rw-r--r--gl/mbtowc.c2
-rw-r--r--gl/memchr.c2
-rw-r--r--gl/memchr.valgrind2
-rw-r--r--gl/minmax.h7
-rw-r--r--gl/mktime-internal.h2
-rw-r--r--gl/mktime.c13
-rw-r--r--gl/mountlist.c21
-rw-r--r--gl/mountlist.h21
-rw-r--r--gl/msvc-inval.c2
-rw-r--r--gl/msvc-inval.h7
-rw-r--r--gl/msvc-nothrow.c2
-rw-r--r--gl/msvc-nothrow.h15
-rw-r--r--gl/netdb.in.h7
-rw-r--r--gl/netinet_in.in.h2
-rw-r--r--gl/nl_langinfo-lock.c19
-rw-r--r--gl/nl_langinfo.c23
-rw-r--r--gl/open.c8
-rw-r--r--gl/pathmax.h7
-rw-r--r--gl/printf-args.c125
-rw-r--r--gl/printf-args.h61
-rw-r--r--gl/printf-parse.c502
-rw-r--r--gl/printf-parse.h10
-rw-r--r--gl/realloc.c2
-rw-r--r--gl/reallocarray.c2
-rw-r--r--gl/regcomp.c4
-rw-r--r--gl/regex.c6
-rw-r--r--gl/regex.h2
-rw-r--r--gl/regex_internal.c2
-rw-r--r--gl/regex_internal.h8
-rw-r--r--gl/regexec.c4
-rw-r--r--gl/setenv.c8
-rw-r--r--gl/setlocale-lock.c19
-rw-r--r--gl/setlocale_null-unlocked.c149
-rw-r--r--gl/setlocale_null.c176
-rw-r--r--gl/setlocale_null.h30
-rw-r--r--gl/sha256-stream.c2
-rw-r--r--gl/sha256.c2
-rw-r--r--gl/sha256.h23
-rw-r--r--gl/size_max.h7
-rw-r--r--gl/snprintf.c2
-rw-r--r--gl/sockets.c2
-rw-r--r--gl/sockets.h16
-rw-r--r--gl/stat-time.c2
-rw-r--r--gl/stat-time.h60
-rw-r--r--gl/stat-w32.c2
-rw-r--r--gl/stat-w32.h2
-rw-r--r--gl/stat.c2
-rw-r--r--gl/stdalign.in.h137
-rw-r--r--gl/stdckdint.in.h2
-rw-r--r--gl/stddef.in.h78
-rw-r--r--gl/stdint.in.h4
-rw-r--r--gl/stdio-impl.h2
-rw-r--r--gl/stdio-read.c2
-rw-r--r--gl/stdio-write.c2
-rw-r--r--gl/stdio.in.h172
-rw-r--r--gl/stdlib.in.h374
-rw-r--r--gl/str-two-way.h2
-rw-r--r--gl/strcasecmp.c8
-rw-r--r--gl/strcasestr.c10
-rw-r--r--gl/streq.h12
-rw-r--r--gl/strerror-override.c2
-rw-r--r--gl/strerror-override.h73
-rw-r--r--gl/strerror.c2
-rw-r--r--gl/string.in.h200
-rw-r--r--gl/strings.in.h7
-rw-r--r--gl/stripslash.c2
-rw-r--r--gl/strncasecmp.c8
-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.h15
-rw-r--r--gl/sys_stat.in.h50
-rw-r--r--gl/sys_types.in.h9
-rw-r--r--gl/sys_uio.in.h2
-rw-r--r--gl/time.in.h142
-rw-r--r--gl/time_r.c7
-rw-r--r--gl/timegm.c2
-rw-r--r--gl/unistd.c4
-rw-r--r--gl/unistd.in.h140
-rw-r--r--gl/unlocked-io.h9
-rw-r--r--gl/unsetenv.c2
-rw-r--r--gl/vasnprintf.c1668
-rw-r--r--gl/vasnprintf.h7
-rw-r--r--gl/vasprintf.c2
-rw-r--r--gl/verify.h65
-rw-r--r--gl/vsnprintf.c2
-rw-r--r--gl/w32sock.h2
-rw-r--r--gl/warn-on-use.h6
-rw-r--r--gl/wchar.in.h376
-rw-r--r--gl/wcrtomb.c4
-rw-r--r--gl/wctype-h.c4
-rw-r--r--gl/wctype-impl.h96
-rw-r--r--gl/wctype.c25
-rw-r--r--gl/wctype.in.h93
-rw-r--r--gl/windows-initguard.h2
-rw-r--r--gl/windows-mutex.c2
-rw-r--r--gl/windows-mutex.h2
-rw-r--r--gl/windows-once.c2
-rw-r--r--gl/windows-once.h2
-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.h13
-rw-r--r--gl/xalloc.h14
-rw-r--r--gl/xmalloc.c16
-rw-r--r--gl/xsize.c2
-rw-r--r--gl/xsize.h20
-rw-r--r--lib/Makefile.am17
-rw-r--r--lib/extra_opts.c149
-rw-r--r--lib/extra_opts.h1
-rw-r--r--lib/maxfd.c32
-rw-r--r--lib/maxfd.h6
-rw-r--r--lib/monitoringplug.h7
-rw-r--r--lib/output.c633
-rw-r--r--lib/output.h117
-rw-r--r--lib/parse_ini.c135
-rw-r--r--lib/parse_ini.h1
-rw-r--r--lib/perfdata.c605
-rw-r--r--lib/perfdata.h219
-rw-r--r--lib/states.h71
-rw-r--r--lib/tests/Makefile.am6
-rw-r--r--lib/tests/test_base64.c308
-rw-r--r--lib/tests/test_cmd.c261
-rw-r--r--lib/tests/test_disk.c224
-rwxr-xr-xlib/tests/test_disk.t6
-rwxr-xr-xlib/tests/test_generic_outputbin0 -> 143808 bytes
-rw-r--r--lib/tests/test_generic_output.c315
-rw-r--r--lib/tests/test_generic_output.t6
-rw-r--r--lib/tests/test_ini1.c116
-rw-r--r--lib/tests/test_ini3.c37
-rw-r--r--lib/tests/test_opts1.c105
-rw-r--r--lib/tests/test_opts2.c124
-rw-r--r--lib/tests/test_opts3.c37
-rw-r--r--lib/tests/test_tcp.c48
-rw-r--r--lib/tests/test_utils.c491
-rw-r--r--lib/thresholds.c71
-rw-r--r--lib/thresholds.h31
-rw-r--r--lib/utils_base.c542
-rw-r--r--lib/utils_base.h69
-rw-r--r--lib/utils_cmd.c280
-rw-r--r--lib/utils_cmd.h20
-rw-r--r--lib/utils_disk.c270
-rw-r--r--lib/utils_disk.h52
-rw-r--r--lib/utils_tcp.c78
-rw-r--r--lib/utils_tcp.h12
-rw-r--r--lib/vendor/cJSON/cJSON.c3165
-rw-r--r--lib/vendor/cJSON/cJSON.h306
-rwxr-xr-xopttest.pl50
-rw-r--r--plugins-root/Makefile.am7
-rw-r--r--plugins-root/check_dhcp.c1558
-rw-r--r--plugins-root/check_dhcp.d/config.h50
-rw-r--r--plugins-root/check_icmp.c3449
-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/t/check_dhcp.t24
-rw-r--r--plugins-root/t/check_icmp.t58
-rwxr-xr-xplugins-scripts/check_ifstatus.pl45
-rwxr-xr-xplugins-scripts/check_rpc.pl6
-rw-r--r--[-rwxr-xr-x]plugins-scripts/check_sensors.sh1
-rw-r--r--plugins/Makefile.am64
-rw-r--r--plugins/check_apt.c683
-rw-r--r--plugins/check_apt.d/config.h41
-rw-r--r--plugins/check_by_ssh.c720
-rw-r--r--plugins/check_by_ssh.d/config.h56
-rw-r--r--plugins/check_cluster.c312
-rw-r--r--plugins/check_cluster.d/config.h27
-rw-r--r--plugins/check_curl.c4587
-rw-r--r--plugins/check_dbi.c1040
-rw-r--r--plugins/check_dbi.d/config.h63
-rw-r--r--plugins/check_dig.c663
-rw-r--r--plugins/check_dig.d/config.h40
-rw-r--r--plugins/check_disk.c2257
-rw-r--r--plugins/check_disk.d/utils_disk.c517
-rw-r--r--plugins/check_disk.d/utils_disk.h157
-rw-r--r--plugins/check_dns.c1162
-rw-r--r--plugins/check_dns.d/config.h34
-rw-r--r--plugins/check_dummy.c195
-rw-r--r--plugins/check_fping.c1034
-rw-r--r--plugins/check_fping.d/config.h82
-rw-r--r--plugins/check_game.c592
-rw-r--r--plugins/check_game.d/config.h30
-rw-r--r--plugins/check_hpjd.c539
-rw-r--r--plugins/check_hpjd.d/config.h25
-rw-r--r--plugins/check_http.c16
-rw-r--r--plugins/check_ide_smart.c580
-rw-r--r--plugins/check_ldap.c604
-rw-r--r--plugins/check_ldap.d/config.h60
-rw-r--r--plugins/check_load.c652
-rw-r--r--plugins/check_load.d/config.h30
-rw-r--r--plugins/check_mrtg.c531
-rw-r--r--plugins/check_mrtg.d/config.h36
-rw-r--r--plugins/check_mrtgtraf.c503
-rw-r--r--plugins/check_mrtgtraf.d/config.h30
-rw-r--r--plugins/check_mysql.c808
-rw-r--r--plugins/check_mysql.d/config.h58
-rw-r--r--plugins/check_mysql_query.c453
-rw-r--r--plugins/check_mysql_query.d/config.h36
-rw-r--r--plugins/check_nagios.c422
-rw-r--r--plugins/check_nagios.d/config.h19
-rw-r--r--plugins/check_nt.c1179
-rw-r--r--plugins/check_nt.d/config.h53
-rw-r--r--plugins/check_ntp.c12
-rw-r--r--plugins/check_ntp_peer.c845
-rw-r--r--plugins/check_ntp_peer.d/config.h67
-rw-r--r--plugins/check_ntp_time.c704
-rw-r--r--plugins/check_ntp_time.d/config.h28
-rw-r--r--plugins/check_nwstat.c1740
-rw-r--r--plugins/check_overcr.c469
-rw-r--r--plugins/check_pgsql.c737
-rw-r--r--plugins/check_pgsql.d/config.h61
-rw-r--r--plugins/check_ping.c854
-rw-r--r--plugins/check_ping.d/config.h46
-rw-r--r--plugins/check_procs.c1143
-rw-r--r--plugins/check_procs.d/config.h75
-rw-r--r--plugins/check_radius.c545
-rw-r--r--plugins/check_radius.d/config.h42
-rw-r--r--plugins/check_real.c575
-rw-r--r--plugins/check_real.d/config.h37
-rw-r--r--plugins/check_smtp.c1159
-rw-r--r--plugins/check_smtp.d/config.h92
-rw-r--r--plugins/check_snmp.c1265
-rw-r--r--plugins/check_ssh.c522
-rw-r--r--plugins/check_ssh.d/config.h29
-rw-r--r--plugins/check_swap.c837
-rw-r--r--plugins/check_swap.d/check_swap.h48
-rw-r--r--plugins/check_swap.d/swap.c465
-rw-r--r--plugins/check_tcp.c1151
-rw-r--r--plugins/check_tcp.d/config.h84
-rw-r--r--plugins/check_time.c520
-rw-r--r--plugins/check_time.d/config.h42
-rw-r--r--plugins/check_ups.c372
-rw-r--r--plugins/check_ups.d/config.h55
-rw-r--r--plugins/check_users.c291
-rw-r--r--plugins/common.h25
-rw-r--r--plugins/negate.c354
-rw-r--r--plugins/negate.d/config.h24
-rw-r--r--plugins/netutils.c295
-rw-r--r--plugins/picohttpparser/picohttpparser.c1101
-rw-r--r--plugins/popen.c284
-rw-r--r--plugins/runcmd.c257
-rw-r--r--plugins/sslutils.c229
-rw-r--r--plugins/t/check_disk.t220
-rw-r--r--plugins/t/check_ftp.t2
-rw-r--r--plugins/t/check_http.t2
-rw-r--r--plugins/t/check_jabber.t6
-rw-r--r--plugins/t/check_ldap.t2
-rw-r--r--plugins/t/check_load.t18
-rw-r--r--plugins/t/check_mysql.t32
-rw-r--r--plugins/t/check_ntp.t2
-rw-r--r--plugins/t/check_smtp.t3
-rw-r--r--plugins/t/check_ssh.t114
-rw-r--r--plugins/t/check_swap.t58
-rw-r--r--plugins/t/check_tcp.t12
-rw-r--r--plugins/t/check_udp.t4
-rw-r--r--plugins/tests/test_check_disk.c197
-rwxr-xr-xplugins/tests/test_check_disk.t6
-rw-r--r--plugins/tests/test_check_swap.c23
-rwxr-xr-xplugins/tests/test_check_swap.t6
-rw-r--r--plugins/tests/var/proc_meminfo55
-rw-r--r--plugins/urlize.c195
-rw-r--r--plugins/utils.c722
-rw-r--r--plugins/utils.h154
-rw-r--r--tap/tap.c140
-rw-r--r--tap/tap.h60
-rw-r--r--tap/tests/diag/test.c4
-rw-r--r--tap/tests/fail/test.c4
-rw-r--r--tap/tests/ok/ok-hash/test.c8
-rw-r--r--tap/tests/ok/ok-numeric/test.c4
-rw-r--r--tap/tests/ok/ok/test.c4
-rw-r--r--tap/tests/pass/test.c4
-rw-r--r--tap/tests/plan/no-tests/test.c4
-rw-r--r--tap/tests/plan/no_plan/test.c4
-rw-r--r--tap/tests/plan/not-enough-tests/test.c4
-rw-r--r--tap/tests/plan/sane/test.c4
-rw-r--r--tap/tests/plan/skip_all/test.c4
-rw-r--r--tap/tests/plan/too-many-plans/test.c4
-rw-r--r--tap/tests/plan/too-many-tests/test.c4
-rw-r--r--tap/tests/skip/test.c12
-rw-r--r--tap/tests/todo/test.c6
-rwxr-xr-xtools/opttest.pl74
-rwxr-xr-xtools/tinderbox_build290
595 files changed, 40421 insertions, 28185 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 00000000..0ff68114
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,12 @@
1UseTab: ForContinuationAndIndentation
2IndentWidth: 4
3TabWidth: 4
4AllowShortIfStatementsOnASingleLine: false
5BreakBeforeBraces: Attach
6AlignConsecutiveMacros: true
7ColumnLimit: 100
8IndentPPDirectives: AfterHash
9SortIncludes: Never
10AllowShortEnumsOnASingleLine: false
11BinPackArguments: true
12InsertBraces: true
diff --git a/.github/NPTest.cache b/.github/NPTest.cache
index d488d1b9..6b463e74 100644
--- a/.github/NPTest.cache
+++ b/.github/NPTest.cache
@@ -38,8 +38,8 @@
38 'NP_MYSQL_LOGIN_DETAILS' => '-u root -d test', 38 'NP_MYSQL_LOGIN_DETAILS' => '-u root -d test',
39 'NP_MYSQL_SERVER' => 'localhost', 39 'NP_MYSQL_SERVER' => 'localhost',
40 'NP_MYSQL_SOCKET' => '/var/run/mysqld/mysqld.sock', 40 'NP_MYSQL_SOCKET' => '/var/run/mysqld/mysqld.sock',
41 'NP_MYSQL_WITH_SLAVE' => '', 41 'NP_MYSQL_WITH_REPLICA' => '',
42 'NP_MYSQL_WITH_SLAVE_LOGIN' => '', 42 'NP_MYSQL_WITH_REPLICA_LOGIN' => '',
43 'NP_NO_NTP_SERVICE' => 'localhost', 43 'NP_NO_NTP_SERVICE' => 'localhost',
44 'NP_PORT_TCP_PROXY' => '3128', 44 'NP_PORT_TCP_PROXY' => '3128',
45 'NP_SMB_SHARE' => '', 45 'NP_SMB_SHARE' => '',
diff --git a/.github/mock.sh b/.github/mock.sh
index 7fbe6903..8f84756c 100755
--- a/.github/mock.sh
+++ b/.github/mock.sh
@@ -2,6 +2,8 @@
2 2
3set -x 3set -x
4 4
5set -euo pipefail
6
5export DEBIAN_FRONTEND=noninteractive 7export DEBIAN_FRONTEND=noninteractive
6 8
7BASE_PATH="/src" 9BASE_PATH="/src"
@@ -18,7 +20,11 @@ SPEC_FILE="${SPEC_DIR}monitoring-plugins.spec"
18cd ${BASE_PATH} 20cd ${BASE_PATH}
19 21
20dnf -y --setopt="tsflags=nodocs" update && \ 22dnf -y --setopt="tsflags=nodocs" update && \
21 if [ ${distro_id} != "fedora" ]; then dnf -y --setopt="tsflags=nodocs" install epel-release; else platform_id="$(echo ${platform_id} | sed s/^f/fc/)"; fi && \ 23 if [ "${distro_id}" != "fedora" ]; then
24 dnf -y --setopt="tsflags=nodocs" install epel-release;
25 else
26 platform_id="$(echo "${platform_id}" | sed s/^f/fc/)";
27 fi && \
22 case ${distro_id} in 28 case ${distro_id} in
23 ol) 29 ol)
24 case ${platform_id} in 30 case ${platform_id} in
@@ -32,19 +38,30 @@ dnf -y --setopt="tsflags=nodocs" update && \
32 ;; 38 ;;
33 esac 39 esac
34 dnf -y --setopt="tsflags=nodocs" install mock rpm-build git-core && \ 40 dnf -y --setopt="tsflags=nodocs" install mock rpm-build git-core && \
35 usermod -a -G mock $(whoami) 41 usermod -a -G mock "$(whoami)"
42
36SRC_RPM="monitoring-plugins-*-1.${platform_id}.src.rpm" 43SRC_RPM="monitoring-plugins-*-1.${platform_id}.src.rpm"
44
37if command -v git > /dev/null 2>&1; then 45if command -v git > /dev/null 2>&1; then
38 git config --global --add safe.directory ${BASE_PATH} 46 git config --global --add safe.directory ${BASE_PATH}
39 SHA="$(git rev-parse HEAD)" 47 SHA="$(git rev-parse HEAD)"
40 sed "s/^%global commit.*/%global commit ${SHA}/" ${SPEC_FILE} > ${SPEC_DIR}monitoring-plugins-git.spec 48 sed "s/^%global commit.*/%global commit ${SHA}/" ${SPEC_FILE} > ${SPEC_DIR}monitoring-plugins-git.spec
41 sed -i "s/^%global fromgit.*/%global fromgit 1/" ${SPEC_DIR}monitoring-plugins-git.spec 49 sed -i "s/^%global fromgit.*/%global fromgit 1/" ${SPEC_DIR}monitoring-plugins-git.spec
42 SPEC_FILE="${SPEC_DIR}monitoring-plugins-git.spec" 50 SPEC_FILE="${SPEC_DIR}monitoring-plugins-git.spec"
43 SRC_RPM="monitoring-plugins-*git.$(echo ${SHA:0:7})*.${platform_id}.src.rpm" 51 SRC_RPM="monitoring-plugins-*git.${SHA:0:7}*.${platform_id}.src.rpm"
44fi 52fi
53
45mkdir -p "${SRCRPM_DIR}" "${RPM_DIR}" 54mkdir -p "${SRCRPM_DIR}" "${RPM_DIR}"
46#rpmbuild --undefine=_disable_source_fetch --define "_sourcedir ${SOURCE_DIR}" -ba ${SPEC_FILE} 55
47dnf -y --setopt="tsflags=nodocs" install rpmdevtools && spectool -g -C ${SOURCE_DIR} ${SPEC_FILE} && \ 56# Run mock below
48mock --dnf --clean --spec ${SPEC_FILE} --sources=${SOURCE_DIR} --result=${SRCRPM_DIR} --build || { cat ${SRCRPM_DIR}/{root,build}.log; exit 1; } 57# No idea what happens here to be honest
49mock --dnf --clean --sources=${SOURCE_DIR} --result=${RPM_DIR} --rebuild ${SRCRPM_DIR}/${SRC_RPM} || { cat ${RPM_DIR}/{root,build}.log; exit 1; } 58# mock seems to run more containers to build the package
59dnf -y --setopt="tsflags=nodocs" install rpmdevtools && \
60 spectool -g -C ${SOURCE_DIR} ${SPEC_FILE} && \
61 mock --init && \
62 { mock --no-clean --spec ${SPEC_FILE} --sources=${SOURCE_DIR} --result=${SRCRPM_DIR} --buildsrpm || \
63 { cat ${SRCRPM_DIR}/{root,build}.log; exit 1; } } && \
64 { mock --no-clean --sources=${SOURCE_DIR} --result=${RPM_DIR} --rebuild "${SRCRPM_DIR}"/${SRC_RPM} || \
65 { cat ${RPM_DIR}/{root,build}.log; exit 1; } }
66
50ls -la ${SOURCE_DIR} ${SRCRPM_DIR} ${RPM_DIR} 67ls -la ${SOURCE_DIR} ${SRCRPM_DIR} ${RPM_DIR}
diff --git a/.github/monitoring-plugins.spec b/.github/monitoring-plugins.spec
index 5cae3e59..10799128 100644
--- a/.github/monitoring-plugins.spec
+++ b/.github/monitoring-plugins.spec
@@ -191,9 +191,7 @@ Requires: %{name}-nt
191Requires: %{name}-ntp 191Requires: %{name}-ntp
192Requires: %{name}-ntp_peer 192Requires: %{name}-ntp_peer
193Requires: %{name}-ntp_time 193Requires: %{name}-ntp_time
194Requires: %{name}-nwstat
195Requires: %{name}-oracle 194Requires: %{name}-oracle
196Requires: %{name}-overcr
197Requires: %{name}-pgsql 195Requires: %{name}-pgsql
198Requires: %{name}-ping 196Requires: %{name}-ping
199Requires: %{name}-procs 197Requires: %{name}-procs
@@ -703,19 +701,6 @@ Provides check_ntp_time of the Monitoring Plugins.
703 701
704 702
705 703
706# check_nwstat
707%package nwstat
708Summary: Monitoring Plugins - check_nwstat
709Requires: %{name} = %{version}-%{release}
710
711%description nwstat
712Provides check_nwstat of the Monitoring Plugins.
713
714%files nwstat
715%{plugindir}/check_nwstat
716
717
718
719# check_oracle 704# check_oracle
720%package oracle 705%package oracle
721Summary: Monitoring Plugins - check_oracle 706Summary: Monitoring Plugins - check_oracle
@@ -729,19 +714,6 @@ Provides check_oracle of the Monitoring Plugins.
729 714
730 715
731 716
732# check_overcr
733%package overcr
734Summary: Monitoring Plugins - check_overcr
735Requires: %{name} = %{version}-%{release}
736
737%description overcr
738Provides check_overcr of the Monitoring Plugins.
739
740%files overcr
741%{plugindir}/check_overcr
742
743
744
745# check_pgsql 717# check_pgsql
746%package pgsql 718%package pgsql
747Summary: Monitoring Plugins - check_pgsql 719Summary: Monitoring Plugins - check_pgsql
diff --git a/.github/os_detect.sh b/.github/os_detect.sh
index ee9c145d..47c762d3 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"
diff --git a/.github/prepare_debian.sh b/.github/prepare_debian.sh
index 3f4674a2..f7b6cf9f 100755
--- a/.github/prepare_debian.sh
+++ b/.github/prepare_debian.sh
@@ -1,7 +1,7 @@
1#!/bin/bash 1#!/bin/bash
2 2
3set -x 3set -x
4set -e 4set -euo pipefail
5 5
6export DEBIAN_FRONTEND=noninteractive 6export DEBIAN_FRONTEND=noninteractive
7 7
@@ -59,9 +59,11 @@ apt-get -y install perl \
59 mariadb-server \ 59 mariadb-server \
60 mariadb-client \ 60 mariadb-client \
61 libmariadb-dev \ 61 libmariadb-dev \
62 libmariadb-dev-compat \
62 cron \ 63 cron \
63 iputils-ping \ 64 iputils-ping \
64 iproute2 65 iproute2 \
66 libjson-perl
65 67
66# remove ipv6 interface from hosts 68# remove ipv6 interface from hosts
67sed '/^::1/d' /etc/hosts > /tmp/hosts 69sed '/^::1/d' /etc/hosts > /tmp/hosts
@@ -127,5 +129,5 @@ sed "/NP_HOST_TLS_CERT/s/.*/'NP_HOST_TLS_CERT' => '$(hostname)',/" -i /src/.gith
127 129
128# create some test files to lower inodes 130# create some test files to lower inodes
129for i in $(seq 10); do 131for i in $(seq 10); do
130 touch /media/ramdisk2/test.$1 132 touch /media/ramdisk2/test.$i
131done 133done
diff --git a/.github/workflows/test-next.yml b/.github/workflows/test-next.yml
new file mode 100644
index 00000000..fd59e85d
--- /dev/null
+++ b/.github/workflows/test-next.yml
@@ -0,0 +1,78 @@
1---
2name: Tests Debian:Testing and Fedora:Rawhide
3
4on:
5 workflow_dispatch: {}
6 push:
7 branches-ignore:
8 - '*'
9 schedule:
10 # Run every week on Monday at 9:00 AM (UTC)
11 - cron: '0 9 * * 1'
12
13jobs:
14 full-test:
15 name: Running unit and integrationt tests
16 runs-on: ubuntu-latest
17 strategy:
18 fail-fast: false
19 matrix:
20 distro:
21 - 'debian:testing'
22 include:
23 - distro: 'debian:testing'
24 prepare: .github/prepare_debian.sh
25 steps:
26 - name: Git clone repository
27 uses: actions/checkout@v4
28 - name: Run the tests on ${{ matrix.distro }}
29 run: |
30 docker volume create --driver local --opt type=tmpfs --opt device=tmpfs --opt o=size=100m,uid=1000 tmp-vol
31 docker run \
32 -e NPTEST_ACCEPTDEFAULT=1 \
33 -e NPTEST_CACHE="/src/.github/NPTest.cache" \
34 -w /src -v ${PWD}:/src \
35 --tmpfs /media/ramdisk1 \
36 -v /var/run/utmp:/var/run/utmp \
37 --mount source=tmp-vol,destination=/src,target=/media/ramdisk2 \
38 ${{ matrix.distro }} \
39 /bin/sh -c '${{ matrix.prepare }} && \
40 tools/setup && \
41 ./configure --enable-libtap && \
42 make && \
43 make test && \
44 make dist && \
45 tar zxf monitoring-plugins-*.tar.gz && \
46 cd monitoring-plugins-*/ && \
47 ./configure && \
48 make'
49 docker container prune -f
50 docker volume prune -f
51
52 build-test:
53 name: Running rpm build test on ${{ matrix.distro }}
54 runs-on: ubuntu-latest
55 strategy:
56 fail-fast: false
57 matrix:
58 include:
59 - {"distro": "fedora:rawhide", "build": ".github/mock.sh"}
60 steps:
61 - name: Git clone repository
62 uses: actions/checkout@v4
63 - name: Run the tests on ${{ matrix.distro }}
64 run: |
65 docker volume create --driver local --opt type=tmpfs --opt device=tmpfs --opt o=size=100m,uid=1000 tmp-vol
66 docker run \
67 --privileged=true \
68 -e NPTEST_ACCEPTDEFAULT=1 \
69 -e NPTEST_CACHE="/src/.github/NPTest.cache" \
70 -w /src -v ${PWD}:/src \
71 --tmpfs /media/ramdisk1 \
72 -v /var/run/utmp:/var/run/utmp \
73 --mount source=tmp-vol,destination=/src,target=/media/ramdisk2 \
74 ${{ matrix.distro }} \
75 /bin/sh -c '${{ matrix.build }} && \
76 ls -la'
77 docker container prune -f
78 docker volume prune -f
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 33220d6d..ce0ec547 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -35,7 +35,7 @@ jobs:
35 ${{ matrix.distro }} \ 35 ${{ matrix.distro }} \
36 /bin/sh -c '${{ matrix.prepare }} && \ 36 /bin/sh -c '${{ matrix.prepare }} && \
37 tools/setup && \ 37 tools/setup && \
38 ./configure --enable-libtap --with-ipv6=no && \ 38 ./configure --enable-libtap && \
39 make && \ 39 make && \
40 make test && \ 40 make test && \
41 make dist && \ 41 make dist && \
@@ -54,7 +54,6 @@ jobs:
54 matrix: 54 matrix:
55 include: 55 include:
56 - {"distro": "fedora:latest", "build": ".github/mock.sh"} 56 - {"distro": "fedora:latest", "build": ".github/mock.sh"}
57 - {"distro": "fedora:rawhide", "build": ".github/mock.sh"}
58 - {"distro": "rockylinux:8", "build": ".github/mock.sh"} 57 - {"distro": "rockylinux:8", "build": ".github/mock.sh"}
59 - {"distro": "almalinux:9", "build": ".github/mock.sh"} 58 - {"distro": "almalinux:9", "build": ".github/mock.sh"}
60# - {"distro": "oraclelinux:9", "build": ".github/mock.sh"} 59# - {"distro": "oraclelinux:9", "build": ".github/mock.sh"}
diff --git a/.gitignore b/.gitignore
index 6f903d61..8b14f429 100644
--- a/.gitignore
+++ b/.gitignore
@@ -58,6 +58,7 @@ NP-VERSION-FILE
58/gl/charset.alias 58/gl/charset.alias
59/gl/configmake.h 59/gl/configmake.h
60/gl/errno.h 60/gl/errno.h
61/gl/error.h
61/gl/fcntl.h 62/gl/fcntl.h
62/gl/float.h 63/gl/float.h
63/gl/getopt.h 64/gl/getopt.h
@@ -102,6 +103,8 @@ NP-VERSION-FILE
102/lib/libmonitoringplug.a 103/lib/libmonitoringplug.a
103/lib/Makefile 104/lib/Makefile
104/lib/Makefile.in 105/lib/Makefile.in
106/lib/vendor/cJSON/.deps
107/lib/vendor/cJSON/.dirstamp
105 108
106# /lib/tests/ 109# /lib/tests/
107/lib/tests/base64.Po 110/lib/tests/base64.Po
@@ -111,7 +114,6 @@ NP-VERSION-FILE
111/lib/tests/Makefile.in 114/lib/tests/Makefile.in
112/lib/tests/test_base64 115/lib/tests/test_base64
113/lib/tests/test_cmd 116/lib/tests/test_cmd
114/lib/tests/test_disk
115/lib/tests/test_tcp 117/lib/tests/test_tcp
116/lib/tests/test_utils 118/lib/tests/test_utils
117/lib/tests/utils_base.Po 119/lib/tests/utils_base.Po
@@ -150,6 +152,8 @@ NP-VERSION-FILE
150/plugins/check_dbi 152/plugins/check_dbi
151/plugins/check_dig 153/plugins/check_dig
152/plugins/check_disk 154/plugins/check_disk
155plugins/check_disk.d/.deps/
156plugins/check_disk.d/.dirstamp
153/plugins/check_dns 157/plugins/check_dns
154/plugins/check_dummy 158/plugins/check_dummy
155/plugins/check_fping 159/plugins/check_fping
@@ -174,8 +178,6 @@ NP-VERSION-FILE
174/plugins/check_ntp 178/plugins/check_ntp
175/plugins/check_ntp_peer 179/plugins/check_ntp_peer
176/plugins/check_ntp_time 180/plugins/check_ntp_time
177/plugins/check_nwstat
178/plugins/check_overcr
179/plugins/check_pgsql 181/plugins/check_pgsql
180/plugins/check_ping 182/plugins/check_ping
181/plugins/check_pop 183/plugins/check_pop
@@ -220,8 +222,14 @@ NP-VERSION-FILE
220/plugins/tests/Makefile 222/plugins/tests/Makefile
221/plugins/tests/Makefile.in 223/plugins/tests/Makefile.in
222/plugins/tests/test_utils 224/plugins/tests/test_utils
223/plugins/tests/test_disk 225/plugins/tests/test_check_disk
226/plugins/tests/test_check_swap
224/plugins/tests/.deps 227/plugins/tests/.deps
228/plugins/tests/.dirstamp
229
230# /plugins/check_swap.d
231/plugins/check_swap.d/.deps
232/plugins/check_swap.d/.dirstamp
225 233
226# /plugins-root/ 234# /plugins-root/
227/plugins-root/.deps 235/plugins-root/.deps
diff --git a/CODING b/CODING
index 74438e7c..d0673e7e 100644
--- a/CODING
+++ b/CODING
@@ -7,33 +7,20 @@ readability in a wide range of environments.
7 7
81. C Language Programming 81. C Language Programming
9 9
10All code should comply with the requirements of the Free Software 10All code should comply with most of the requirements of the Free Software
11Foundation Coding standards (which are currently available at 11Foundation Coding standards (which are currently available at
12http://www.gnu.org/prep/standards_toc.html). We also follow most of 12https://www.gnu.org/prep/standards/standards.html ).
13the FSF guidelines. Developers may suggest deviations from the FSF 13We also follow most of the FSF guidelines, with the huge and explicit
14exception of the style guidelines.
15Developers may suggest deviations from the FSF
14style recommendations, which will be considered by open discussion on 16style recommendations, which will be considered by open discussion on
15the Monitoring Plugins devel mailing list. Any such deviations will 17the Monitoring Plugins devel mailing list or the Github Pull Request.
16apply to the entire code base to ensure consistency. 18Any such deviations should be
17 19applied to the entire code base to ensure consistency.
18Currently, the exceptions to FSF recommendations are roughly equivalent
19to GNU indent with invoked as 'indent -ts 2 -br'. Specifically, the
20exceptions are as follows:
21
22a) leading white space for a statement should be formatted as tabs,
23with one tab for each code indentation level.
24
25b) in statement continuation lines, format whitespace up to the column
26starting the statement as tabs, format the rest as spaces (this
27results in code that is legible regardless of tab-width setting).
28
29c) with the exception of the above, tabs should generally be avoided
30
31d) when tab width is 2 spaces, line-length should not exceed 80
32characters
33
34e) The opening brace of an if or while block is on the same line as
35the end of the conditional expression (the '-br' option).
36 20
21The style guideline is the following:
22Whatever clang-format does with the configuration file available (.clang-format)
23Apart from that, code should naturally be readable and easy to understand.
37 24
382. Perl Language Programming 252. Perl Language Programming
39 26
diff --git a/Makefile.am b/Makefile.am
index 5959f70f..f8e3de45 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -7,8 +7,7 @@ EXTRA_DIST = config.rpath \
7 NP-VERSION-GEN REQUIREMENTS SUPPORT THANKS \ 7 NP-VERSION-GEN REQUIREMENTS SUPPORT THANKS \
8 NPTest.pm pkg \ 8 NPTest.pm pkg \
9 config_test/Makefile config_test/run_tests config_test/child_test.c \ 9 config_test/Makefile config_test/run_tests config_test/child_test.c \
10 perlmods tools/build_perl_modules \ 10 perlmods tools/build_perl_modules
11 tools/tinderbox_build
12 11
13ACLOCAL_AMFLAGS = -I gl/m4 -I m4 12ACLOCAL_AMFLAGS = -I gl/m4 -I m4
14 13
diff --git a/NPTest.pm b/NPTest.pm
index 9b25ac3e..1c008589 100644
--- a/NPTest.pm
+++ b/NPTest.pm
@@ -15,6 +15,8 @@ use warnings;
15use Cwd; 15use Cwd;
16use File::Basename; 16use File::Basename;
17 17
18use JSON;
19
18use IO::File; 20use IO::File;
19use Data::Dumper; 21use Data::Dumper;
20 22
@@ -617,6 +619,8 @@ sub testCmd {
617 chomp $output; 619 chomp $output;
618 $object->output($output); 620 $object->output($output);
619 621
622 eval { $object->{'mp_test_result'} = decode_json($output) };
623
620 alarm(0); 624 alarm(0);
621 625
622 my ($pkg, $file, $line) = caller(0); 626 my ($pkg, $file, $line) = caller(0);
diff --git a/REQUIREMENTS b/REQUIREMENTS
index f3b1c01d..551fdb1a 100644
--- a/REQUIREMENTS
+++ b/REQUIREMENTS
@@ -87,10 +87,6 @@ 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: 90check_nt:
95 - Requires NSClient to run on the NT server to monitor 91 - Requires NSClient to run on the NT server to monitor
96 http://nsclient.ready2run.nl/ 92 http://nsclient.ready2run.nl/
diff --git a/ROADMAP b/ROADMAP
deleted file mode 100644
index 6378ec74..00000000
--- a/ROADMAP
+++ /dev/null
@@ -1,117 +0,0 @@
1
2Releases in the 1.3 series will be for development. Version 1.4.0 will
3be the next full production release. I am not planning on dates right now,
4but you can expect maintennence releases for 1.2.9 as well.
5
6With that done, it's time to figure out what we are doing for release
71.3 development. I have a few ideas. Maybe others do as well.
8
9DOCUMENTATION:
10 We pretty much have decided that we will doing something along
11 the lines of a literate programming model. So far, we have site
12 documentation in DocBook. I have some ideas here, which I will
13 discuss in a separate thread.
14
15
16
17OPTION PROCESSING:
18 I believe we can remove reverse compatibility for non-Getopt
19 option specifications. For example, 'check_ping 1 2 3 4 -p 2'
20 would not be supported anymore. Support for this is a hack,
21 and making it portable is bug-prone. We should also review
22 standardization of our options -- the current list is a little
23 ad hoc, it should be nailed down. Details in a separate thread.
24
25Also,
26
27 check_http -p 443 --ssl www.infoplease.com
28
29should be fine, but if the getopt in use does not natively support it,
30things like
31
32 check_http www.infoplease.com -p 443 --ssl
33
34should be trapped and result in a call to one of the usage macros
35(which print a message and then exit STATE_UNKNOWN).
36
37This means that the call_getopt() function can go away. It's an
38inconsistent mess and I'd love to ditch it. I only created it to
39satisfy people that wanted reverse compatibility and did not have
40GNU getopt.
41
42But I would like to urge that all standard plugins contain
43validate_arguments(). I think this will help convey the idea that
44validations should be done, even if we don't insist on the specific
45extent that each plugin must do that validation.
46
47This is the set of standard options I envision:
48
49Reserved:
50
51-h, --help (REQUIRED!!!!!)
52-V, --version (REQUIRED!!!!!)
53-v, --verbose
54-q, --quiet
55-t, --timeout = INTEGER (senonds)
56-c, --critical = (INT|FLOAT|RANGE|LIST)
57-w, --warning = (INT|FLOAT|RANGE|LIST)
58-H, --hostname = STRING
59-F, --file = STRING (usually input)
60-O, --output = STRING (output file)
61
62Recommended, but not reserved:
63
64-I, --ipaddress = STRING
65-C, --community = STRING
66-a, --auth(info) = STRING (authentication or password)
67-l, --logname = STRING
68-p, --password = STRING
69-P, --port = INT
70-u, --url = STRING (also --username if --url is not needed)
71
72I am suggesting that port always be '-P' (uppercase) -- we are
73currently inconsistent in that regard.
74
75I am also adding '-q' for silent running. This is totally self
76centered--I am planning to use a plugin in a cron script, and I
77don't want nightly emails.
78
79As has been the case, ranges are specified with colons, like 'i:j'
80and list are specified with commas like 'i,k' and may contain ranges
81if it makes sense to do so. Perhaps it would be good to build a
82standard list/range processing function for this task.
83
84
85Programming:
86 I would like to follow the GNU guidelines and remove all fixed
87 length character assignments, at least to the extent possible,
88 from the C-based plugins. To that end, I have made strscpy and
89 friends in utils.c -- I'd like to deploy them. I have comments
90 that there is a lot of duplicated code, and techniques used that
91 should be cleaned up. Details in a separate thread.
92
93Remote checks:
94 I have a proposal in hand to incorporate ssh check into spopen()
95 so that remote machine checks can be seamless. A nice idea, but
96 complex enough to require discussion. Another thread.
97
98I also have a wish list, and I'm sure I've forgot some items. I'll
99list mine, please respond with other items that can be put into the
100sourceforge task manager:
101
102 Indent all code in a GNU-compatible manner (indent -ts 2 -br)
103 Add RAND_seed to check_http for --ssl on systems without /dev/random
104 Add regex filtering to check_procs --args option
105 Add working procs syntax for AIX check_procs
106 Allow check_disk to exclude non-local disks
107 Add md5 checksumming to check_http
108 Complete unification of check_tcp and friends
109 Add SSL in a general way to check_tcp and friends
110 Patches to check_log from Joonas
111 Add calculator engine and snmpwalk to check_snmp
112 Is there a bug in check_oracle
113 Are there outstanding bugs in check_snmp
114 Change check_http --onredirect to default as STATE_UNKNOWN
115 Create plugin to check tftp servers
116 Create plugin wrapper to invert error status
117
diff --git a/SUPPORT b/SUPPORT
index d2a2b7de..d98c6c16 100644
--- a/SUPPORT
+++ b/SUPPORT
@@ -8,7 +8,7 @@ support offerings.
8 8
9There are two mailing lists associated with Monitoring Plugins development: 9There are two mailing lists associated with Monitoring Plugins development:
10'help' (mailto:help@monitoring-plugins.org), and 'devel' 10'help' (mailto:help@monitoring-plugins.org), and 'devel'
11(mailto:help@monitoring-plugins.org). Unless you are fairly 11(mailto:devel@monitoring-plugins.org). Unless you are fairly
12certain you have found a bug or that you are requesting a new feature, 12certain you have found a bug or that you are requesting a new feature,
13please direct support requests to 'help'. 13please direct support requests to 'help'.
14 14
diff --git a/configure.ac b/configure.ac
index 8594238f..ce140218 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,10 +1,10 @@
1dnl Process this file with autoconf to produce a configure script. 1dnl Process this file with autoconf to produce a configure script.
2AC_PREREQ(2.64) 2AC_PREREQ([2.64])
3AC_INIT(monitoring-plugins,2.4git) 3AC_INIT([monitoring-plugins],[2.4git])
4AC_CONFIG_SRCDIR(NPTest.pm) 4AC_CONFIG_SRCDIR(NPTest.pm)
5AC_CONFIG_FILES([gl/Makefile]) 5AC_CONFIG_FILES([gl/Makefile])
6AC_CONFIG_AUX_DIR(build-aux) 6AC_CONFIG_AUX_DIR(build-aux)
7AM_INIT_AUTOMAKE([1.8.3]) 7AM_INIT_AUTOMAKE([1.8.3 subdir-objects])
8AM_SILENT_RULES([yes]) 8AM_SILENT_RULES([yes])
9AM_MAINTAINER_MODE([enable]) 9AM_MAINTAINER_MODE([enable])
10AC_CONFIG_HEADERS([config.h]) 10AC_CONFIG_HEADERS([config.h])
@@ -43,14 +43,14 @@ AC_SUBST(INSTALL)
43AC_PROG_CC 43AC_PROG_CC
44gl_EARLY 44gl_EARLY
45AC_PROG_GCC_TRADITIONAL 45AC_PROG_GCC_TRADITIONAL
46AC_PROG_LIBTOOL 46LT_INIT
47 47
48AM_PROG_CC_C_O 48AM_PROG_CC_C_O
49 49
50AC_FUNC_ERROR_AT_LINE 50AC_FUNC_ERROR_AT_LINE
51AC_SYS_LARGEFILE 51AC_SYS_LARGEFILE
52 52
53ifdef([AC_FUNC_STRTOD],[AC_FUNC_STRTOD],[AM_FUNC_STRTOD]) 53ifdef([AC_FUNC_STRTOD],[AC_FUNC_STRTOD],[AC_FUNC_STRTOD])
54 54
55PLUGIN_TEST=`echo $srcdir/plugins/t/*.t|sed -e 's,\.*/plugins/,,g'` 55PLUGIN_TEST=`echo $srcdir/plugins/t/*.t|sed -e 's,\.*/plugins/,,g'`
56AC_SUBST(PLUGIN_TEST)dnl 56AC_SUBST(PLUGIN_TEST)dnl
@@ -125,8 +125,7 @@ AC_SUBST(PERL, $with_perl)
125 125
126dnl openssl/gnutls 126dnl openssl/gnutls
127AC_ARG_WITH(openssl, 127AC_ARG_WITH(openssl,
128 AC_HELP_STRING([--with-openssl=DIR], 128 AS_HELP_STRING([--with-openssl=DIR],[path to openssl installation]),)
129 [path to openssl installation]),)
130 129
131AC_ARG_WITH(gnutls, 130AC_ARG_WITH(gnutls,
132 ACX_HELP_STRING([--with-gnutls=PATH], 131 ACX_HELP_STRING([--with-gnutls=PATH],
@@ -167,8 +166,7 @@ AC_SUBST(MATHLIBS)
167 166
168dnl Check if we buils local libtap 167dnl Check if we buils local libtap
169AC_ARG_ENABLE(libtap, 168AC_ARG_ENABLE(libtap,
170 AC_HELP_STRING([--enable-libtap], 169 AS_HELP_STRING([--enable-libtap],[Enable built-in libtap for unit-testing (default: autodetect system library).]),
171 [Enable built-in libtap for unit-testing (default: autodetect system library).]),
172 [enable_libtap=$enableval], 170 [enable_libtap=$enableval],
173 [enable_libtap=no]) 171 [enable_libtap=no])
174AM_CONDITIONAL([USE_LIBTAP_LOCAL],[test "$enable_libtap" = "yes"]) 172AM_CONDITIONAL([USE_LIBTAP_LOCAL],[test "$enable_libtap" = "yes"])
@@ -183,14 +181,16 @@ fi
183 181
184# Finally, define tests if we use libtap 182# Finally, define tests if we use libtap
185if test "$enable_libtap" = "yes" ; then 183if test "$enable_libtap" = "yes" ; then
186 EXTRA_TEST="test_utils test_disk test_tcp test_cmd test_base64" 184 EXTRA_TEST="test_utils test_tcp test_cmd test_base64"
187 AC_SUBST(EXTRA_TEST) 185 AC_SUBST(EXTRA_TEST)
186
187 EXTRA_PLUGIN_TESTS="tests/test_check_swap tests/test_check_disk"
188 AC_SUBST(EXTRA_PLUGIN_TESTS)
188fi 189fi
189 190
190dnl INI Parsing 191dnl INI Parsing
191AC_ARG_ENABLE(extra-opts, 192AC_ARG_ENABLE(extra-opts,
192 AC_HELP_STRING([--enable-extra-opts], 193 AS_HELP_STRING([--enable-extra-opts],[Enables parsing of plugins ini config files for extra options (default: no)]),
193 [Enables parsing of plugins ini config files for extra options (default: no)]),
194 [enable_extra_opts=$enableval], 194 [enable_extra_opts=$enableval],
195 [enable_extra_opts=yes]) 195 [enable_extra_opts=yes])
196AM_CONDITIONAL([USE_PARSE_INI],[test "$enable_extra_opts" = "yes"]) 196AM_CONDITIONAL([USE_PARSE_INI],[test "$enable_extra_opts" = "yes"])
@@ -464,20 +464,16 @@ AC_ARG_WITH([ipv6],
464dnl Check for AF_INET6 support - unistd.h required for Darwin 464dnl Check for AF_INET6 support - unistd.h required for Darwin
465if test "$with_ipv6" != "no"; then 465if test "$with_ipv6" != "no"; then
466 AC_CACHE_CHECK([for IPv6 support], np_cv_sys_ipv6, [ 466 AC_CACHE_CHECK([for IPv6 support], np_cv_sys_ipv6, [
467 AC_TRY_COMPILE( 467 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#ifdef HAVE_UNISTD_H
468 [#ifdef HAVE_UNISTD_H
469 #include <unistd.h> 468 #include <unistd.h>
470 #endif 469 #endif
471 #include <netinet/in.h> 470 #include <netinet/in.h>
472 #include <sys/socket.h>], 471 #include <sys/socket.h>]], [[struct sockaddr_in6 sin6;
473 [struct sockaddr_in6 sin6;
474 void *p; 472 void *p;
475 473
476 sin6.sin6_family = AF_INET6; 474 sin6.sin6_family = AF_INET6;
477 sin6.sin6_port = 587; 475 sin6.sin6_port = 587;
478 p = &sin6.sin6_addr;], 476 p = &sin6.sin6_addr;]])],[np_cv_sys_ipv6=yes],[np_cv_sys_ipv6=no])
479 [np_cv_sys_ipv6=yes],
480 [np_cv_sys_ipv6=no])
481 ]) 477 ])
482 if test "$np_cv_sys_ipv6" = "no" -a "$with_ipv6" != "check"; then 478 if test "$np_cv_sys_ipv6" = "no" -a "$with_ipv6" != "check"; then
483 AC_MSG_FAILURE([--with-ipv6 was given, but test for IPv6 support failed]) 479 AC_MSG_FAILURE([--with-ipv6 was given, but test for IPv6 support failed])
@@ -611,10 +607,10 @@ dnl
611dnl Checks for header files. 607dnl Checks for header files.
612dnl 608dnl
613 609
614AC_HEADER_TIME
615AC_HEADER_SYS_WAIT 610AC_HEADER_SYS_WAIT
616AC_CHECK_HEADERS(signal.h syslog.h uio.h errno.h sys/time.h sys/socket.h sys/un.h sys/poll.h) 611AC_CHECK_HEADERS(signal.h syslog.h uio.h errno.h sys/time.h sys/socket.h sys/un.h sys/poll.h)
617AC_CHECK_HEADERS(features.h stdarg.h sys/unistd.h ctype.h) 612AC_CHECK_HEADERS(features.h stdarg.h sys/unistd.h ctype.h)
613AC_CHECK_HEADERS_ONCE([sys/time.h])
618 614
619dnl Checks for typedefs, structures, and compiler characteristics. 615dnl Checks for typedefs, structures, and compiler characteristics.
620AC_C_CONST 616AC_C_CONST
@@ -623,36 +619,27 @@ AC_TYPE_PID_T
623AC_TYPE_SIZE_T 619AC_TYPE_SIZE_T
624 620
625AC_CACHE_CHECK([for va_copy],ac_cv_HAVE_VA_COPY,[ 621AC_CACHE_CHECK([for va_copy],ac_cv_HAVE_VA_COPY,[
626AC_TRY_LINK([#include <stdarg.h> 622AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <stdarg.h>
627va_list ap1,ap2;], [va_copy(ap1,ap2);], 623va_list ap1,ap2;]], [[va_copy(ap1,ap2);]])],[ac_cv_HAVE_VA_COPY=yes],[ac_cv_HAVE_VA_COPY=no])])
628ac_cv_HAVE_VA_COPY=yes,
629ac_cv_HAVE_VA_COPY=no)])
630if test x"$ac_cv_HAVE_VA_COPY" = x"yes"; then 624if test x"$ac_cv_HAVE_VA_COPY" = x"yes"; then
631 AC_DEFINE(HAVE_VA_COPY,1,[Whether va_copy() is available]) 625 AC_DEFINE(HAVE_VA_COPY,1,[Whether va_copy() is available])
632else 626else
633 AC_CACHE_CHECK([for __va_copy],ac_cv_HAVE___VA_COPY,[ 627 AC_CACHE_CHECK([for __va_copy],ac_cv_HAVE___VA_COPY,[
634 AC_TRY_LINK([#include <stdarg.h> 628 AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <stdarg.h>
635 va_list ap1,ap2;], [__va_copy(ap1,ap2);], 629 va_list ap1,ap2;]], [[__va_copy(ap1,ap2);]])],[ac_cv_HAVE___VA_COPY=yes],[ac_cv_HAVE___VA_COPY=no])])
636 ac_cv_HAVE___VA_COPY=yes,
637 ac_cv_HAVE___VA_COPY=no)])
638 if test x"$ac_cv_HAVE___VA_COPY" = x"yes"; then 630 if test x"$ac_cv_HAVE___VA_COPY" = x"yes"; then
639 AC_DEFINE(HAVE___VA_COPY,1,[Whether __va_copy() is available]) 631 AC_DEFINE(HAVE___VA_COPY,1,[Whether __va_copy() is available])
640 fi 632 fi
641fi 633fi
642 634
643AC_TRY_COMPILE([#include <sys/time.h>], 635AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/time.h>]], [[struct timeval *tv;
644 [struct timeval *tv; 636 struct timezone *tz;]])],[AC_DEFINE(HAVE_STRUCT_TIMEVAL,1,Define if we have a timeval structure)
645 struct timezone *tz;], 637 FOUND_STRUCT_TIMEVAL="yes"],[])
646 AC_DEFINE(HAVE_STRUCT_TIMEVAL,1,[Define if we have a timeval structure])
647 FOUND_STRUCT_TIMEVAL="yes")
648 638
649if test x"$FOUND_STRUCT_TIMEVAL" = x"yes"; then 639if test x"$FOUND_STRUCT_TIMEVAL" = x"yes"; then
650 AC_TRY_COMPILE([#include <sys/time.h>], 640 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/time.h>]], [[struct timeval *tv;
651 [struct timeval *tv;
652 struct timezone *tz; 641 struct timezone *tz;
653 gettimeofday(tv, tz);], 642 gettimeofday(tv, tz);]])],[AC_DEFINE(HAVE_GETTIMEOFDAY,1,Define if gettimeofday is found)],[AC_DEFINE(NEED_GETTIMEOFDAY,1,Define if gettimeofday is needed)])
654 AC_DEFINE(HAVE_GETTIMEOFDAY,1,[Define if gettimeofday is found]),
655 AC_DEFINE(NEED_GETTIMEOFDAY,1,[Define if gettimeofday is needed]))
656fi 643fi
657 644
658dnl Checks for library functions. 645dnl Checks for library functions.
@@ -660,14 +647,11 @@ AC_CHECK_FUNCS(memmove select socket strdup strstr strtol strtoul floor)
660AC_CHECK_FUNCS(poll) 647AC_CHECK_FUNCS(poll)
661 648
662AC_MSG_CHECKING(return type of socket size) 649AC_MSG_CHECKING(return type of socket size)
663AC_TRY_COMPILE([#include <stdlib.h> 650AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <stdlib.h>
664 #include <sys/types.h> 651 #include <sys/types.h>
665 #include <sys/socket.h>], 652 #include <sys/socket.h>]], [[int a = send(1, (const void *) buffer, (size_t *) 0, (int *) 0);]])],[ac_cv_socket_size_type="size_t"
666 [int a = send(1, (const void *) buffer, (size_t *) 0, (int *) 0);], 653 AC_MSG_RESULT(size_t)],[ac_cv_socket_size_type="int"
667 ac_cv_socket_size_type=["size_t"] 654 AC_MSG_RESULT(int)])
668 AC_MSG_RESULT(size_t),
669 ac_cv_socket_size_type=["int"]
670 AC_MSG_RESULT(int))
671 655
672AC_DEFINE_UNQUOTED(SOCKET_SIZE_TYPE, $ac_cv_socket_size_type , 656AC_DEFINE_UNQUOTED(SOCKET_SIZE_TYPE, $ac_cv_socket_size_type ,
673 [Define type of socket size]) 657 [Define type of socket size])
@@ -812,7 +796,7 @@ elif ps axwo 'stat comm vsz rss user uid pid ppid etime args' 2>/dev/null | \
812then 796then
813 ac_cv_ps_varlist="[procstat,&procuid,&procpid,&procppid,&procvsz,&procrss,&procpcpu,procetime,procprog,&pos]" 797 ac_cv_ps_varlist="[procstat,&procuid,&procpid,&procppid,&procvsz,&procrss,&procpcpu,procetime,procprog,&pos]"
814 ac_cv_ps_command="$PATH_TO_PS axwo 'stat uid pid ppid vsz rss pcpu etime comm args'" 798 ac_cv_ps_command="$PATH_TO_PS axwo 'stat uid pid ppid vsz rss pcpu etime comm args'"
815 ac_cv_ps_format="%s %d %d %d %d %d %f %s %s %n" 799 ac_cv_ps_format="%s %u %d %d %d %d %f %s %s %n"
816 ac_cv_ps_cols=10 800 ac_cv_ps_cols=10
817 AC_MSG_RESULT([$ac_cv_ps_command]) 801 AC_MSG_RESULT([$ac_cv_ps_command])
818 802
@@ -1430,20 +1414,14 @@ if test -n "$ac_cv_nslookup_command"; then
1430fi 1414fi
1431 1415
1432AC_MSG_CHECKING([for number of online cpus]) 1416AC_MSG_CHECKING([for number of online cpus])
1433AC_TRY_COMPILE([#include <unistd.h>], 1417AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <unistd.h>]], [[sysconf(_SC_NPROCESSORS_ONLN) > 0;]])],[AC_DEFINE(HAVE_SYSCONF__SC_NPROCESSORS_ONLN,1,Define if sysconf returns number of online cpus)
1434 [sysconf(_SC_NPROCESSORS_ONLN) > 0;], 1418 AC_MSG_RESULT(sysconf(_SC_NPROCESSORS_ONLN))],[AC_MSG_RESULT(cannot calculate)
1435 AC_DEFINE(HAVE_SYSCONF__SC_NPROCESSORS_ONLN,1,[Define if sysconf returns number of online cpus]) 1419 ])
1436 AC_MSG_RESULT([sysconf(_SC_NPROCESSORS_ONLN)]),
1437 AC_MSG_RESULT([cannot calculate])
1438 )
1439 1420
1440AC_MSG_CHECKING([for number of available cpus]) 1421AC_MSG_CHECKING([for number of available cpus])
1441AC_TRY_COMPILE([#include <unistd.h>], 1422AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <unistd.h>]], [[sysconf(_SC_NPROCESSORS_CONF) > 0;]])],[AC_DEFINE(HAVE_SYSCONF__SC_NPROCESSORS_CONF,1,Define if sysconf returns number of available cpus)
1442 [sysconf(_SC_NPROCESSORS_CONF) > 0;], 1423 AC_MSG_RESULT(sysconf(_SC_NPROCESSORS_CONF))],[AC_MSG_RESULT(cannot calculate)
1443 AC_DEFINE(HAVE_SYSCONF__SC_NPROCESSORS_CONF,1,[Define if sysconf returns number of available cpus]) 1424 ])
1444 AC_MSG_RESULT([sysconf(_SC_NPROCESSORS_CONF)]),
1445 AC_MSG_RESULT([cannot calculate])
1446 )
1447 1425
1448AC_PATH_PROG(PATH_TO_UPTIME,uptime) 1426AC_PATH_PROG(PATH_TO_UPTIME,uptime)
1449AC_ARG_WITH(uptime_command, 1427AC_ARG_WITH(uptime_command,
@@ -1482,23 +1460,30 @@ AC_ARG_WITH(snmpget_command,
1482 ACX_HELP_STRING([--with-snmpget-command=PATH], 1460 ACX_HELP_STRING([--with-snmpget-command=PATH],
1483 [Path to snmpget command]), 1461 [Path to snmpget command]),
1484 PATH_TO_SNMPGET=$withval) 1462 PATH_TO_SNMPGET=$withval)
1485if test -n "$PATH_TO_SNMPGET"
1486then
1487 AC_DEFINE_UNQUOTED(PATH_TO_SNMPGET,"$PATH_TO_SNMPGET",[path to snmpget binary])
1488 EXTRAS="$EXTRAS check_hpjd check_snmp\$(EXEEXT)"
1489else
1490 AC_MSG_WARN([Get snmpget from http://net-snmp.sourceforge.net to make check_hpjd and check_snmp plugins])
1491fi
1492 1463
1493AC_PATH_PROG(PATH_TO_SNMPGETNEXT,snmpgetnext) 1464AC_PATH_PROG(PATH_TO_SNMPGETNEXT,snmpgetnext)
1494AC_ARG_WITH(snmpgetnext_command, 1465AC_ARG_WITH(snmpgetnext_command,
1495 ACX_HELP_STRING([--with-snmpgetnext-command=PATH], 1466 ACX_HELP_STRING([--with-snmpgetnext-command=PATH],
1496 [Path to snmpgetnext command]), 1467 [Path to snmpgetnext command]),
1497 PATH_TO_SNMPGETNEXT=$withval) 1468 PATH_TO_SNMPGETNEXT=$withval)
1498if test -n "$PATH_TO_SNMPGETNEXT" 1469
1499then 1470AS_IF([test -n "$PATH_TO_SNMPGET"], [
1500 AC_DEFINE_UNQUOTED(PATH_TO_SNMPGETNEXT,"$PATH_TO_SNMPGETNEXT",[path to snmpgetnext binary]) 1471 AC_DEFINE_UNQUOTED(PATH_TO_SNMPGET,"$PATH_TO_SNMPGET",[path to snmpget binary])
1501fi 1472 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], [
1485 AC_MSG_WARN([Get snmpget from https://net-snmp.sourceforge.io/ to build the check_hpjd and check_snmp plugins])
1486])
1502 1487
1503if ( $PERL -M"Net::SNMP 3.6" -e 'exit' 2>/dev/null ) 1488if ( $PERL -M"Net::SNMP 3.6" -e 'exit' 2>/dev/null )
1504then 1489then
@@ -1534,21 +1519,47 @@ then
1534fi 1519fi
1535 1520
1536AC_PATH_PROG(PATH_TO_FPING,fping) 1521AC_PATH_PROG(PATH_TO_FPING,fping)
1537AC_PATH_PROG(PATH_TO_FPING6,fping6)
1538 1522
1539AC_ARG_WITH(fping_command, 1523AC_ARG_WITH(fping_command,
1540 ACX_HELP_STRING([--with-fping-command=PATH], 1524 ACX_HELP_STRING([--with-fping-command=PATH],
1541 [Path to fping command]), PATH_TO_FPING=$withval) 1525 [Path to fping command]), PATH_TO_FPING=$withval)
1542AC_ARG_WITH(fping6_command, 1526if test -n "$PATH_TO_FPING"; then
1543 ACX_HELP_STRING([--with-fping6-command=PATH],
1544 [Path to fping6 command]), PATH_TO_FPING6=$withval)
1545
1546if test -n "$PATH_TO_FPING"
1547then
1548 AC_DEFINE_UNQUOTED(PATH_TO_FPING,"$PATH_TO_FPING",[path to fping]) 1527 AC_DEFINE_UNQUOTED(PATH_TO_FPING,"$PATH_TO_FPING",[path to fping])
1549 EXTRAS="$EXTRAS check_fping\$(EXEEXT)" 1528 EXTRAS="$EXTRAS check_fping\$(EXEEXT)"
1550 if test x"$with_ipv6" != xno && test -n "$PATH_TO_FPING6"; then 1529
1551 AC_DEFINE_UNQUOTED(PATH_TO_FPING6,"$PATH_TO_FPING6",[path to fping6]) 1530 if test -z "$($PATH_TO_FPING --version)" ; then
1531 AC_MSG_NOTICE([failed to get version of fping])
1532 else
1533 FPING_MAJOR_VERSION="$($PATH_TO_FPING --version | sed 's/.*fping: Version //' | sed 's/\..*//')"
1534 FPING_MINOR_VERSION="$($PATH_TO_FPING --version | sed 's/.*fping: Version //' | sed 's/.*\.//')"
1535
1536 if test $FPING_MAJOR_VERSION -eq 5 ; then
1537 if test $FPING_MINOR_VERSION -ge 3 ; then
1538 AC_DEFINE(FPING_VERSION_5_3_OR_HIGHER, "true", [fping is of version 5.3 or higher])
1539 AC_MSG_NOTICE([fping is of version 5.3 or higher])
1540 AC_DEFINE(FPING_VERSION_5_2_OR_HIGHER, "true", [fping is of version 5.2 or higher])
1541 AC_MSG_NOTICE([fping is of version 5.2 or higher])
1542 elif test $FPING_MINOR_VERSION -ge 2 ; then
1543 AC_DEFINE(FPING_VERSION_5_2_OR_HIGHER, "true", [fping is of version 5.2 or higher])
1544 AC_MSG_NOTICE([fping is of version 5.2 or higher])
1545 else
1546 AC_MSG_NOTICE([fping is of a version lower then 5.2])
1547 fi
1548
1549 elif $FPING_MAJOR_VERSION > 5 ; then
1550 AC_DEFINE(FPING_VERSION_5_2_OR_HIGHER, "true", [fping is of version 5.2 or higher])
1551 AC_MSG_NOTICE([fping is of version 5.2 or higher])
1552 AC_DEFINE(FPING_VERSION_5_3_OR_HIGHER, "true", [fping is of version 5.2 or higher])
1553 AC_MSG_NOTICE([fping is of version 5.3 or higher])
1554 fi
1555
1556 if test "`fping --version | sed 's/.*fping: Version //'`" = "5.2" ; then
1557 AC_DEFINE(FPING_VERSION, "5.2", [the version of fping available])
1558 AC_MSG_NOTICE([fping version: 5.2])
1559 elif test "`fping --version | sed 's/.*fping: Version //'`" = "5.3"; then
1560 AC_DEFINE(FPING_VERSION, "5.3", [the version of fping available])
1561 AC_MSG_NOTICE([fping version: 5.3])
1562 fi
1552 fi 1563 fi
1553else 1564else
1554 AC_MSG_WARN([Get fping from http://www.fping.com in order to make check_fping plugin]) 1565 AC_MSG_WARN([Get fping from http://www.fping.com in order to make check_fping plugin])
@@ -1850,8 +1861,8 @@ AC_SUBST(EXTRAS_ROOT)
1850AC_SUBST(EXTRA_NETOBJS) 1861AC_SUBST(EXTRA_NETOBJS)
1851AC_SUBST(DEPLIBS) 1862AC_SUBST(DEPLIBS)
1852 1863
1853AM_GNU_GETTEXT([external], [need-ngettext]) 1864dnl AM_GNU_GETTEXT([external], [need-ngettext])
1854AM_GNU_GETTEXT_VERSION(0.15) 1865dnl AM_GNU_GETTEXT_VERSION(0.15)
1855 1866
1856dnl Check for Redhat spopen problem 1867dnl Check for Redhat spopen problem
1857dnl Weird problem where ECHILD is returned from a wait call in error 1868dnl Weird problem where ECHILD is returned from a wait call in error
@@ -1861,8 +1872,7 @@ dnl We patch plugins/popen.c
1861dnl Need to add smp because uname different on those 1872dnl Need to add smp because uname different on those
1862dnl Can force patch to be applied with --enable-redhat-pthread-workaround 1873dnl Can force patch to be applied with --enable-redhat-pthread-workaround
1863AC_ARG_ENABLE(redhat-pthread-workaround, 1874AC_ARG_ENABLE(redhat-pthread-workaround,
1864 AC_HELP_STRING([--enable-redhat-pthread-workaround], 1875 AS_HELP_STRING([--enable-redhat-pthread-workaround],[force Redhat patch to be applied (default: test system)]),
1865 [force Redhat patch to be applied (default: test system)]),
1866 [ac_cv_enable_redhat_pthread_workaround=$enableval], 1876 [ac_cv_enable_redhat_pthread_workaround=$enableval],
1867 [ac_cv_enable_redhat_pthread_workaround=test]) 1877 [ac_cv_enable_redhat_pthread_workaround=test])
1868if test "$ac_cv_enable_redhat_pthread_workaround" = "test" ; then 1878if test "$ac_cv_enable_redhat_pthread_workaround" = "test" ; then
@@ -1883,8 +1893,7 @@ fi
1883 1893
1884dnl Perl modules 1894dnl Perl modules
1885AC_ARG_ENABLE(perl-modules, 1895AC_ARG_ENABLE(perl-modules,
1886 AC_HELP_STRING([--enable-perl-modules], 1896 AS_HELP_STRING([--enable-perl-modules],[Enables installation of Monitoring::Plugin and its dependencies (default: no)]),
1887 [Enables installation of Monitoring::Plugin and its dependencies (default: no)]),
1888 [enable_perl_modules=$enableval], 1897 [enable_perl_modules=$enableval],
1889 [enable_perl_modules=no]) 1898 [enable_perl_modules=no])
1890if test "$enable_perl_modules" = "yes" ; then 1899if test "$enable_perl_modules" = "yes" ; then
@@ -1911,8 +1920,7 @@ if test "$ac_cv_uname_s" = 'SunOS' -a \( "x$ac_cv_prog_ac_ct_AR" = "x" -o "$ac_c
1911 AC_MSG_ERROR(No ar found for Solaris - is /usr/ccs/bin in PATH?) 1920 AC_MSG_ERROR(No ar found for Solaris - is /usr/ccs/bin in PATH?)
1912fi 1921fi
1913 1922
1914AC_OUTPUT( 1923AC_CONFIG_FILES([Makefile
1915 Makefile
1916 tap/Makefile 1924 tap/Makefile
1917 lib/Makefile 1925 lib/Makefile
1918 plugins/Makefile 1926 plugins/Makefile
@@ -1924,7 +1932,8 @@ AC_OUTPUT(
1924 perlmods/Makefile 1932 perlmods/Makefile
1925 test.pl 1933 test.pl
1926 pkg/solaris/pkginfo 1934 pkg/solaris/pkginfo
1927) 1935])
1936AC_OUTPUT
1928 1937
1929 1938
1930dnl the ones below that are commented out need to be cleaned up 1939dnl the ones below that are commented out need to be cleaned up
diff --git a/doc/developer-guidelines.sgml b/doc/developer-guidelines.sgml
index 37c963ed..0afa733b 100644
--- a/doc/developer-guidelines.sgml
+++ b/doc/developer-guidelines.sgml
@@ -14,15 +14,8 @@
14 <pubdate>2013</pubdate> 14 <pubdate>2013</pubdate>
15 <title>Monitoring Plugins Development Guidelines</title> 15 <title>Monitoring Plugins Development Guidelines</title>
16 16
17 <revhistory>
18 <revision>
19 <revnumber>1796</revnumber>
20 <date>2007-09-24 14:51:07 -0400 (Mon, 24 Sep 2007)</date>
21 </revision>
22 </revhistory>
23
24 <copyright> 17 <copyright>
25 <year>2000 - 2013</year> 18 <year>2000 - 2024</year>
26 <holder>Monitoring Plugins Development Team</holder> 19 <holder>Monitoring Plugins Development Team</holder>
27 </copyright> 20 </copyright>
28 21
@@ -34,7 +27,7 @@
34 the plugin developers and encourage the standardization of the 27 the plugin developers and encourage the standardization of the
35 different kind of plugins: C, shell, perl, python, etc.</para> 28 different kind of plugins: C, shell, perl, python, etc.</para>
36 29
37 <para>Monitoring Plugins Development Guidelines Copyright (C) 2000-2013 30 <para>Monitoring Plugins Development Guidelines Copyright (C) 2000-2024
38 (Monitoring Plugins Team)</para> 31 (Monitoring Plugins Team)</para>
39 32
40 <para>Permission is granted to make and distribute verbatim 33 <para>Permission is granted to make and distribute verbatim
@@ -383,13 +376,6 @@
383 <para>It is up to third party programs to convert the Monitoring Plugins 376 <para>It is up to third party programs to convert the Monitoring Plugins
384 performance data into graphs.</para> 377 performance data into graphs.</para>
385 </section> 378 </section>
386
387 <section><title>Translations</title>
388 <para>If possible, use translation tools for all output to respect the user's language
389 settings. See <xref linkend="translationsdevelopers"> for guidelines
390 for the core plugins.
391 </para>
392 </section>
393</section> 379</section>
394 380
395<section id="SysCmdAuxFiles"><title>System Commands and Auxiliary Files</title> 381<section id="SysCmdAuxFiles"><title>System Commands and Auxiliary Files</title>
@@ -727,19 +713,18 @@ setup the tests. Run "make test" to run all the tests.
727</section> 713</section>
728<section id="CodingGuidelines"><title>Coding guidelines</title> 714<section id="CodingGuidelines"><title>Coding guidelines</title>
729 <para>See <ulink url="http://www.gnu.org/prep/standards_toc.html">GNU 715 <para>See <ulink url="http://www.gnu.org/prep/standards_toc.html">GNU
730 Coding standards</ulink> for general guidelines.</para> 716 Coding standards</ulink> for general guidelines.
717 Some parts of the guidelines (namely and explicitly the coding style)
718 are not seen as best practice by us.</para>
731 <section><title>C coding</title> 719 <section><title>C coding</title>
732 720
733 <para>Variables should be declared at the beginning of code blocks and
734 not inline because of portability with older compilers.</para>
735
736 <para>You should use the type "bool" and its values 721 <para>You should use the type "bool" and its values
737 "true" and "false" instead of the "int" type for booleans. 722 "true" and "false" instead of the "int" type for booleans.
738 </para> 723 </para>
739 </section> 724 </section>
740 725
741 <section><title>Crediting sources</title> 726 <section><title>Crediting sources</title>
742 <para>If you have copied a routine from another source, make sure the licence 727 <para>If you have copied a routine from another source, make sure the license
743 from your source allows this. Add a comment referencing the ACKNOWLEDGEMENTS 728 from your source allows this. Add a comment referencing the ACKNOWLEDGEMENTS
744 file, where you can put more detail about the source.</para> 729 file, where you can put more detail about the source.</para>
745 <para>For contributed code, do not add any named credits in the source code 730 <para>For contributed code, do not add any named credits in the source code
@@ -756,32 +741,6 @@ setup the tests. Run "make test" to run all the tests.
756 <para>All commits will be written to a ChangeLog at release time. 741 <para>All commits will be written to a ChangeLog at release time.
757 </para> 742 </para>
758 </section> 743 </section>
759
760 <section id="translationsdevelopers"><title>Translations for developers</title>
761 <para>To make the job easier for translators, please follow these guidelines:</para>
762 <orderedlist>
763 <listitem><para>
764 Before creating new strings, check the po/monitoring-plugins.pot file to
765 see if a similar string
766 already exists
767 </para></listitem>
768 <listitem><para>
769 For help texts, break into individual options so that these can be reused
770 between plugins
771 </para></listitem>
772 <listitem><para>Try to avoid linefeeds unless you are working on a block of text</para></listitem>
773 <listitem><para>Short help is not translated</para></listitem>
774 <listitem><para>Long help has options in English language, but text translated</para></listitem>
775 <listitem><para>"Copyright" kept in English</para></listitem>
776 <listitem><para>Copyright holder names kept in original text</para></listitem>
777 <listitem><para>Debugging output does not need to be translated</para></listitem>
778 </orderedlist>
779 </section>
780
781 <section><title>Translations for translators</title>
782 <para>To create an up to date list of translatable strings, run: tools/gen_locale.sh</para>
783 </section>
784
785</section> 744</section>
786 745
787<section id="SubmittingChanges"><title>Submission of new plugins and patches</title> 746<section id="SubmittingChanges"><title>Submission of new plugins and patches</title>
diff --git a/gl/Makefile.am b/gl/Makefile.am
index dcebd4aa..df988b37 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-2023 Free Software Foundation, Inc. 3# Copyright (C) 2002-2024 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
@@ -62,6 +62,7 @@ SUBDIRS =
62noinst_HEADERS = 62noinst_HEADERS =
63noinst_LIBRARIES = 63noinst_LIBRARIES =
64noinst_LTLIBRARIES = 64noinst_LTLIBRARIES =
65pkgdata_DATA =
65EXTRA_DIST = 66EXTRA_DIST =
66BUILT_SOURCES = 67BUILT_SOURCES =
67SUFFIXES = 68SUFFIXES =
@@ -350,10 +351,32 @@ if GL_COND_OBJ_ERROR
350libgnu_a_SOURCES += error.c 351libgnu_a_SOURCES += error.c
351endif 352endif
352 353
353EXTRA_DIST += error.h
354
355## end gnulib module error 354## end gnulib module error
356 355
356## begin gnulib module error-h
357
358BUILT_SOURCES += error.h
359
360# We need the following in order to override <error.h>.
361error.h: error.in.h $(top_builddir)/config.status $(CXXDEFS_H)
362 $(gl_V_at)$(SED_HEADER_STDOUT) \
363 -e 's|@''GUARD_PREFIX''@|GL|g' \
364 -e 's|@''HAVE_ERROR_H''@|$(HAVE_ERROR_H)|g' \
365 -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
366 -e 's|@''NEXT_ERROR_H''@|$(NEXT_ERROR_H)|g' \
367 -e 's|@''HAVE_ERROR''@|$(HAVE_ERROR)|g' \
368 -e 's|@''HAVE_ERROR_AT_LINE''@|$(HAVE_ERROR_AT_LINE)|g' \
369 -e 's|@''REPLACE_ERROR''@|$(REPLACE_ERROR)|g' \
370 -e 's|@''REPLACE_ERROR_AT_LINE''@|$(REPLACE_ERROR_AT_LINE)|g' \
371 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
372 $(srcdir)/error.in.h > $@-t
373 $(AM_V_at)mv $@-t $@
374MOSTLYCLEANFILES += error.h error.h-t
375
376EXTRA_DIST += error.in.h
377
378## end gnulib module error-h
379
357## begin gnulib module exitfail 380## begin gnulib module exitfail
358 381
359libgnu_a_SOURCES += exitfail.c 382libgnu_a_SOURCES += exitfail.c
@@ -595,6 +618,7 @@ SED_HEADER_STDOUT = sed -e 1h -e '1$(SED_HEADER_NOEDIT)' -e 1G
595SED_HEADER_TO_AT_t = $(SED_HEADER_STDOUT) -n -e 'w $@-t' 618SED_HEADER_TO_AT_t = $(SED_HEADER_STDOUT) -n -e 'w $@-t'
596 619
597# Use $(gl_V_at) instead of $(AM_V_GEN) or $(AM_V_at) on a line that 620# Use $(gl_V_at) instead of $(AM_V_GEN) or $(AM_V_at) on a line that
621# is its recipe's first line if and only if @NMD@ lines are absent.
598gl_V_at = $(AM_V_GEN) 622gl_V_at = $(AM_V_GEN)
599 623
600## end gnulib module gen-header 624## end gnulib module gen-header
@@ -698,7 +722,11 @@ EXTRA_DIST += getopt-cdefs.in.h getopt-core.h getopt-ext.h getopt-pfx-core.h get
698 722
699## begin gnulib module getprogname 723## begin gnulib module getprogname
700 724
701libgnu_a_SOURCES += getprogname.h getprogname.c 725if GL_COND_OBJ_GETPROGNAME
726libgnu_a_SOURCES += getprogname.c
727endif
728
729EXTRA_DIST += getprogname.h
702 730
703## end gnulib module getprogname 731## end gnulib module getprogname
704 732
@@ -810,6 +838,8 @@ inttypes.h: inttypes.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(WARN_ON_U
810 -e 's/@''HAVE_DECL_STRTOIMAX''@/$(HAVE_DECL_STRTOIMAX)/g' \ 838 -e 's/@''HAVE_DECL_STRTOIMAX''@/$(HAVE_DECL_STRTOIMAX)/g' \
811 -e 's/@''HAVE_DECL_STRTOUMAX''@/$(HAVE_DECL_STRTOUMAX)/g' \ 839 -e 's/@''HAVE_DECL_STRTOUMAX''@/$(HAVE_DECL_STRTOUMAX)/g' \
812 -e 's/@''HAVE_IMAXDIV_T''@/$(HAVE_IMAXDIV_T)/g' \ 840 -e 's/@''HAVE_IMAXDIV_T''@/$(HAVE_IMAXDIV_T)/g' \
841 -e 's/@''REPLACE_IMAXABS''@/$(REPLACE_IMAXABS)/g' \
842 -e 's/@''REPLACE_IMAXDIV''@/$(REPLACE_IMAXDIV)/g' \
813 -e 's/@''REPLACE_STRTOIMAX''@/$(REPLACE_STRTOIMAX)/g' \ 843 -e 's/@''REPLACE_STRTOIMAX''@/$(REPLACE_STRTOIMAX)/g' \
814 -e 's/@''REPLACE_STRTOUMAX''@/$(REPLACE_STRTOUMAX)/g' \ 844 -e 's/@''REPLACE_STRTOUMAX''@/$(REPLACE_STRTOUMAX)/g' \
815 -e 's/@''INT32_MAX_LT_INTMAX_MAX''@/$(INT32_MAX_LT_INTMAX_MAX)/g' \ 845 -e 's/@''INT32_MAX_LT_INTMAX_MAX''@/$(INT32_MAX_LT_INTMAX_MAX)/g' \
@@ -827,6 +857,48 @@ EXTRA_DIST += inttypes.in.h
827 857
828## end gnulib module inttypes-incomplete 858## end gnulib module inttypes-incomplete
829 859
860## begin gnulib module iswblank
861
862if GL_COND_OBJ_ISWBLANK
863libgnu_a_SOURCES += iswblank.c
864endif
865
866## end gnulib module iswblank
867
868## begin gnulib module iswctype
869
870if GL_COND_OBJ_ISWCTYPE
871libgnu_a_SOURCES += iswctype.c
872endif
873
874EXTRA_DIST += iswctype-impl.h
875
876## end gnulib module iswctype
877
878## begin gnulib module iswdigit
879
880if GL_COND_OBJ_ISWDIGIT
881libgnu_a_SOURCES += iswdigit.c
882endif
883
884## end gnulib module iswdigit
885
886## begin gnulib module iswpunct
887
888if GL_COND_OBJ_ISWPUNCT
889libgnu_a_SOURCES += iswpunct.c
890endif
891
892## end gnulib module iswpunct
893
894## begin gnulib module iswxdigit
895
896if GL_COND_OBJ_ISWXDIGIT
897libgnu_a_SOURCES += iswxdigit.c
898endif
899
900## end gnulib module iswxdigit
901
830## begin gnulib module langinfo 902## begin gnulib module langinfo
831 903
832BUILT_SOURCES += langinfo.h 904BUILT_SOURCES += langinfo.h
@@ -917,7 +989,7 @@ locale.h: locale.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
917 -e 's/@''GNULIB_SETLOCALE''@/$(GL_GNULIB_SETLOCALE)/g' \ 989 -e 's/@''GNULIB_SETLOCALE''@/$(GL_GNULIB_SETLOCALE)/g' \
918 -e 's/@''GNULIB_SETLOCALE_NULL''@/$(GL_GNULIB_SETLOCALE_NULL)/g' \ 990 -e 's/@''GNULIB_SETLOCALE_NULL''@/$(GL_GNULIB_SETLOCALE_NULL)/g' \
919 -e 's/@''GNULIB_DUPLOCALE''@/$(GL_GNULIB_DUPLOCALE)/g' \ 991 -e 's/@''GNULIB_DUPLOCALE''@/$(GL_GNULIB_DUPLOCALE)/g' \
920 -e 's/@''GNULIB_LOCALENAME''@/$(GL_GNULIB_LOCALENAME)/g' \ 992 -e 's/@''GNULIB_LOCALENAME_UNSAFE''@/$(GL_GNULIB_LOCALENAME_UNSAFE)/g' \
921 -e 's|@''HAVE_NEWLOCALE''@|$(HAVE_NEWLOCALE)|g' \ 993 -e 's|@''HAVE_NEWLOCALE''@|$(HAVE_NEWLOCALE)|g' \
922 -e 's|@''HAVE_DUPLOCALE''@|$(HAVE_DUPLOCALE)|g' \ 994 -e 's|@''HAVE_DUPLOCALE''@|$(HAVE_DUPLOCALE)|g' \
923 -e 's|@''HAVE_FREELOCALE''@|$(HAVE_FREELOCALE)|g' \ 995 -e 's|@''HAVE_FREELOCALE''@|$(HAVE_FREELOCALE)|g' \
@@ -1043,11 +1115,15 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
1043 -e 's/@''GNULIB_FREXPF''@/$(GL_GNULIB_FREXPF)/g' \ 1115 -e 's/@''GNULIB_FREXPF''@/$(GL_GNULIB_FREXPF)/g' \
1044 -e 's/@''GNULIB_FREXP''@/$(GL_GNULIB_FREXP)/g' \ 1116 -e 's/@''GNULIB_FREXP''@/$(GL_GNULIB_FREXP)/g' \
1045 -e 's/@''GNULIB_FREXPL''@/$(GL_GNULIB_FREXPL)/g' \ 1117 -e 's/@''GNULIB_FREXPL''@/$(GL_GNULIB_FREXPL)/g' \
1118 -e 's/@''GNULIB_GETPAYLOAD''@/$(GL_GNULIB_GETPAYLOAD)/g' \
1119 -e 's/@''GNULIB_GETPAYLOADF''@/$(GL_GNULIB_GETPAYLOADF)/g' \
1120 -e 's/@''GNULIB_GETPAYLOADL''@/$(GL_GNULIB_GETPAYLOADL)/g' \
1046 -e 's/@''GNULIB_HYPOT''@/$(GL_GNULIB_HYPOT)/g' \ 1121 -e 's/@''GNULIB_HYPOT''@/$(GL_GNULIB_HYPOT)/g' \
1047 -e 's/@''GNULIB_HYPOTF''@/$(GL_GNULIB_HYPOTF)/g' \ 1122 -e 's/@''GNULIB_HYPOTF''@/$(GL_GNULIB_HYPOTF)/g' \
1048 -e 's/@''GNULIB_HYPOTL''@/$(GL_GNULIB_HYPOTL)/g' \ 1123 -e 's/@''GNULIB_HYPOTL''@/$(GL_GNULIB_HYPOTL)/g' \
1049 < $(srcdir)/math.in.h | \ 1124 < $(srcdir)/math.in.h > $@-t1
1050 sed -e 's/@''GNULIB_ILOGB''@/$(GL_GNULIB_ILOGB)/g' \ 1125 $(AM_V_at)sed \
1126 -e 's/@''GNULIB_ILOGB''@/$(GL_GNULIB_ILOGB)/g' \
1051 -e 's/@''GNULIB_ILOGBF''@/$(GL_GNULIB_ILOGBF)/g' \ 1127 -e 's/@''GNULIB_ILOGBF''@/$(GL_GNULIB_ILOGBF)/g' \
1052 -e 's/@''GNULIB_ILOGBL''@/$(GL_GNULIB_ILOGBL)/g' \ 1128 -e 's/@''GNULIB_ILOGBL''@/$(GL_GNULIB_ILOGBL)/g' \
1053 -e 's/@''GNULIB_ISFINITE''@/$(GL_GNULIB_ISFINITE)/g' \ 1129 -e 's/@''GNULIB_ISFINITE''@/$(GL_GNULIB_ISFINITE)/g' \
@@ -1056,6 +1132,7 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
1056 -e 's/@''GNULIB_ISNANF''@/$(GL_GNULIB_ISNANF)/g' \ 1132 -e 's/@''GNULIB_ISNANF''@/$(GL_GNULIB_ISNANF)/g' \
1057 -e 's/@''GNULIB_ISNAND''@/$(GL_GNULIB_ISNAND)/g' \ 1133 -e 's/@''GNULIB_ISNAND''@/$(GL_GNULIB_ISNAND)/g' \
1058 -e 's/@''GNULIB_ISNANL''@/$(GL_GNULIB_ISNANL)/g' \ 1134 -e 's/@''GNULIB_ISNANL''@/$(GL_GNULIB_ISNANL)/g' \
1135 -e 's/@''GNULIB_LDEXP''@/$(GL_GNULIB_LDEXP)/g' \
1059 -e 's/@''GNULIB_LDEXPF''@/$(GL_GNULIB_LDEXPF)/g' \ 1136 -e 's/@''GNULIB_LDEXPF''@/$(GL_GNULIB_LDEXPF)/g' \
1060 -e 's/@''GNULIB_LDEXPL''@/$(GL_GNULIB_LDEXPL)/g' \ 1137 -e 's/@''GNULIB_LDEXPL''@/$(GL_GNULIB_LDEXPL)/g' \
1061 -e 's/@''GNULIB_LOG''@/$(GL_GNULIB_LOG)/g' \ 1138 -e 's/@''GNULIB_LOG''@/$(GL_GNULIB_LOG)/g' \
@@ -1086,6 +1163,12 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
1086 -e 's/@''GNULIB_ROUND''@/$(GL_GNULIB_ROUND)/g' \ 1163 -e 's/@''GNULIB_ROUND''@/$(GL_GNULIB_ROUND)/g' \
1087 -e 's/@''GNULIB_ROUNDF''@/$(GL_GNULIB_ROUNDF)/g' \ 1164 -e 's/@''GNULIB_ROUNDF''@/$(GL_GNULIB_ROUNDF)/g' \
1088 -e 's/@''GNULIB_ROUNDL''@/$(GL_GNULIB_ROUNDL)/g' \ 1165 -e 's/@''GNULIB_ROUNDL''@/$(GL_GNULIB_ROUNDL)/g' \
1166 -e 's/@''GNULIB_SETPAYLOAD''@/$(GL_GNULIB_SETPAYLOAD)/g' \
1167 -e 's/@''GNULIB_SETPAYLOADF''@/$(GL_GNULIB_SETPAYLOADF)/g' \
1168 -e 's/@''GNULIB_SETPAYLOADL''@/$(GL_GNULIB_SETPAYLOADL)/g' \
1169 -e 's/@''GNULIB_SETPAYLOADSIG''@/$(GL_GNULIB_SETPAYLOADSIG)/g' \
1170 -e 's/@''GNULIB_SETPAYLOADSIGF''@/$(GL_GNULIB_SETPAYLOADSIGF)/g' \
1171 -e 's/@''GNULIB_SETPAYLOADSIGL''@/$(GL_GNULIB_SETPAYLOADSIGL)/g' \
1089 -e 's/@''GNULIB_SIGNBIT''@/$(GL_GNULIB_SIGNBIT)/g' \ 1172 -e 's/@''GNULIB_SIGNBIT''@/$(GL_GNULIB_SIGNBIT)/g' \
1090 -e 's/@''GNULIB_SINF''@/$(GL_GNULIB_SINF)/g' \ 1173 -e 's/@''GNULIB_SINF''@/$(GL_GNULIB_SINF)/g' \
1091 -e 's/@''GNULIB_SINL''@/$(GL_GNULIB_SINL)/g' \ 1174 -e 's/@''GNULIB_SINL''@/$(GL_GNULIB_SINL)/g' \
@@ -1098,14 +1181,21 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
1098 -e 's/@''GNULIB_TRUNC''@/$(GL_GNULIB_TRUNC)/g' \ 1181 -e 's/@''GNULIB_TRUNC''@/$(GL_GNULIB_TRUNC)/g' \
1099 -e 's/@''GNULIB_TRUNCF''@/$(GL_GNULIB_TRUNCF)/g' \ 1182 -e 's/@''GNULIB_TRUNCF''@/$(GL_GNULIB_TRUNCF)/g' \
1100 -e 's/@''GNULIB_TRUNCL''@/$(GL_GNULIB_TRUNCL)/g' \ 1183 -e 's/@''GNULIB_TRUNCL''@/$(GL_GNULIB_TRUNCL)/g' \
1184 -e 's/@''GNULIB_TOTALORDER''@/$(GL_GNULIB_TOTALORDER)/g' \
1185 -e 's/@''GNULIB_TOTALORDERF''@/$(GL_GNULIB_TOTALORDERF)/g' \
1186 -e 's/@''GNULIB_TOTALORDERL''@/$(GL_GNULIB_TOTALORDERL)/g' \
1187 -e 's/@''GNULIB_TOTALORDERMAG''@/$(GL_GNULIB_TOTALORDERMAG)/g' \
1188 -e 's/@''GNULIB_TOTALORDERMAGF''@/$(GL_GNULIB_TOTALORDERMAGF)/g' \
1189 -e 's/@''GNULIB_TOTALORDERMAGL''@/$(GL_GNULIB_TOTALORDERMAGL)/g' \
1101 -e 's/@''GNULIB_MDA_J0''@/$(GL_GNULIB_MDA_J0)/g' \ 1190 -e 's/@''GNULIB_MDA_J0''@/$(GL_GNULIB_MDA_J0)/g' \
1102 -e 's/@''GNULIB_MDA_J1''@/$(GL_GNULIB_MDA_J1)/g' \ 1191 -e 's/@''GNULIB_MDA_J1''@/$(GL_GNULIB_MDA_J1)/g' \
1103 -e 's/@''GNULIB_MDA_JN''@/$(GL_GNULIB_MDA_JN)/g' \ 1192 -e 's/@''GNULIB_MDA_JN''@/$(GL_GNULIB_MDA_JN)/g' \
1104 -e 's/@''GNULIB_MDA_Y0''@/$(GL_GNULIB_MDA_Y0)/g' \ 1193 -e 's/@''GNULIB_MDA_Y0''@/$(GL_GNULIB_MDA_Y0)/g' \
1105 -e 's/@''GNULIB_MDA_Y1''@/$(GL_GNULIB_MDA_Y1)/g' \ 1194 -e 's/@''GNULIB_MDA_Y1''@/$(GL_GNULIB_MDA_Y1)/g' \
1106 -e 's/@''GNULIB_MDA_YN''@/$(GL_GNULIB_MDA_YN)/g' \ 1195 -e 's/@''GNULIB_MDA_YN''@/$(GL_GNULIB_MDA_YN)/g' \
1107 | \ 1196 < $@-t1 > $@-t2
1108 sed -e 's|@''HAVE_ACOSF''@|$(HAVE_ACOSF)|g' \ 1197 $(AM_V_at)sed \
1198 -e 's|@''HAVE_ACOSF''@|$(HAVE_ACOSF)|g' \
1109 -e 's|@''HAVE_ACOSL''@|$(HAVE_ACOSL)|g' \ 1199 -e 's|@''HAVE_ACOSL''@|$(HAVE_ACOSL)|g' \
1110 -e 's|@''HAVE_ASINF''@|$(HAVE_ASINF)|g' \ 1200 -e 's|@''HAVE_ASINF''@|$(HAVE_ASINF)|g' \
1111 -e 's|@''HAVE_ASINL''@|$(HAVE_ASINL)|g' \ 1201 -e 's|@''HAVE_ASINL''@|$(HAVE_ASINL)|g' \
@@ -1132,6 +1222,9 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
1132 -e 's|@''HAVE_FMODF''@|$(HAVE_FMODF)|g' \ 1222 -e 's|@''HAVE_FMODF''@|$(HAVE_FMODF)|g' \
1133 -e 's|@''HAVE_FMODL''@|$(HAVE_FMODL)|g' \ 1223 -e 's|@''HAVE_FMODL''@|$(HAVE_FMODL)|g' \
1134 -e 's|@''HAVE_FREXPF''@|$(HAVE_FREXPF)|g' \ 1224 -e 's|@''HAVE_FREXPF''@|$(HAVE_FREXPF)|g' \
1225 -e 's|@''HAVE_GETPAYLOAD''@|$(HAVE_GETPAYLOAD)|g' \
1226 -e 's|@''HAVE_GETPAYLOADF''@|$(HAVE_GETPAYLOADF)|g' \
1227 -e 's|@''HAVE_GETPAYLOADL''@|$(HAVE_GETPAYLOADL)|g' \
1135 -e 's|@''HAVE_HYPOTF''@|$(HAVE_HYPOTF)|g' \ 1228 -e 's|@''HAVE_HYPOTF''@|$(HAVE_HYPOTF)|g' \
1136 -e 's|@''HAVE_HYPOTL''@|$(HAVE_HYPOTL)|g' \ 1229 -e 's|@''HAVE_HYPOTL''@|$(HAVE_HYPOTL)|g' \
1137 -e 's|@''HAVE_ILOGB''@|$(HAVE_ILOGB)|g' \ 1230 -e 's|@''HAVE_ILOGB''@|$(HAVE_ILOGB)|g' \
@@ -1157,6 +1250,12 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
1157 -e 's|@''HAVE_REMAINDERF''@|$(HAVE_REMAINDERF)|g' \ 1250 -e 's|@''HAVE_REMAINDERF''@|$(HAVE_REMAINDERF)|g' \
1158 -e 's|@''HAVE_RINT''@|$(HAVE_RINT)|g' \ 1251 -e 's|@''HAVE_RINT''@|$(HAVE_RINT)|g' \
1159 -e 's|@''HAVE_RINTL''@|$(HAVE_RINTL)|g' \ 1252 -e 's|@''HAVE_RINTL''@|$(HAVE_RINTL)|g' \
1253 -e 's|@''HAVE_SETPAYLOAD''@|$(HAVE_SETPAYLOAD)|g' \
1254 -e 's|@''HAVE_SETPAYLOADF''@|$(HAVE_SETPAYLOADF)|g' \
1255 -e 's|@''HAVE_SETPAYLOADL''@|$(HAVE_SETPAYLOADL)|g' \
1256 -e 's|@''HAVE_SETPAYLOADSIG''@|$(HAVE_SETPAYLOADSIG)|g' \
1257 -e 's|@''HAVE_SETPAYLOADSIGF''@|$(HAVE_SETPAYLOADSIGF)|g' \
1258 -e 's|@''HAVE_SETPAYLOADSIGL''@|$(HAVE_SETPAYLOADSIGL)|g' \
1160 -e 's|@''HAVE_SINF''@|$(HAVE_SINF)|g' \ 1259 -e 's|@''HAVE_SINF''@|$(HAVE_SINF)|g' \
1161 -e 's|@''HAVE_SINL''@|$(HAVE_SINL)|g' \ 1260 -e 's|@''HAVE_SINL''@|$(HAVE_SINL)|g' \
1162 -e 's|@''HAVE_SINHF''@|$(HAVE_SINHF)|g' \ 1261 -e 's|@''HAVE_SINHF''@|$(HAVE_SINHF)|g' \
@@ -1165,6 +1264,14 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
1165 -e 's|@''HAVE_TANF''@|$(HAVE_TANF)|g' \ 1264 -e 's|@''HAVE_TANF''@|$(HAVE_TANF)|g' \
1166 -e 's|@''HAVE_TANL''@|$(HAVE_TANL)|g' \ 1265 -e 's|@''HAVE_TANL''@|$(HAVE_TANL)|g' \
1167 -e 's|@''HAVE_TANHF''@|$(HAVE_TANHF)|g' \ 1266 -e 's|@''HAVE_TANHF''@|$(HAVE_TANHF)|g' \
1267 -e 's|@''HAVE_TOTALORDER''@|$(HAVE_TOTALORDER)|g' \
1268 -e 's|@''HAVE_TOTALORDERF''@|$(HAVE_TOTALORDERF)|g' \
1269 -e 's|@''HAVE_TOTALORDERL''@|$(HAVE_TOTALORDERL)|g' \
1270 -e 's|@''HAVE_TOTALORDERMAG''@|$(HAVE_TOTALORDERMAG)|g' \
1271 -e 's|@''HAVE_TOTALORDERMAGF''@|$(HAVE_TOTALORDERMAGF)|g' \
1272 -e 's|@''HAVE_TOTALORDERMAGL''@|$(HAVE_TOTALORDERMAGL)|g' \
1273 < $@-t2 > $@-t3
1274 $(AM_V_at)sed \
1168 -e 's|@''HAVE_DECL_ACOSL''@|$(HAVE_DECL_ACOSL)|g' \ 1275 -e 's|@''HAVE_DECL_ACOSL''@|$(HAVE_DECL_ACOSL)|g' \
1169 -e 's|@''HAVE_DECL_ASINL''@|$(HAVE_DECL_ASINL)|g' \ 1276 -e 's|@''HAVE_DECL_ASINL''@|$(HAVE_DECL_ASINL)|g' \
1170 -e 's|@''HAVE_DECL_ATANL''@|$(HAVE_DECL_ATANL)|g' \ 1277 -e 's|@''HAVE_DECL_ATANL''@|$(HAVE_DECL_ATANL)|g' \
@@ -1201,8 +1308,9 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
1201 -e 's|@''HAVE_DECL_TRUNC''@|$(HAVE_DECL_TRUNC)|g' \ 1308 -e 's|@''HAVE_DECL_TRUNC''@|$(HAVE_DECL_TRUNC)|g' \
1202 -e 's|@''HAVE_DECL_TRUNCF''@|$(HAVE_DECL_TRUNCF)|g' \ 1309 -e 's|@''HAVE_DECL_TRUNCF''@|$(HAVE_DECL_TRUNCF)|g' \
1203 -e 's|@''HAVE_DECL_TRUNCL''@|$(HAVE_DECL_TRUNCL)|g' \ 1310 -e 's|@''HAVE_DECL_TRUNCL''@|$(HAVE_DECL_TRUNCL)|g' \
1204 | \ 1311 < $@-t3 > $@-t4
1205 sed -e 's|@''REPLACE_ACOSF''@|$(REPLACE_ACOSF)|g' \ 1312 $(AM_V_at)sed \
1313 -e 's|@''REPLACE_ACOSF''@|$(REPLACE_ACOSF)|g' \
1206 -e 's|@''REPLACE_ASINF''@|$(REPLACE_ASINF)|g' \ 1314 -e 's|@''REPLACE_ASINF''@|$(REPLACE_ASINF)|g' \
1207 -e 's|@''REPLACE_ATANF''@|$(REPLACE_ATANF)|g' \ 1315 -e 's|@''REPLACE_ATANF''@|$(REPLACE_ATANF)|g' \
1208 -e 's|@''REPLACE_ATAN2F''@|$(REPLACE_ATAN2F)|g' \ 1316 -e 's|@''REPLACE_ATAN2F''@|$(REPLACE_ATAN2F)|g' \
@@ -1233,6 +1341,9 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
1233 -e 's|@''REPLACE_FREXPF''@|$(REPLACE_FREXPF)|g' \ 1341 -e 's|@''REPLACE_FREXPF''@|$(REPLACE_FREXPF)|g' \
1234 -e 's|@''REPLACE_FREXP''@|$(REPLACE_FREXP)|g' \ 1342 -e 's|@''REPLACE_FREXP''@|$(REPLACE_FREXP)|g' \
1235 -e 's|@''REPLACE_FREXPL''@|$(REPLACE_FREXPL)|g' \ 1343 -e 's|@''REPLACE_FREXPL''@|$(REPLACE_FREXPL)|g' \
1344 -e 's|@''REPLACE_GETPAYLOAD''@|$(REPLACE_GETPAYLOAD)|g' \
1345 -e 's|@''REPLACE_GETPAYLOADF''@|$(REPLACE_GETPAYLOADF)|g' \
1346 -e 's|@''REPLACE_GETPAYLOADL''@|$(REPLACE_GETPAYLOADL)|g' \
1236 -e 's|@''REPLACE_HUGE_VAL''@|$(REPLACE_HUGE_VAL)|g' \ 1347 -e 's|@''REPLACE_HUGE_VAL''@|$(REPLACE_HUGE_VAL)|g' \
1237 -e 's|@''REPLACE_HYPOT''@|$(REPLACE_HYPOT)|g' \ 1348 -e 's|@''REPLACE_HYPOT''@|$(REPLACE_HYPOT)|g' \
1238 -e 's|@''REPLACE_HYPOTF''@|$(REPLACE_HYPOTF)|g' \ 1349 -e 's|@''REPLACE_HYPOTF''@|$(REPLACE_HYPOTF)|g' \
@@ -1244,6 +1355,9 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
1244 -e 's|@''REPLACE_ISINF''@|$(REPLACE_ISINF)|g' \ 1355 -e 's|@''REPLACE_ISINF''@|$(REPLACE_ISINF)|g' \
1245 -e 's|@''REPLACE_ISNAN''@|$(REPLACE_ISNAN)|g' \ 1356 -e 's|@''REPLACE_ISNAN''@|$(REPLACE_ISNAN)|g' \
1246 -e 's|@''REPLACE_ITOLD''@|$(REPLACE_ITOLD)|g' \ 1357 -e 's|@''REPLACE_ITOLD''@|$(REPLACE_ITOLD)|g' \
1358 < $@-t4 > $@-t5
1359 $(AM_V_at)sed \
1360 -e 's|@''REPLACE_LDEXP''@|$(REPLACE_LDEXP)|g' \
1247 -e 's|@''REPLACE_LDEXPL''@|$(REPLACE_LDEXPL)|g' \ 1361 -e 's|@''REPLACE_LDEXPL''@|$(REPLACE_LDEXPL)|g' \
1248 -e 's|@''REPLACE_LOG''@|$(REPLACE_LOG)|g' \ 1362 -e 's|@''REPLACE_LOG''@|$(REPLACE_LOG)|g' \
1249 -e 's|@''REPLACE_LOGF''@|$(REPLACE_LOGF)|g' \ 1363 -e 's|@''REPLACE_LOGF''@|$(REPLACE_LOGF)|g' \
@@ -1279,15 +1393,22 @@ math.h: math.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
1279 -e 's|@''REPLACE_SQRTL''@|$(REPLACE_SQRTL)|g' \ 1393 -e 's|@''REPLACE_SQRTL''@|$(REPLACE_SQRTL)|g' \
1280 -e 's|@''REPLACE_TANF''@|$(REPLACE_TANF)|g' \ 1394 -e 's|@''REPLACE_TANF''@|$(REPLACE_TANF)|g' \
1281 -e 's|@''REPLACE_TANHF''@|$(REPLACE_TANHF)|g' \ 1395 -e 's|@''REPLACE_TANHF''@|$(REPLACE_TANHF)|g' \
1396 -e 's|@''REPLACE_TOTALORDER''@|$(REPLACE_TOTALORDER)|g' \
1397 -e 's|@''REPLACE_TOTALORDERF''@|$(REPLACE_TOTALORDERF)|g' \
1398 -e 's|@''REPLACE_TOTALORDERL''@|$(REPLACE_TOTALORDERL)|g' \
1399 -e 's|@''REPLACE_TOTALORDERMAG''@|$(REPLACE_TOTALORDERMAG)|g' \
1400 -e 's|@''REPLACE_TOTALORDERMAGF''@|$(REPLACE_TOTALORDERMAGF)|g' \
1401 -e 's|@''REPLACE_TOTALORDERMAGL''@|$(REPLACE_TOTALORDERMAGL)|g' \
1282 -e 's|@''REPLACE_TRUNC''@|$(REPLACE_TRUNC)|g' \ 1402 -e 's|@''REPLACE_TRUNC''@|$(REPLACE_TRUNC)|g' \
1283 -e 's|@''REPLACE_TRUNCF''@|$(REPLACE_TRUNCF)|g' \ 1403 -e 's|@''REPLACE_TRUNCF''@|$(REPLACE_TRUNCF)|g' \
1284 -e 's|@''REPLACE_TRUNCL''@|$(REPLACE_TRUNCL)|g' \ 1404 -e 's|@''REPLACE_TRUNCL''@|$(REPLACE_TRUNCL)|g' \
1285 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ 1405 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
1286 -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \ 1406 -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
1287 -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \ 1407 -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
1288 > $@-t 1408 < $@-t5 > $@-t6
1289 $(AM_V_at)mv $@-t $@ 1409 $(AM_V_at)rm -f $@-t1 $@-t2 $@-t3 $@-t4 $@-t5
1290MOSTLYCLEANFILES += math.h math.h-t 1410 $(AM_V_at)mv $@-t6 $@
1411MOSTLYCLEANFILES += math.h math.h-t1 math.h-t2 math.h-t3 math.h-t4 math.h-t5 math.h-t6
1291 1412
1292EXTRA_DIST += math.in.h 1413EXTRA_DIST += math.in.h
1293 1414
@@ -1313,6 +1434,12 @@ endif
1313 1434
1314## end gnulib module mbsinit 1435## end gnulib module mbsinit
1315 1436
1437## begin gnulib module mbszero
1438
1439libgnu_a_SOURCES += mbszero.c
1440
1441## end gnulib module mbszero
1442
1316## begin gnulib module mbtowc 1443## begin gnulib module mbtowc
1317 1444
1318if GL_COND_OBJ_MBTOWC 1445if GL_COND_OBJ_MBTOWC
@@ -1534,6 +1661,14 @@ EXTRA_DIST += setlocale_null.h windows-initguard.h
1534 1661
1535## end gnulib module setlocale-null 1662## end gnulib module setlocale-null
1536 1663
1664## begin gnulib module setlocale-null-unlocked
1665
1666libgnu_a_SOURCES += setlocale_null-unlocked.c
1667
1668EXTRA_DIST += setlocale_null.h
1669
1670## end gnulib module setlocale-null-unlocked
1671
1537## begin gnulib module size_max 1672## begin gnulib module size_max
1538 1673
1539libgnu_a_SOURCES += size_max.h 1674libgnu_a_SOURCES += size_max.h
@@ -1625,26 +1760,6 @@ EXTRA_DIST += stat-time.h
1625 1760
1626## end gnulib module stat-time 1761## end gnulib module stat-time
1627 1762
1628## begin gnulib module stdalign
1629
1630BUILT_SOURCES += $(STDALIGN_H)
1631
1632# We need the following in order to create <stdalign.h> when the system
1633# doesn't have one that works.
1634if GL_GENERATE_STDALIGN_H
1635stdalign.h: stdalign.in.h $(top_builddir)/config.status
1636 $(gl_V_at)$(SED_HEADER_TO_AT_t) $(srcdir)/stdalign.in.h
1637 $(AM_V_at)mv $@-t $@
1638else
1639stdalign.h: $(top_builddir)/config.status
1640 rm -f $@
1641endif
1642MOSTLYCLEANFILES += stdalign.h stdalign.h-t
1643
1644EXTRA_DIST += stdalign.in.h
1645
1646## end gnulib module stdalign
1647
1648## begin gnulib module stdckdint 1763## begin gnulib module stdckdint
1649 1764
1650BUILT_SOURCES += $(STDCKDINT_H) 1765BUILT_SOURCES += $(STDCKDINT_H)
@@ -1816,14 +1931,17 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
1816 -e 's/@''GNULIB_MDA_GETW''@/$(GL_GNULIB_MDA_GETW)/g' \ 1931 -e 's/@''GNULIB_MDA_GETW''@/$(GL_GNULIB_MDA_GETW)/g' \
1817 -e 's/@''GNULIB_MDA_PUTW''@/$(GL_GNULIB_MDA_PUTW)/g' \ 1932 -e 's/@''GNULIB_MDA_PUTW''@/$(GL_GNULIB_MDA_PUTW)/g' \
1818 -e 's/@''GNULIB_MDA_TEMPNAM''@/$(GL_GNULIB_MDA_TEMPNAM)/g' \ 1933 -e 's/@''GNULIB_MDA_TEMPNAM''@/$(GL_GNULIB_MDA_TEMPNAM)/g' \
1819 < $(srcdir)/stdio.in.h | \ 1934 < $(srcdir)/stdio.in.h > $@-t1
1820 sed -e 's|@''HAVE_DECL_FCLOSEALL''@|$(HAVE_DECL_FCLOSEALL)|g' \ 1935 $(AM_V_at)sed \
1936 -e 's|@''HAVE_DECL_FCLOSEALL''@|$(HAVE_DECL_FCLOSEALL)|g' \
1821 -e 's|@''HAVE_DECL_FPURGE''@|$(HAVE_DECL_FPURGE)|g' \ 1937 -e 's|@''HAVE_DECL_FPURGE''@|$(HAVE_DECL_FPURGE)|g' \
1822 -e 's|@''HAVE_DECL_FSEEKO''@|$(HAVE_DECL_FSEEKO)|g' \ 1938 -e 's|@''HAVE_DECL_FSEEKO''@|$(HAVE_DECL_FSEEKO)|g' \
1823 -e 's|@''HAVE_DECL_FTELLO''@|$(HAVE_DECL_FTELLO)|g' \ 1939 -e 's|@''HAVE_DECL_FTELLO''@|$(HAVE_DECL_FTELLO)|g' \
1824 -e 's|@''HAVE_DECL_GETDELIM''@|$(HAVE_DECL_GETDELIM)|g' \ 1940 -e 's|@''HAVE_DECL_GETDELIM''@|$(HAVE_DECL_GETDELIM)|g' \
1825 -e 's|@''HAVE_DECL_GETLINE''@|$(HAVE_DECL_GETLINE)|g' \ 1941 -e 's|@''HAVE_DECL_GETLINE''@|$(HAVE_DECL_GETLINE)|g' \
1942 -e 's|@''HAVE_DECL_GETW''@|$(HAVE_DECL_GETW)|g' \
1826 -e 's|@''HAVE_DECL_OBSTACK_PRINTF''@|$(HAVE_DECL_OBSTACK_PRINTF)|g' \ 1943 -e 's|@''HAVE_DECL_OBSTACK_PRINTF''@|$(HAVE_DECL_OBSTACK_PRINTF)|g' \
1944 -e 's|@''HAVE_DECL_PUTW''@|$(HAVE_DECL_PUTW)|g' \
1827 -e 's|@''HAVE_DECL_SNPRINTF''@|$(HAVE_DECL_SNPRINTF)|g' \ 1945 -e 's|@''HAVE_DECL_SNPRINTF''@|$(HAVE_DECL_SNPRINTF)|g' \
1828 -e 's|@''HAVE_DECL_VSNPRINTF''@|$(HAVE_DECL_VSNPRINTF)|g' \ 1946 -e 's|@''HAVE_DECL_VSNPRINTF''@|$(HAVE_DECL_VSNPRINTF)|g' \
1829 -e 's|@''HAVE_DPRINTF''@|$(HAVE_DPRINTF)|g' \ 1947 -e 's|@''HAVE_DPRINTF''@|$(HAVE_DPRINTF)|g' \
@@ -1834,6 +1952,8 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
1834 -e 's|@''HAVE_RENAMEAT''@|$(HAVE_RENAMEAT)|g' \ 1952 -e 's|@''HAVE_RENAMEAT''@|$(HAVE_RENAMEAT)|g' \
1835 -e 's|@''HAVE_VASPRINTF''@|$(HAVE_VASPRINTF)|g' \ 1953 -e 's|@''HAVE_VASPRINTF''@|$(HAVE_VASPRINTF)|g' \
1836 -e 's|@''HAVE_VDPRINTF''@|$(HAVE_VDPRINTF)|g' \ 1954 -e 's|@''HAVE_VDPRINTF''@|$(HAVE_VDPRINTF)|g' \
1955 < $@-t1 > $@-t2
1956 $(AM_V_at)sed \
1837 -e 's|@''REPLACE_DPRINTF''@|$(REPLACE_DPRINTF)|g' \ 1957 -e 's|@''REPLACE_DPRINTF''@|$(REPLACE_DPRINTF)|g' \
1838 -e 's|@''REPLACE_FCLOSE''@|$(REPLACE_FCLOSE)|g' \ 1958 -e 's|@''REPLACE_FCLOSE''@|$(REPLACE_FCLOSE)|g' \
1839 -e 's|@''REPLACE_FDOPEN''@|$(REPLACE_FDOPEN)|g' \ 1959 -e 's|@''REPLACE_FDOPEN''@|$(REPLACE_FDOPEN)|g' \
@@ -1871,9 +1991,10 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
1871 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ 1991 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
1872 -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \ 1992 -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
1873 -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \ 1993 -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
1874 > $@-t 1994 < $@-t2 > $@-t3
1875 $(AM_V_at)mv $@-t $@ 1995 $(AM_V_at)rm -f $@-t1 $@-t2
1876MOSTLYCLEANFILES += stdio.h stdio.h-t 1996 $(AM_V_at)mv $@-t3 $@
1997MOSTLYCLEANFILES += stdio.h stdio.h-t1 stdio.h-t2 stdio.h-t3
1877 1998
1878if GL_COND_OBJ_STDIO_READ 1999if GL_COND_OBJ_STDIO_READ
1879libgnu_a_SOURCES += stdio-read.c 2000libgnu_a_SOURCES += stdio-read.c
@@ -1908,10 +2029,12 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
1908 -e 's/@''GNULIB_CANONICALIZE_FILE_NAME''@/$(GL_GNULIB_CANONICALIZE_FILE_NAME)/g' \ 2029 -e 's/@''GNULIB_CANONICALIZE_FILE_NAME''@/$(GL_GNULIB_CANONICALIZE_FILE_NAME)/g' \
1909 -e 's/@''GNULIB_FREE_POSIX''@/$(GL_GNULIB_FREE_POSIX)/g' \ 2030 -e 's/@''GNULIB_FREE_POSIX''@/$(GL_GNULIB_FREE_POSIX)/g' \
1910 -e 's/@''GNULIB_GETLOADAVG''@/$(GL_GNULIB_GETLOADAVG)/g' \ 2031 -e 's/@''GNULIB_GETLOADAVG''@/$(GL_GNULIB_GETLOADAVG)/g' \
2032 -e 's/@''GNULIB_GETPROGNAME''@/$(GL_GNULIB_GETPROGNAME)/g' \
1911 -e 's/@''GNULIB_GETSUBOPT''@/$(GL_GNULIB_GETSUBOPT)/g' \ 2033 -e 's/@''GNULIB_GETSUBOPT''@/$(GL_GNULIB_GETSUBOPT)/g' \
1912 -e 's/@''GNULIB_GRANTPT''@/$(GL_GNULIB_GRANTPT)/g' \ 2034 -e 's/@''GNULIB_GRANTPT''@/$(GL_GNULIB_GRANTPT)/g' \
1913 -e 's/@''GNULIB_MALLOC_GNU''@/$(GL_GNULIB_MALLOC_GNU)/g' \ 2035 -e 's/@''GNULIB_MALLOC_GNU''@/$(GL_GNULIB_MALLOC_GNU)/g' \
1914 -e 's/@''GNULIB_MALLOC_POSIX''@/$(GL_GNULIB_MALLOC_POSIX)/g' \ 2036 -e 's/@''GNULIB_MALLOC_POSIX''@/$(GL_GNULIB_MALLOC_POSIX)/g' \
2037 -e 's/@''GNULIB_MBSTOWCS''@/$(GL_GNULIB_MBSTOWCS)/g' \
1915 -e 's/@''GNULIB_MBTOWC''@/$(GL_GNULIB_MBTOWC)/g' \ 2038 -e 's/@''GNULIB_MBTOWC''@/$(GL_GNULIB_MBTOWC)/g' \
1916 -e 's/@''GNULIB_MKDTEMP''@/$(GL_GNULIB_MKDTEMP)/g' \ 2039 -e 's/@''GNULIB_MKDTEMP''@/$(GL_GNULIB_MKDTEMP)/g' \
1917 -e 's/@''GNULIB_MKOSTEMP''@/$(GL_GNULIB_MKOSTEMP)/g' \ 2040 -e 's/@''GNULIB_MKOSTEMP''@/$(GL_GNULIB_MKOSTEMP)/g' \
@@ -1924,6 +2047,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
1924 -e 's/@''GNULIB_PTSNAME_R''@/$(GL_GNULIB_PTSNAME_R)/g' \ 2047 -e 's/@''GNULIB_PTSNAME_R''@/$(GL_GNULIB_PTSNAME_R)/g' \
1925 -e 's/@''GNULIB_PUTENV''@/$(GL_GNULIB_PUTENV)/g' \ 2048 -e 's/@''GNULIB_PUTENV''@/$(GL_GNULIB_PUTENV)/g' \
1926 -e 's/@''GNULIB_QSORT_R''@/$(GL_GNULIB_QSORT_R)/g' \ 2049 -e 's/@''GNULIB_QSORT_R''@/$(GL_GNULIB_QSORT_R)/g' \
2050 -e 's/@''GNULIB_RAND''@/$(GL_GNULIB_RAND)/g' \
1927 -e 's/@''GNULIB_RANDOM''@/$(GL_GNULIB_RANDOM)/g' \ 2051 -e 's/@''GNULIB_RANDOM''@/$(GL_GNULIB_RANDOM)/g' \
1928 -e 's/@''GNULIB_RANDOM_R''@/$(GL_GNULIB_RANDOM_R)/g' \ 2052 -e 's/@''GNULIB_RANDOM_R''@/$(GL_GNULIB_RANDOM_R)/g' \
1929 -e 's/@''GNULIB_REALLOC_GNU''@/$(GL_GNULIB_REALLOC_GNU)/g' \ 2053 -e 's/@''GNULIB_REALLOC_GNU''@/$(GL_GNULIB_REALLOC_GNU)/g' \
@@ -1934,6 +2058,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
1934 -e 's/@''GNULIB_SECURE_GETENV''@/$(GL_GNULIB_SECURE_GETENV)/g' \ 2058 -e 's/@''GNULIB_SECURE_GETENV''@/$(GL_GNULIB_SECURE_GETENV)/g' \
1935 -e 's/@''GNULIB_SETENV''@/$(GL_GNULIB_SETENV)/g' \ 2059 -e 's/@''GNULIB_SETENV''@/$(GL_GNULIB_SETENV)/g' \
1936 -e 's/@''GNULIB_STRTOD''@/$(GL_GNULIB_STRTOD)/g' \ 2060 -e 's/@''GNULIB_STRTOD''@/$(GL_GNULIB_STRTOD)/g' \
2061 -e 's/@''GNULIB_STRTOF''@/$(GL_GNULIB_STRTOF)/g' \
1937 -e 's/@''GNULIB_STRTOL''@/$(GL_GNULIB_STRTOL)/g' \ 2062 -e 's/@''GNULIB_STRTOL''@/$(GL_GNULIB_STRTOL)/g' \
1938 -e 's/@''GNULIB_STRTOLD''@/$(GL_GNULIB_STRTOLD)/g' \ 2063 -e 's/@''GNULIB_STRTOLD''@/$(GL_GNULIB_STRTOLD)/g' \
1939 -e 's/@''GNULIB_STRTOLL''@/$(GL_GNULIB_STRTOLL)/g' \ 2064 -e 's/@''GNULIB_STRTOLL''@/$(GL_GNULIB_STRTOLL)/g' \
@@ -1948,8 +2073,9 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
1948 -e 's/@''GNULIB_MDA_GCVT''@/$(GL_GNULIB_MDA_GCVT)/g' \ 2073 -e 's/@''GNULIB_MDA_GCVT''@/$(GL_GNULIB_MDA_GCVT)/g' \
1949 -e 's/@''GNULIB_MDA_MKTEMP''@/$(GL_GNULIB_MDA_MKTEMP)/g' \ 2074 -e 's/@''GNULIB_MDA_MKTEMP''@/$(GL_GNULIB_MDA_MKTEMP)/g' \
1950 -e 's/@''GNULIB_MDA_PUTENV''@/$(GL_GNULIB_MDA_PUTENV)/g' \ 2075 -e 's/@''GNULIB_MDA_PUTENV''@/$(GL_GNULIB_MDA_PUTENV)/g' \
1951 < $(srcdir)/stdlib.in.h | \ 2076 < $(srcdir)/stdlib.in.h > $@-t1
1952 sed -e 's|@''HAVE__EXIT''@|$(HAVE__EXIT)|g' \ 2077 $(AM_V_at)sed \
2078 -e 's|@''HAVE__EXIT''@|$(HAVE__EXIT)|g' \
1953 -e 's|@''HAVE_ALIGNED_ALLOC''@|$(HAVE_ALIGNED_ALLOC)|g' \ 2079 -e 's|@''HAVE_ALIGNED_ALLOC''@|$(HAVE_ALIGNED_ALLOC)|g' \
1954 -e 's|@''HAVE_ATOLL''@|$(HAVE_ATOLL)|g' \ 2080 -e 's|@''HAVE_ATOLL''@|$(HAVE_ATOLL)|g' \
1955 -e 's|@''HAVE_CANONICALIZE_FILE_NAME''@|$(HAVE_CANONICALIZE_FILE_NAME)|g' \ 2081 -e 's|@''HAVE_CANONICALIZE_FILE_NAME''@|$(HAVE_CANONICALIZE_FILE_NAME)|g' \
@@ -1957,6 +2083,8 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
1957 -e 's|@''HAVE_DECL_FCVT''@|$(HAVE_DECL_FCVT)|g' \ 2083 -e 's|@''HAVE_DECL_FCVT''@|$(HAVE_DECL_FCVT)|g' \
1958 -e 's|@''HAVE_DECL_GCVT''@|$(HAVE_DECL_GCVT)|g' \ 2084 -e 's|@''HAVE_DECL_GCVT''@|$(HAVE_DECL_GCVT)|g' \
1959 -e 's|@''HAVE_DECL_GETLOADAVG''@|$(HAVE_DECL_GETLOADAVG)|g' \ 2085 -e 's|@''HAVE_DECL_GETLOADAVG''@|$(HAVE_DECL_GETLOADAVG)|g' \
2086 -e 's|@''HAVE_DECL_PROGRAM_INVOCATION_NAME''@|$(HAVE_DECL_PROGRAM_INVOCATION_NAME)|g' \
2087 -e 's|@''HAVE_GETPROGNAME''@|$(HAVE_GETPROGNAME)|g' \
1960 -e 's|@''HAVE_GETSUBOPT''@|$(HAVE_GETSUBOPT)|g' \ 2088 -e 's|@''HAVE_GETSUBOPT''@|$(HAVE_GETSUBOPT)|g' \
1961 -e 's|@''HAVE_GRANTPT''@|$(HAVE_GRANTPT)|g' \ 2089 -e 's|@''HAVE_GRANTPT''@|$(HAVE_GRANTPT)|g' \
1962 -e 's|@''HAVE_INITSTATE''@|$(HAVE_INITSTATE)|g' \ 2090 -e 's|@''HAVE_INITSTATE''@|$(HAVE_INITSTATE)|g' \
@@ -1983,6 +2111,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
1983 -e 's|@''HAVE_SETSTATE''@|$(HAVE_SETSTATE)|g' \ 2111 -e 's|@''HAVE_SETSTATE''@|$(HAVE_SETSTATE)|g' \
1984 -e 's|@''HAVE_DECL_SETSTATE''@|$(HAVE_DECL_SETSTATE)|g' \ 2112 -e 's|@''HAVE_DECL_SETSTATE''@|$(HAVE_DECL_SETSTATE)|g' \
1985 -e 's|@''HAVE_STRTOD''@|$(HAVE_STRTOD)|g' \ 2113 -e 's|@''HAVE_STRTOD''@|$(HAVE_STRTOD)|g' \
2114 -e 's|@''HAVE_STRTOF''@|$(HAVE_STRTOF)|g' \
1986 -e 's|@''HAVE_STRTOL''@|$(HAVE_STRTOL)|g' \ 2115 -e 's|@''HAVE_STRTOL''@|$(HAVE_STRTOL)|g' \
1987 -e 's|@''HAVE_STRTOLD''@|$(HAVE_STRTOLD)|g' \ 2116 -e 's|@''HAVE_STRTOLD''@|$(HAVE_STRTOLD)|g' \
1988 -e 's|@''HAVE_STRTOLL''@|$(HAVE_STRTOLL)|g' \ 2117 -e 's|@''HAVE_STRTOLL''@|$(HAVE_STRTOLL)|g' \
@@ -1992,21 +2121,33 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
1992 -e 's|@''HAVE_SYS_LOADAVG_H''@|$(HAVE_SYS_LOADAVG_H)|g' \ 2121 -e 's|@''HAVE_SYS_LOADAVG_H''@|$(HAVE_SYS_LOADAVG_H)|g' \
1993 -e 's|@''HAVE_UNLOCKPT''@|$(HAVE_UNLOCKPT)|g' \ 2122 -e 's|@''HAVE_UNLOCKPT''@|$(HAVE_UNLOCKPT)|g' \
1994 -e 's|@''HAVE_DECL_UNSETENV''@|$(HAVE_DECL_UNSETENV)|g' \ 2123 -e 's|@''HAVE_DECL_UNSETENV''@|$(HAVE_DECL_UNSETENV)|g' \
2124 < $@-t1 > $@-t2
2125 $(AM_V_at)sed \
2126 -e 's|@''REPLACE__EXIT''@|$(REPLACE__EXIT)|g' \
1995 -e 's|@''REPLACE_ALIGNED_ALLOC''@|$(REPLACE_ALIGNED_ALLOC)|g' \ 2127 -e 's|@''REPLACE_ALIGNED_ALLOC''@|$(REPLACE_ALIGNED_ALLOC)|g' \
1996 -e 's|@''REPLACE_CALLOC_FOR_CALLOC_GNU''@|$(REPLACE_CALLOC_FOR_CALLOC_GNU)|g' \ 2128 -e 's|@''REPLACE_CALLOC_FOR_CALLOC_GNU''@|$(REPLACE_CALLOC_FOR_CALLOC_GNU)|g' \
1997 -e 's|@''REPLACE_CALLOC_FOR_CALLOC_POSIX''@|$(REPLACE_CALLOC_FOR_CALLOC_POSIX)|g' \ 2129 -e 's|@''REPLACE_CALLOC_FOR_CALLOC_POSIX''@|$(REPLACE_CALLOC_FOR_CALLOC_POSIX)|g' \
1998 -e 's|@''REPLACE_CANONICALIZE_FILE_NAME''@|$(REPLACE_CANONICALIZE_FILE_NAME)|g' \ 2130 -e 's|@''REPLACE_CANONICALIZE_FILE_NAME''@|$(REPLACE_CANONICALIZE_FILE_NAME)|g' \
1999 -e 's|@''REPLACE_FREE''@|$(REPLACE_FREE)|g' \ 2131 -e 's|@''REPLACE_FREE''@|$(REPLACE_FREE)|g' \
2132 -e 's|@''REPLACE_GETLOADAVG''@|$(REPLACE_GETLOADAVG)|g' \
2133 -e 's|@''REPLACE_GETPROGNAME''@|$(REPLACE_GETPROGNAME)|g' \
2134 -e 's|@''REPLACE_GETSUBOPT''@|$(REPLACE_GETSUBOPT)|g' \
2000 -e 's|@''REPLACE_INITSTATE''@|$(REPLACE_INITSTATE)|g' \ 2135 -e 's|@''REPLACE_INITSTATE''@|$(REPLACE_INITSTATE)|g' \
2001 -e 's|@''REPLACE_MALLOC_FOR_MALLOC_GNU''@|$(REPLACE_MALLOC_FOR_MALLOC_GNU)|g' \ 2136 -e 's|@''REPLACE_MALLOC_FOR_MALLOC_GNU''@|$(REPLACE_MALLOC_FOR_MALLOC_GNU)|g' \
2002 -e 's|@''REPLACE_MALLOC_FOR_MALLOC_POSIX''@|$(REPLACE_MALLOC_FOR_MALLOC_POSIX)|g' \ 2137 -e 's|@''REPLACE_MALLOC_FOR_MALLOC_POSIX''@|$(REPLACE_MALLOC_FOR_MALLOC_POSIX)|g' \
2138 -e 's|@''REPLACE_MB_CUR_MAX''@|$(REPLACE_MB_CUR_MAX)|g' \
2139 -e 's|@''REPLACE_MBSTOWCS''@|$(REPLACE_MBSTOWCS)|g' \
2003 -e 's|@''REPLACE_MBTOWC''@|$(REPLACE_MBTOWC)|g' \ 2140 -e 's|@''REPLACE_MBTOWC''@|$(REPLACE_MBTOWC)|g' \
2141 -e 's|@''REPLACE_MKOSTEMP''@|$(REPLACE_MKOSTEMP)|g' \
2142 -e 's|@''REPLACE_MKOSTEMPS''@|$(REPLACE_MKOSTEMPS)|g' \
2004 -e 's|@''REPLACE_MKSTEMP''@|$(REPLACE_MKSTEMP)|g' \ 2143 -e 's|@''REPLACE_MKSTEMP''@|$(REPLACE_MKSTEMP)|g' \
2005 -e 's|@''REPLACE_POSIX_MEMALIGN''@|$(REPLACE_POSIX_MEMALIGN)|g' \ 2144 -e 's|@''REPLACE_POSIX_MEMALIGN''@|$(REPLACE_POSIX_MEMALIGN)|g' \
2145 -e 's|@''REPLACE_POSIX_OPENPT''@|$(REPLACE_POSIX_OPENPT)|g' \
2006 -e 's|@''REPLACE_PTSNAME''@|$(REPLACE_PTSNAME)|g' \ 2146 -e 's|@''REPLACE_PTSNAME''@|$(REPLACE_PTSNAME)|g' \
2007 -e 's|@''REPLACE_PTSNAME_R''@|$(REPLACE_PTSNAME_R)|g' \ 2147 -e 's|@''REPLACE_PTSNAME_R''@|$(REPLACE_PTSNAME_R)|g' \
2008 -e 's|@''REPLACE_PUTENV''@|$(REPLACE_PUTENV)|g' \ 2148 -e 's|@''REPLACE_PUTENV''@|$(REPLACE_PUTENV)|g' \
2009 -e 's|@''REPLACE_QSORT_R''@|$(REPLACE_QSORT_R)|g' \ 2149 -e 's|@''REPLACE_QSORT_R''@|$(REPLACE_QSORT_R)|g' \
2150 -e 's|@''REPLACE_RAND''@|$(REPLACE_RAND)|g' \
2010 -e 's|@''REPLACE_RANDOM''@|$(REPLACE_RANDOM)|g' \ 2151 -e 's|@''REPLACE_RANDOM''@|$(REPLACE_RANDOM)|g' \
2011 -e 's|@''REPLACE_RANDOM_R''@|$(REPLACE_RANDOM_R)|g' \ 2152 -e 's|@''REPLACE_RANDOM_R''@|$(REPLACE_RANDOM_R)|g' \
2012 -e 's|@''REPLACE_REALLOC_FOR_REALLOC_GNU''@|$(REPLACE_REALLOC_FOR_REALLOC_GNU)|g' \ 2153 -e 's|@''REPLACE_REALLOC_FOR_REALLOC_GNU''@|$(REPLACE_REALLOC_FOR_REALLOC_GNU)|g' \
@@ -2016,6 +2157,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
2016 -e 's|@''REPLACE_SETENV''@|$(REPLACE_SETENV)|g' \ 2157 -e 's|@''REPLACE_SETENV''@|$(REPLACE_SETENV)|g' \
2017 -e 's|@''REPLACE_SETSTATE''@|$(REPLACE_SETSTATE)|g' \ 2158 -e 's|@''REPLACE_SETSTATE''@|$(REPLACE_SETSTATE)|g' \
2018 -e 's|@''REPLACE_STRTOD''@|$(REPLACE_STRTOD)|g' \ 2159 -e 's|@''REPLACE_STRTOD''@|$(REPLACE_STRTOD)|g' \
2160 -e 's|@''REPLACE_STRTOF''@|$(REPLACE_STRTOF)|g' \
2019 -e 's|@''REPLACE_STRTOL''@|$(REPLACE_STRTOL)|g' \ 2161 -e 's|@''REPLACE_STRTOL''@|$(REPLACE_STRTOL)|g' \
2020 -e 's|@''REPLACE_STRTOLD''@|$(REPLACE_STRTOLD)|g' \ 2162 -e 's|@''REPLACE_STRTOLD''@|$(REPLACE_STRTOLD)|g' \
2021 -e 's|@''REPLACE_STRTOLL''@|$(REPLACE_STRTOLL)|g' \ 2163 -e 's|@''REPLACE_STRTOLL''@|$(REPLACE_STRTOLL)|g' \
@@ -2027,9 +2169,10 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
2027 -e '/definition of _Noreturn/r $(_NORETURN_H)' \ 2169 -e '/definition of _Noreturn/r $(_NORETURN_H)' \
2028 -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \ 2170 -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
2029 -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \ 2171 -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
2030 > $@-t 2172 < $@-t2 > $@-t3
2031 $(AM_V_at)mv $@-t $@ 2173 $(AM_V_at)rm -f $@-t1 $@-t2
2032MOSTLYCLEANFILES += stdlib.h stdlib.h-t 2174 $(AM_V_at)mv $@-t3 $@
2175MOSTLYCLEANFILES += stdlib.h stdlib.h-t1 stdlib.h-t2 stdlib.h-t3
2033 2176
2034EXTRA_DIST += stdlib.in.h 2177EXTRA_DIST += stdlib.in.h
2035 2178
@@ -2147,8 +2290,9 @@ string.h: string.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
2147 -e 's/@''GNULIB_MDA_MEMCCPY''@/$(GL_GNULIB_MDA_MEMCCPY)/g' \ 2290 -e 's/@''GNULIB_MDA_MEMCCPY''@/$(GL_GNULIB_MDA_MEMCCPY)/g' \
2148 -e 's/@''GNULIB_MDA_STRDUP''@/$(GL_GNULIB_MDA_STRDUP)/g' \ 2291 -e 's/@''GNULIB_MDA_STRDUP''@/$(GL_GNULIB_MDA_STRDUP)/g' \
2149 -e 's/@''GNULIB_FREE_POSIX''@/$(GL_GNULIB_FREE_POSIX)/g' \ 2292 -e 's/@''GNULIB_FREE_POSIX''@/$(GL_GNULIB_FREE_POSIX)/g' \
2150 < $(srcdir)/string.in.h | \ 2293 < $(srcdir)/string.in.h > $@-t1
2151 sed -e 's|@''HAVE_EXPLICIT_BZERO''@|$(HAVE_EXPLICIT_BZERO)|g' \ 2294 $(AM_V_at)sed \
2295 -e 's|@''HAVE_EXPLICIT_BZERO''@|$(HAVE_EXPLICIT_BZERO)|g' \
2152 -e 's|@''HAVE_FFSL''@|$(HAVE_FFSL)|g' \ 2296 -e 's|@''HAVE_FFSL''@|$(HAVE_FFSL)|g' \
2153 -e 's|@''HAVE_FFSLL''@|$(HAVE_FFSLL)|g' \ 2297 -e 's|@''HAVE_FFSLL''@|$(HAVE_FFSLL)|g' \
2154 -e 's|@''HAVE_MBSLEN''@|$(HAVE_MBSLEN)|g' \ 2298 -e 's|@''HAVE_MBSLEN''@|$(HAVE_MBSLEN)|g' \
@@ -2176,7 +2320,10 @@ string.h: string.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
2176 -e 's|@''REPLACE_FFSLL''@|$(REPLACE_FFSLL)|g' \ 2320 -e 's|@''REPLACE_FFSLL''@|$(REPLACE_FFSLL)|g' \
2177 -e 's|@''REPLACE_MEMCHR''@|$(REPLACE_MEMCHR)|g' \ 2321 -e 's|@''REPLACE_MEMCHR''@|$(REPLACE_MEMCHR)|g' \
2178 -e 's|@''REPLACE_MEMMEM''@|$(REPLACE_MEMMEM)|g' \ 2322 -e 's|@''REPLACE_MEMMEM''@|$(REPLACE_MEMMEM)|g' \
2323 -e 's|@''REPLACE_MEMPCPY''@|$(REPLACE_MEMPCPY)|g' \
2324 -e 's|@''REPLACE_MEMSET_EXPLICIT''@|$(REPLACE_MEMSET_EXPLICIT)|g' \
2179 -e 's|@''REPLACE_FREE''@|$(REPLACE_FREE)|g' \ 2325 -e 's|@''REPLACE_FREE''@|$(REPLACE_FREE)|g' \
2326 -e 's|@''REPLACE_STPCPY''@|$(REPLACE_STPCPY)|g' \
2180 -e 's|@''REPLACE_STPNCPY''@|$(REPLACE_STPNCPY)|g' \ 2327 -e 's|@''REPLACE_STPNCPY''@|$(REPLACE_STPNCPY)|g' \
2181 -e 's|@''REPLACE_STRCHRNUL''@|$(REPLACE_STRCHRNUL)|g' \ 2328 -e 's|@''REPLACE_STRCHRNUL''@|$(REPLACE_STRCHRNUL)|g' \
2182 -e 's|@''REPLACE_STRDUP''@|$(REPLACE_STRDUP)|g' \ 2329 -e 's|@''REPLACE_STRDUP''@|$(REPLACE_STRDUP)|g' \
@@ -2190,13 +2337,15 @@ string.h: string.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
2190 -e 's|@''REPLACE_STRERROR_R''@|$(REPLACE_STRERROR_R)|g' \ 2337 -e 's|@''REPLACE_STRERROR_R''@|$(REPLACE_STRERROR_R)|g' \
2191 -e 's|@''REPLACE_STRERRORNAME_NP''@|$(REPLACE_STRERRORNAME_NP)|g' \ 2338 -e 's|@''REPLACE_STRERRORNAME_NP''@|$(REPLACE_STRERRORNAME_NP)|g' \
2192 -e 's|@''REPLACE_STRSIGNAL''@|$(REPLACE_STRSIGNAL)|g' \ 2339 -e 's|@''REPLACE_STRSIGNAL''@|$(REPLACE_STRSIGNAL)|g' \
2340 -e 's|@''REPLACE_STRVERSCMP''@|$(REPLACE_STRVERSCMP)|g' \
2193 -e 's|@''UNDEFINE_STRTOK_R''@|$(UNDEFINE_STRTOK_R)|g' \ 2341 -e 's|@''UNDEFINE_STRTOK_R''@|$(UNDEFINE_STRTOK_R)|g' \
2194 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ 2342 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
2195 -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \ 2343 -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
2196 -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \ 2344 -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
2197 > $@-t 2345 < $@-t1 > $@-t2
2198 $(AM_V_at)mv $@-t $@ 2346 $(AM_V_at)rm -f $@-t1
2199MOSTLYCLEANFILES += string.h string.h-t 2347 $(AM_V_at)mv $@-t2 $@
2348MOSTLYCLEANFILES += string.h string.h-t1 string.h-t2
2200 2349
2201EXTRA_DIST += string.in.h 2350EXTRA_DIST += string.in.h
2202 2351
@@ -2425,7 +2574,7 @@ libgnu_a_SOURCES += glthread/threadlib.c
2425 2574
2426## end gnulib module threadlib 2575## end gnulib module threadlib
2427 2576
2428## begin gnulib module time 2577## begin gnulib module time-h
2429 2578
2430BUILT_SOURCES += time.h 2579BUILT_SOURCES += time.h
2431 2580
@@ -2444,6 +2593,7 @@ time.h: time.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
2444 -e 's/@''GNULIB_NANOSLEEP''@/$(GL_GNULIB_NANOSLEEP)/g' \ 2593 -e 's/@''GNULIB_NANOSLEEP''@/$(GL_GNULIB_NANOSLEEP)/g' \
2445 -e 's/@''GNULIB_STRFTIME''@/$(GL_GNULIB_STRFTIME)/g' \ 2594 -e 's/@''GNULIB_STRFTIME''@/$(GL_GNULIB_STRFTIME)/g' \
2446 -e 's/@''GNULIB_STRPTIME''@/$(GL_GNULIB_STRPTIME)/g' \ 2595 -e 's/@''GNULIB_STRPTIME''@/$(GL_GNULIB_STRPTIME)/g' \
2596 -e 's/@''GNULIB_TIME''@/$(GL_GNULIB_TIME)/g' \
2447 -e 's/@''GNULIB_TIMEGM''@/$(GL_GNULIB_TIMEGM)/g' \ 2597 -e 's/@''GNULIB_TIMEGM''@/$(GL_GNULIB_TIMEGM)/g' \
2448 -e 's/@''GNULIB_TIMESPEC_GET''@/$(GL_GNULIB_TIMESPEC_GET)/g' \ 2598 -e 's/@''GNULIB_TIMESPEC_GET''@/$(GL_GNULIB_TIMESPEC_GET)/g' \
2449 -e 's/@''GNULIB_TIMESPEC_GETRES''@/$(GL_GNULIB_TIMESPEC_GETRES)/g' \ 2599 -e 's/@''GNULIB_TIMESPEC_GETRES''@/$(GL_GNULIB_TIMESPEC_GETRES)/g' \
@@ -2465,7 +2615,10 @@ time.h: time.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(
2465 -e 's|@''REPLACE_MKTIME''@|$(REPLACE_MKTIME)|g' \ 2615 -e 's|@''REPLACE_MKTIME''@|$(REPLACE_MKTIME)|g' \
2466 -e 's|@''REPLACE_NANOSLEEP''@|$(REPLACE_NANOSLEEP)|g' \ 2616 -e 's|@''REPLACE_NANOSLEEP''@|$(REPLACE_NANOSLEEP)|g' \
2467 -e 's|@''REPLACE_STRFTIME''@|$(REPLACE_STRFTIME)|g' \ 2617 -e 's|@''REPLACE_STRFTIME''@|$(REPLACE_STRFTIME)|g' \
2618 -e 's|@''REPLACE_TIME''@|$(REPLACE_TIME)|g' \
2468 -e 's|@''REPLACE_TIMEGM''@|$(REPLACE_TIMEGM)|g' \ 2619 -e 's|@''REPLACE_TIMEGM''@|$(REPLACE_TIMEGM)|g' \
2620 -e 's|@''REPLACE_TIMESPEC_GET''@|$(REPLACE_TIMESPEC_GET)|g' \
2621 -e 's|@''REPLACE_TIMESPEC_GETRES''@|$(REPLACE_TIMESPEC_GETRES)|g' \
2469 -e 's|@''REPLACE_TZSET''@|$(REPLACE_TZSET)|g' \ 2622 -e 's|@''REPLACE_TZSET''@|$(REPLACE_TZSET)|g' \
2470 -e 's|@''PTHREAD_H_DEFINES_STRUCT_TIMESPEC''@|$(PTHREAD_H_DEFINES_STRUCT_TIMESPEC)|g' \ 2623 -e 's|@''PTHREAD_H_DEFINES_STRUCT_TIMESPEC''@|$(PTHREAD_H_DEFINES_STRUCT_TIMESPEC)|g' \
2471 -e 's|@''SYS_TIME_H_DEFINES_STRUCT_TIMESPEC''@|$(SYS_TIME_H_DEFINES_STRUCT_TIMESPEC)|g' \ 2624 -e 's|@''SYS_TIME_H_DEFINES_STRUCT_TIMESPEC''@|$(SYS_TIME_H_DEFINES_STRUCT_TIMESPEC)|g' \
@@ -2481,7 +2634,7 @@ MOSTLYCLEANFILES += time.h time.h-t
2481 2634
2482EXTRA_DIST += time.in.h 2635EXTRA_DIST += time.in.h
2483 2636
2484## end gnulib module time 2637## end gnulib module time-h
2485 2638
2486## begin gnulib module time_r 2639## begin gnulib module time_r
2487 2640
@@ -2540,6 +2693,8 @@ unistd.h: unistd.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
2540 -e 's/@''GNULIB_FDATASYNC''@/$(GL_GNULIB_FDATASYNC)/g' \ 2693 -e 's/@''GNULIB_FDATASYNC''@/$(GL_GNULIB_FDATASYNC)/g' \
2541 -e 's/@''GNULIB_FSYNC''@/$(GL_GNULIB_FSYNC)/g' \ 2694 -e 's/@''GNULIB_FSYNC''@/$(GL_GNULIB_FSYNC)/g' \
2542 -e 's/@''GNULIB_FTRUNCATE''@/$(GL_GNULIB_FTRUNCATE)/g' \ 2695 -e 's/@''GNULIB_FTRUNCATE''@/$(GL_GNULIB_FTRUNCATE)/g' \
2696 < $(srcdir)/unistd.in.h > $@-t1
2697 $(AM_V_at)sed \
2543 -e 's/@''GNULIB_GETCWD''@/$(GL_GNULIB_GETCWD)/g' \ 2698 -e 's/@''GNULIB_GETCWD''@/$(GL_GNULIB_GETCWD)/g' \
2544 -e 's/@''GNULIB_GETDOMAINNAME''@/$(GL_GNULIB_GETDOMAINNAME)/g' \ 2699 -e 's/@''GNULIB_GETDOMAINNAME''@/$(GL_GNULIB_GETDOMAINNAME)/g' \
2545 -e 's/@''GNULIB_GETDTABLESIZE''@/$(GL_GNULIB_GETDTABLESIZE)/g' \ 2700 -e 's/@''GNULIB_GETDTABLESIZE''@/$(GL_GNULIB_GETDTABLESIZE)/g' \
@@ -2601,8 +2756,9 @@ unistd.h: unistd.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
2601 -e 's/@''GNULIB_MDA_SWAB''@/$(GL_GNULIB_MDA_SWAB)/g' \ 2756 -e 's/@''GNULIB_MDA_SWAB''@/$(GL_GNULIB_MDA_SWAB)/g' \
2602 -e 's/@''GNULIB_MDA_UNLINK''@/$(GL_GNULIB_MDA_UNLINK)/g' \ 2757 -e 's/@''GNULIB_MDA_UNLINK''@/$(GL_GNULIB_MDA_UNLINK)/g' \
2603 -e 's/@''GNULIB_MDA_WRITE''@/$(GL_GNULIB_MDA_WRITE)/g' \ 2758 -e 's/@''GNULIB_MDA_WRITE''@/$(GL_GNULIB_MDA_WRITE)/g' \
2604 < $(srcdir)/unistd.in.h | \ 2759 < $@-t1 > $@-t2
2605 sed -e 's|@''HAVE_CHOWN''@|$(HAVE_CHOWN)|g' \ 2760 $(AM_V_at)sed \
2761 -e 's|@''HAVE_CHOWN''@|$(HAVE_CHOWN)|g' \
2606 -e 's|@''HAVE_COPY_FILE_RANGE''@|$(HAVE_COPY_FILE_RANGE)|g' \ 2762 -e 's|@''HAVE_COPY_FILE_RANGE''@|$(HAVE_COPY_FILE_RANGE)|g' \
2607 -e 's|@''HAVE_DUP3''@|$(HAVE_DUP3)|g' \ 2763 -e 's|@''HAVE_DUP3''@|$(HAVE_DUP3)|g' \
2608 -e 's|@''HAVE_EUIDACCESS''@|$(HAVE_EUIDACCESS)|g' \ 2764 -e 's|@''HAVE_EUIDACCESS''@|$(HAVE_EUIDACCESS)|g' \
@@ -2649,13 +2805,15 @@ unistd.h: unistd.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
2649 -e 's|@''HAVE_DECL_TTYNAME_R''@|$(HAVE_DECL_TTYNAME_R)|g' \ 2805 -e 's|@''HAVE_DECL_TTYNAME_R''@|$(HAVE_DECL_TTYNAME_R)|g' \
2650 -e 's|@''HAVE_OS_H''@|$(HAVE_OS_H)|g' \ 2806 -e 's|@''HAVE_OS_H''@|$(HAVE_OS_H)|g' \
2651 -e 's|@''HAVE_SYS_PARAM_H''@|$(HAVE_SYS_PARAM_H)|g' \ 2807 -e 's|@''HAVE_SYS_PARAM_H''@|$(HAVE_SYS_PARAM_H)|g' \
2652 | \ 2808 < $@-t2 > $@-t3
2653 sed -e 's|@''REPLACE_ACCESS''@|$(REPLACE_ACCESS)|g' \ 2809 $(AM_V_at)sed \
2810 -e 's|@''REPLACE_ACCESS''@|$(REPLACE_ACCESS)|g' \
2654 -e 's|@''REPLACE_CHOWN''@|$(REPLACE_CHOWN)|g' \ 2811 -e 's|@''REPLACE_CHOWN''@|$(REPLACE_CHOWN)|g' \
2655 -e 's|@''REPLACE_CLOSE''@|$(REPLACE_CLOSE)|g' \ 2812 -e 's|@''REPLACE_CLOSE''@|$(REPLACE_CLOSE)|g' \
2656 -e 's|@''REPLACE_COPY_FILE_RANGE''@|$(REPLACE_COPY_FILE_RANGE)|g' \ 2813 -e 's|@''REPLACE_COPY_FILE_RANGE''@|$(REPLACE_COPY_FILE_RANGE)|g' \
2657 -e 's|@''REPLACE_DUP''@|$(REPLACE_DUP)|g' \ 2814 -e 's|@''REPLACE_DUP''@|$(REPLACE_DUP)|g' \
2658 -e 's|@''REPLACE_DUP2''@|$(REPLACE_DUP2)|g' \ 2815 -e 's|@''REPLACE_DUP2''@|$(REPLACE_DUP2)|g' \
2816 -e 's|@''REPLACE_DUP3''@|$(REPLACE_DUP3)|g' \
2659 -e 's|@''REPLACE_EXECL''@|$(REPLACE_EXECL)|g' \ 2817 -e 's|@''REPLACE_EXECL''@|$(REPLACE_EXECL)|g' \
2660 -e 's|@''REPLACE_EXECLE''@|$(REPLACE_EXECLE)|g' \ 2818 -e 's|@''REPLACE_EXECLE''@|$(REPLACE_EXECLE)|g' \
2661 -e 's|@''REPLACE_EXECLP''@|$(REPLACE_EXECLP)|g' \ 2819 -e 's|@''REPLACE_EXECLP''@|$(REPLACE_EXECLP)|g' \
@@ -2664,11 +2822,14 @@ unistd.h: unistd.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
2664 -e 's|@''REPLACE_EXECVP''@|$(REPLACE_EXECVP)|g' \ 2822 -e 's|@''REPLACE_EXECVP''@|$(REPLACE_EXECVP)|g' \
2665 -e 's|@''REPLACE_EXECVPE''@|$(REPLACE_EXECVPE)|g' \ 2823 -e 's|@''REPLACE_EXECVPE''@|$(REPLACE_EXECVPE)|g' \
2666 -e 's|@''REPLACE_FACCESSAT''@|$(REPLACE_FACCESSAT)|g' \ 2824 -e 's|@''REPLACE_FACCESSAT''@|$(REPLACE_FACCESSAT)|g' \
2825 -e 's|@''REPLACE_FCHDIR''@|$(REPLACE_FCHDIR)|g' \
2667 -e 's|@''REPLACE_FCHOWNAT''@|$(REPLACE_FCHOWNAT)|g' \ 2826 -e 's|@''REPLACE_FCHOWNAT''@|$(REPLACE_FCHOWNAT)|g' \
2827 -e 's|@''REPLACE_FDATASYNC''@|$(REPLACE_FDATASYNC)|g' \
2668 -e 's|@''REPLACE_FTRUNCATE''@|$(REPLACE_FTRUNCATE)|g' \ 2828 -e 's|@''REPLACE_FTRUNCATE''@|$(REPLACE_FTRUNCATE)|g' \
2669 -e 's|@''REPLACE_GETCWD''@|$(REPLACE_GETCWD)|g' \ 2829 -e 's|@''REPLACE_GETCWD''@|$(REPLACE_GETCWD)|g' \
2670 -e 's|@''REPLACE_GETDOMAINNAME''@|$(REPLACE_GETDOMAINNAME)|g' \ 2830 -e 's|@''REPLACE_GETDOMAINNAME''@|$(REPLACE_GETDOMAINNAME)|g' \
2671 -e 's|@''REPLACE_GETDTABLESIZE''@|$(REPLACE_GETDTABLESIZE)|g' \ 2831 -e 's|@''REPLACE_GETDTABLESIZE''@|$(REPLACE_GETDTABLESIZE)|g' \
2832 -e 's|@''REPLACE_GETENTROPY''@|$(REPLACE_GETENTROPY)|g' \
2672 -e 's|@''REPLACE_GETLOGIN_R''@|$(REPLACE_GETLOGIN_R)|g' \ 2833 -e 's|@''REPLACE_GETLOGIN_R''@|$(REPLACE_GETLOGIN_R)|g' \
2673 -e 's|@''REPLACE_GETGROUPS''@|$(REPLACE_GETGROUPS)|g' \ 2834 -e 's|@''REPLACE_GETGROUPS''@|$(REPLACE_GETGROUPS)|g' \
2674 -e 's|@''REPLACE_GETPAGESIZE''@|$(REPLACE_GETPAGESIZE)|g' \ 2835 -e 's|@''REPLACE_GETPAGESIZE''@|$(REPLACE_GETPAGESIZE)|g' \
@@ -2679,12 +2840,14 @@ unistd.h: unistd.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
2679 -e 's|@''REPLACE_LINK''@|$(REPLACE_LINK)|g' \ 2840 -e 's|@''REPLACE_LINK''@|$(REPLACE_LINK)|g' \
2680 -e 's|@''REPLACE_LINKAT''@|$(REPLACE_LINKAT)|g' \ 2841 -e 's|@''REPLACE_LINKAT''@|$(REPLACE_LINKAT)|g' \
2681 -e 's|@''REPLACE_LSEEK''@|$(REPLACE_LSEEK)|g' \ 2842 -e 's|@''REPLACE_LSEEK''@|$(REPLACE_LSEEK)|g' \
2843 -e 's|@''REPLACE_PIPE2''@|$(REPLACE_PIPE2)|g' \
2682 -e 's|@''REPLACE_PREAD''@|$(REPLACE_PREAD)|g' \ 2844 -e 's|@''REPLACE_PREAD''@|$(REPLACE_PREAD)|g' \
2683 -e 's|@''REPLACE_PWRITE''@|$(REPLACE_PWRITE)|g' \ 2845 -e 's|@''REPLACE_PWRITE''@|$(REPLACE_PWRITE)|g' \
2684 -e 's|@''REPLACE_READ''@|$(REPLACE_READ)|g' \ 2846 -e 's|@''REPLACE_READ''@|$(REPLACE_READ)|g' \
2685 -e 's|@''REPLACE_READLINK''@|$(REPLACE_READLINK)|g' \ 2847 -e 's|@''REPLACE_READLINK''@|$(REPLACE_READLINK)|g' \
2686 -e 's|@''REPLACE_READLINKAT''@|$(REPLACE_READLINKAT)|g' \ 2848 -e 's|@''REPLACE_READLINKAT''@|$(REPLACE_READLINKAT)|g' \
2687 -e 's|@''REPLACE_RMDIR''@|$(REPLACE_RMDIR)|g' \ 2849 -e 's|@''REPLACE_RMDIR''@|$(REPLACE_RMDIR)|g' \
2850 -e 's|@''REPLACE_SETHOSTNAME''@|$(REPLACE_SETHOSTNAME)|g' \
2688 -e 's|@''REPLACE_SLEEP''@|$(REPLACE_SLEEP)|g' \ 2851 -e 's|@''REPLACE_SLEEP''@|$(REPLACE_SLEEP)|g' \
2689 -e 's|@''REPLACE_SYMLINK''@|$(REPLACE_SYMLINK)|g' \ 2852 -e 's|@''REPLACE_SYMLINK''@|$(REPLACE_SYMLINK)|g' \
2690 -e 's|@''REPLACE_SYMLINKAT''@|$(REPLACE_SYMLINKAT)|g' \ 2853 -e 's|@''REPLACE_SYMLINKAT''@|$(REPLACE_SYMLINKAT)|g' \
@@ -2700,9 +2863,10 @@ unistd.h: unistd.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
2700 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ 2863 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
2701 -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \ 2864 -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
2702 -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \ 2865 -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
2703 > $@-t 2866 < $@-t3 > $@-t4
2704 $(AM_V_at)mv $@-t $@ 2867 $(AM_V_at)rm -f $@-t1 $@-t2 $@-t3
2705MOSTLYCLEANFILES += unistd.h unistd.h-t 2868 $(AM_V_at)mv $@-t4 $@
2869MOSTLYCLEANFILES += unistd.h unistd.h-t1 unistd.h-t2 unistd.h-t3 unistd.h-t4
2706 2870
2707EXTRA_DIST += unistd.in.h 2871EXTRA_DIST += unistd.in.h
2708 2872
@@ -2777,6 +2941,7 @@ wchar.h: wchar.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
2777 -e 's/@''GNULIB_BTOWC''@/$(GL_GNULIB_BTOWC)/g' \ 2941 -e 's/@''GNULIB_BTOWC''@/$(GL_GNULIB_BTOWC)/g' \
2778 -e 's/@''GNULIB_WCTOB''@/$(GL_GNULIB_WCTOB)/g' \ 2942 -e 's/@''GNULIB_WCTOB''@/$(GL_GNULIB_WCTOB)/g' \
2779 -e 's/@''GNULIB_MBSINIT''@/$(GL_GNULIB_MBSINIT)/g' \ 2943 -e 's/@''GNULIB_MBSINIT''@/$(GL_GNULIB_MBSINIT)/g' \
2944 -e 's/@''GNULIB_MBSZERO''@/$(GL_GNULIB_MBSZERO)/g' \
2780 -e 's/@''GNULIB_MBRTOWC''@/$(GL_GNULIB_MBRTOWC)/g' \ 2945 -e 's/@''GNULIB_MBRTOWC''@/$(GL_GNULIB_MBRTOWC)/g' \
2781 -e 's/@''GNULIB_MBRLEN''@/$(GL_GNULIB_MBRLEN)/g' \ 2946 -e 's/@''GNULIB_MBRLEN''@/$(GL_GNULIB_MBRLEN)/g' \
2782 -e 's/@''GNULIB_MBSRTOWCS''@/$(GL_GNULIB_MBSRTOWCS)/g' \ 2947 -e 's/@''GNULIB_MBSRTOWCS''@/$(GL_GNULIB_MBSRTOWCS)/g' \
@@ -2815,10 +2980,12 @@ wchar.h: wchar.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
2815 -e 's/@''GNULIB_WCSTOK''@/$(GL_GNULIB_WCSTOK)/g' \ 2980 -e 's/@''GNULIB_WCSTOK''@/$(GL_GNULIB_WCSTOK)/g' \
2816 -e 's/@''GNULIB_WCSWIDTH''@/$(GL_GNULIB_WCSWIDTH)/g' \ 2981 -e 's/@''GNULIB_WCSWIDTH''@/$(GL_GNULIB_WCSWIDTH)/g' \
2817 -e 's/@''GNULIB_WCSFTIME''@/$(GL_GNULIB_WCSFTIME)/g' \ 2982 -e 's/@''GNULIB_WCSFTIME''@/$(GL_GNULIB_WCSFTIME)/g' \
2983 -e 's/@''GNULIB_WGETCWD''@/$(GL_GNULIB_WGETCWD)/g' \
2818 -e 's/@''GNULIB_MDA_WCSDUP''@/$(GL_GNULIB_MDA_WCSDUP)/g' \ 2984 -e 's/@''GNULIB_MDA_WCSDUP''@/$(GL_GNULIB_MDA_WCSDUP)/g' \
2819 -e 's/@''GNULIB_FREE_POSIX''@/$(GL_GNULIB_FREE_POSIX)/g' \ 2985 -e 's/@''GNULIB_FREE_POSIX''@/$(GL_GNULIB_FREE_POSIX)/g' \
2820 < $(srcdir)/wchar.in.h | \ 2986 < $(srcdir)/wchar.in.h > $@-t1
2821 sed -e 's|@''HAVE_WINT_T''@|$(HAVE_WINT_T)|g' \ 2987 $(AM_V_at)sed \
2988 -e 's|@''HAVE_WINT_T''@|$(HAVE_WINT_T)|g' \
2822 -e 's|@''HAVE_BTOWC''@|$(HAVE_BTOWC)|g' \ 2989 -e 's|@''HAVE_BTOWC''@|$(HAVE_BTOWC)|g' \
2823 -e 's|@''HAVE_MBSINIT''@|$(HAVE_MBSINIT)|g' \ 2990 -e 's|@''HAVE_MBSINIT''@|$(HAVE_MBSINIT)|g' \
2824 -e 's|@''HAVE_MBRTOWC''@|$(HAVE_MBRTOWC)|g' \ 2991 -e 's|@''HAVE_MBRTOWC''@|$(HAVE_MBRTOWC)|g' \
@@ -2861,8 +3028,9 @@ wchar.h: wchar.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
2861 -e 's|@''HAVE_DECL_WCTOB''@|$(HAVE_DECL_WCTOB)|g' \ 3028 -e 's|@''HAVE_DECL_WCTOB''@|$(HAVE_DECL_WCTOB)|g' \
2862 -e 's|@''HAVE_DECL_WCSDUP''@|$(HAVE_DECL_WCSDUP)|g' \ 3029 -e 's|@''HAVE_DECL_WCSDUP''@|$(HAVE_DECL_WCSDUP)|g' \
2863 -e 's|@''HAVE_DECL_WCWIDTH''@|$(HAVE_DECL_WCWIDTH)|g' \ 3030 -e 's|@''HAVE_DECL_WCWIDTH''@|$(HAVE_DECL_WCWIDTH)|g' \
2864 | \ 3031 < $@-t1 > $@-t2
2865 sed -e 's|@''REPLACE_MBSTATE_T''@|$(REPLACE_MBSTATE_T)|g' \ 3032 $(AM_V_at)sed \
3033 -e 's|@''REPLACE_MBSTATE_T''@|$(REPLACE_MBSTATE_T)|g' \
2866 -e 's|@''REPLACE_BTOWC''@|$(REPLACE_BTOWC)|g' \ 3034 -e 's|@''REPLACE_BTOWC''@|$(REPLACE_BTOWC)|g' \
2867 -e 's|@''REPLACE_WCTOB''@|$(REPLACE_WCTOB)|g' \ 3035 -e 's|@''REPLACE_WCTOB''@|$(REPLACE_WCTOB)|g' \
2868 -e 's|@''REPLACE_FREE''@|$(REPLACE_FREE)|g' \ 3036 -e 's|@''REPLACE_FREE''@|$(REPLACE_FREE)|g' \
@@ -2877,13 +3045,19 @@ wchar.h: wchar.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
2877 -e 's|@''REPLACE_WCWIDTH''@|$(REPLACE_WCWIDTH)|g' \ 3045 -e 's|@''REPLACE_WCWIDTH''@|$(REPLACE_WCWIDTH)|g' \
2878 -e 's|@''REPLACE_WCSWIDTH''@|$(REPLACE_WCSWIDTH)|g' \ 3046 -e 's|@''REPLACE_WCSWIDTH''@|$(REPLACE_WCSWIDTH)|g' \
2879 -e 's|@''REPLACE_WCSFTIME''@|$(REPLACE_WCSFTIME)|g' \ 3047 -e 's|@''REPLACE_WCSFTIME''@|$(REPLACE_WCSFTIME)|g' \
3048 -e 's|@''REPLACE_WCSCMP''@|$(REPLACE_WCSCMP)|g' \
3049 -e 's|@''REPLACE_WCSNCMP''@|$(REPLACE_WCSNCMP)|g' \
3050 -e 's|@''REPLACE_WCSSTR''@|$(REPLACE_WCSSTR)|g' \
2880 -e 's|@''REPLACE_WCSTOK''@|$(REPLACE_WCSTOK)|g' \ 3051 -e 's|@''REPLACE_WCSTOK''@|$(REPLACE_WCSTOK)|g' \
3052 -e 's|@''REPLACE_WMEMCMP''@|$(REPLACE_WMEMCMP)|g' \
3053 -e 's|@''REPLACE_WMEMPCPY''@|$(REPLACE_WMEMPCPY)|g' \
2881 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ 3054 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
2882 -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \ 3055 -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
2883 -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \ 3056 -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
2884 > $@-t 3057 < $@-t2 > $@-t3
2885 $(AM_V_at)mv $@-t $@ 3058 $(AM_V_at)rm -f $@-t1 $@-t2
2886MOSTLYCLEANFILES += wchar.h wchar.h-t 3059 $(AM_V_at)mv $@-t3 $@
3060MOSTLYCLEANFILES += wchar.h wchar.h-t1 wchar.h-t2 wchar.h-t3
2887 3061
2888EXTRA_DIST += wchar.in.h 3062EXTRA_DIST += wchar.in.h
2889 3063
@@ -2897,6 +3071,16 @@ endif
2897 3071
2898## end gnulib module wcrtomb 3072## end gnulib module wcrtomb
2899 3073
3074## begin gnulib module wctype
3075
3076if GL_COND_OBJ_WCTYPE
3077libgnu_a_SOURCES += wctype.c
3078endif
3079
3080EXTRA_DIST += wctype-impl.h
3081
3082## end gnulib module wctype
3083
2900## begin gnulib module wctype-h 3084## begin gnulib module wctype-h
2901 3085
2902BUILT_SOURCES += wctype.h 3086BUILT_SOURCES += wctype.h
@@ -2904,7 +3088,7 @@ libgnu_a_SOURCES += wctype-h.c
2904 3088
2905# We need the following in order to create <wctype.h> when the system 3089# We need the following in order to create <wctype.h> when the system
2906# doesn't have one that works with the given compiler. 3090# doesn't have one that works with the given compiler.
2907wctype.h: wctype.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(WARN_ON_USE_H) 3091wctype.h: wctype.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)
2908 $(gl_V_at)$(SED_HEADER_STDOUT) \ 3092 $(gl_V_at)$(SED_HEADER_STDOUT) \
2909 -e 's|@''GUARD_PREFIX''@|GL|g' \ 3093 -e 's|@''GUARD_PREFIX''@|GL|g' \
2910 -e 's/@''HAVE_WCTYPE_H''@/$(HAVE_WCTYPE_H)/g' \ 3094 -e 's/@''HAVE_WCTYPE_H''@/$(HAVE_WCTYPE_H)/g' \
@@ -2916,6 +3100,7 @@ wctype.h: wctype.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(WARN_ON_USE_H
2916 -e 's/@''GNULIBHEADERS_OVERRIDE_WINT_T''@/$(GNULIBHEADERS_OVERRIDE_WINT_T)/g' \ 3100 -e 's/@''GNULIBHEADERS_OVERRIDE_WINT_T''@/$(GNULIBHEADERS_OVERRIDE_WINT_T)/g' \
2917 -e 's/@''GNULIB_ISWBLANK''@/$(GL_GNULIB_ISWBLANK)/g' \ 3101 -e 's/@''GNULIB_ISWBLANK''@/$(GL_GNULIB_ISWBLANK)/g' \
2918 -e 's/@''GNULIB_ISWDIGIT''@/$(GL_GNULIB_ISWDIGIT)/g' \ 3102 -e 's/@''GNULIB_ISWDIGIT''@/$(GL_GNULIB_ISWDIGIT)/g' \
3103 -e 's/@''GNULIB_ISWPUNCT''@/$(GL_GNULIB_ISWPUNCT)/g' \
2919 -e 's/@''GNULIB_ISWXDIGIT''@/$(GL_GNULIB_ISWXDIGIT)/g' \ 3104 -e 's/@''GNULIB_ISWXDIGIT''@/$(GL_GNULIB_ISWXDIGIT)/g' \
2920 -e 's/@''GNULIB_WCTYPE''@/$(GL_GNULIB_WCTYPE)/g' \ 3105 -e 's/@''GNULIB_WCTYPE''@/$(GL_GNULIB_WCTYPE)/g' \
2921 -e 's/@''GNULIB_ISWCTYPE''@/$(GL_GNULIB_ISWCTYPE)/g' \ 3106 -e 's/@''GNULIB_ISWCTYPE''@/$(GL_GNULIB_ISWCTYPE)/g' \
@@ -2928,10 +3113,14 @@ wctype.h: wctype.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(WARN_ON_USE_H
2928 -e 's/@''HAVE_WINT_T''@/$(HAVE_WINT_T)/g' \ 3113 -e 's/@''HAVE_WINT_T''@/$(HAVE_WINT_T)/g' \
2929 -e 's/@''REPLACE_ISWBLANK''@/$(REPLACE_ISWBLANK)/g' \ 3114 -e 's/@''REPLACE_ISWBLANK''@/$(REPLACE_ISWBLANK)/g' \
2930 -e 's/@''REPLACE_ISWDIGIT''@/$(REPLACE_ISWDIGIT)/g' \ 3115 -e 's/@''REPLACE_ISWDIGIT''@/$(REPLACE_ISWDIGIT)/g' \
3116 -e 's/@''REPLACE_ISWPUNCT''@/$(REPLACE_ISWPUNCT)/g' \
2931 -e 's/@''REPLACE_ISWXDIGIT''@/$(REPLACE_ISWXDIGIT)/g' \ 3117 -e 's/@''REPLACE_ISWXDIGIT''@/$(REPLACE_ISWXDIGIT)/g' \
2932 -e 's/@''REPLACE_ISWCNTRL''@/$(REPLACE_ISWCNTRL)/g' \ 3118 -e 's/@''REPLACE_ISWCNTRL''@/$(REPLACE_ISWCNTRL)/g' \
2933 -e 's/@''REPLACE_TOWLOWER''@/$(REPLACE_TOWLOWER)/g' \ 3119 -e 's/@''REPLACE_TOWLOWER''@/$(REPLACE_TOWLOWER)/g' \
3120 -e 's/@''REPLACE_WCTRANS''@/$(REPLACE_WCTRANS)/g' \
3121 -e 's/@''REPLACE_WCTYPE''@/$(REPLACE_WCTYPE)/g' \
2934 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ 3122 -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
3123 -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
2935 -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \ 3124 -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
2936 $(srcdir)/wctype.in.h > $@-t 3125 $(srcdir)/wctype.in.h > $@-t
2937 $(AM_V_at)mv $@-t $@ 3126 $(AM_V_at)mv $@-t $@
diff --git a/gl/_Noreturn.h b/gl/_Noreturn.h
index 6ecea98b..7326bd47 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2011-2024 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/af_alg.c b/gl/af_alg.c
index 9f022ce5..6fd08c28 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2018-2024 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 e8ffb3f7..ed933e12 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2018-2024 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 a1bb3d75..6aa47df8 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-2023 Free Software Foundation, 3 Copyright (C) 1995, 1999, 2001-2004, 2006-2024 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 9498ae1f..46c711ca 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2009-2024 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.in.h b/gl/arpa_inet.in.h
index 80e6713f..523a448c 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2005-2006, 2008-2024 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
@@ -49,6 +49,11 @@
49#ifndef _@GUARD_PREFIX@_ARPA_INET_H 49#ifndef _@GUARD_PREFIX@_ARPA_INET_H
50#define _@GUARD_PREFIX@_ARPA_INET_H 50#define _@GUARD_PREFIX@_ARPA_INET_H
51 51
52/* This file uses GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */
53#if !_GL_CONFIG_H_INCLUDED
54 #error "Please include config.h first."
55#endif
56
52/* Get all possible declarations of inet_ntop() and inet_pton(). */ 57/* Get all possible declarations of inet_ntop() and inet_pton(). */
53#if (@GNULIB_INET_NTOP@ || @GNULIB_INET_PTON@ || defined GNULIB_POSIXCHECK) \ 58#if (@GNULIB_INET_NTOP@ || @GNULIB_INET_PTON@ || defined GNULIB_POSIXCHECK) \
54 && @HAVE_WS2TCPIP_H@ 59 && @HAVE_WS2TCPIP_H@
diff --git a/gl/asnprintf.c b/gl/asnprintf.c
index f4861bf8..a6c09bc2 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2002, 2006, 2009-2024 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 ba58e064..b0c33478 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-2023 Free Software Foundation, 2 Copyright (C) 1999, 2002, 2006-2007, 2009-2024 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 b0ab99c7..6e4995e1 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2011-2024 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 130644d8..710341ba 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-2023 Free Software Foundation, Inc. 3 Copyright 2020-2024 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
@@ -41,6 +41,21 @@
41 These names begin with 'ATTRIBUTE_' to avoid name clashes. */ 41 These names begin with 'ATTRIBUTE_' to avoid name clashes. */
42 42
43 43
44/* This file uses _GL_ATTRIBUTE_ALLOC_SIZE, _GL_ATTRIBUTE_ALWAYS_INLINE,
45 _GL_ATTRIBUTE_ARTIFICIAL, _GL_ATTRIBUTE_COLD, _GL_ATTRIBUTE_CONST,
46 _GL_ATTRIBUTE_DEALLOC, _GL_ATTRIBUTE_DEPRECATED, _GL_ATTRIBUTE_ERROR,
47 _GL_ATTRIBUTE_WARNING, _GL_ATTRIBUTE_EXTERNALLY_VISIBLE,
48 _GL_ATTRIBUTE_FALLTHROUGH, _GL_ATTRIBUTE_FORMAT, _GL_ATTRIBUTE_LEAF,
49 _GL_ATTRIBUTE_MALLOC, _GL_ATTRIBUTE_MAY_ALIAS, _GL_ATTRIBUTE_MAYBE_UNUSED,
50 _GL_ATTRIBUTE_NODISCARD, _GL_ATTRIBUTE_NOINLINE, _GL_ATTRIBUTE_NONNULL,
51 _GL_ATTRIBUTE_NONSTRING, _GL_ATTRIBUTE_NOTHROW, _GL_ATTRIBUTE_PACKED,
52 _GL_ATTRIBUTE_PURE, _GL_ATTRIBUTE_RETURNS_NONNULL,
53 _GL_ATTRIBUTE_SENTINEL. */
54#if !_GL_CONFIG_H_INCLUDED
55 #error "Please include config.h first."
56#endif
57
58
44/* =============== Attributes for specific kinds of functions =============== */ 59/* =============== Attributes for specific kinds of functions =============== */
45 60
46/* Attributes for functions that should not be used. */ 61/* Attributes for functions that should not be used. */
@@ -167,6 +182,8 @@
167 182
168/* The function does not throw exceptions. */ 183/* The function does not throw exceptions. */
169/* Applies to: functions. */ 184/* Applies to: functions. */
185/* After a function's parameter list, this attribute must come first, before
186 other attributes. */
170#define ATTRIBUTE_NOTHROW _GL_ATTRIBUTE_NOTHROW 187#define ATTRIBUTE_NOTHROW _GL_ATTRIBUTE_NOTHROW
171 188
172/* Do not inline the function. */ 189/* Do not inline the function. */
diff --git a/gl/base64.c b/gl/base64.c
index 95b669aa..c8b3b76b 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 1999-2001, 2004-2006, 2009-2024 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
@@ -42,6 +42,7 @@
42#include <config.h> 42#include <config.h>
43 43
44/* Get prototype. */ 44/* Get prototype. */
45#define BASE64_INLINE _GL_EXTERN_INLINE
45#include "base64.h" 46#include "base64.h"
46 47
47/* Get imalloc. */ 48/* Get imalloc. */
@@ -49,9 +50,6 @@
49 50
50#include <intprops.h> 51#include <intprops.h>
51 52
52/* Get UCHAR_MAX. */
53#include <limits.h>
54
55#include <string.h> 53#include <string.h>
56 54
57/* Convert 'char' to 'unsigned char' without casting. */ 55/* Convert 'char' to 'unsigned char' without casting. */
@@ -242,7 +240,7 @@ base64_encode_alloc (const char *in, idx_t inlen, char **out)
242 : (_) == '/' ? 63 \ 240 : (_) == '/' ? 63 \
243 : -1) 241 : -1)
244 242
245static const signed char b64[0x100] = { 243signed char const base64_to_int[256] = {
246 B64 (0), B64 (1), B64 (2), B64 (3), 244 B64 (0), B64 (1), B64 (2), B64 (3),
247 B64 (4), B64 (5), B64 (6), B64 (7), 245 B64 (4), B64 (5), B64 (6), B64 (7),
248 B64 (8), B64 (9), B64 (10), B64 (11), 246 B64 (8), B64 (9), B64 (10), B64 (11),
@@ -309,28 +307,6 @@ static const signed char b64[0x100] = {
309 B64 (252), B64 (253), B64 (254), B64 (255) 307 B64 (252), B64 (253), B64 (254), B64 (255)
310}; 308};
311 309
312#if UCHAR_MAX == 255
313# define uchar_in_range(c) true
314#else
315# define uchar_in_range(c) ((c) <= 255)
316#endif
317
318/* Return true if CH is a character from the Base64 alphabet, and
319 false otherwise. Note that '=' is padding and not considered to be
320 part of the alphabet. */
321bool
322isbase64 (char ch)
323{
324 return uchar_in_range (to_uchar (ch)) && 0 <= b64[to_uchar (ch)];
325}
326
327/* Initialize decode-context buffer, CTX. */
328void
329base64_decode_ctx_init (struct base64_decode_context *ctx)
330{
331 ctx->i = 0;
332}
333
334/* If CTX->i is 0 or 4, there are four or more bytes in [*IN..IN_END), and 310/* If CTX->i is 0 or 4, there are four or more bytes in [*IN..IN_END), and
335 none of those four is a newline, then return *IN. Otherwise, copy up to 311 none of those four is a newline, then return *IN. Otherwise, copy up to
336 4 - CTX->i non-newline bytes from that range into CTX->buf, starting at 312 4 - CTX->i non-newline bytes from that range into CTX->buf, starting at
@@ -405,8 +381,8 @@ decode_4 (char const *restrict in, idx_t inlen,
405 381
406 if (*outleft) 382 if (*outleft)
407 { 383 {
408 *out++ = ((b64[to_uchar (in[0])] << 2) 384 *out++ = ((base64_to_int[to_uchar (in[0])] << 2)
409 | (b64[to_uchar (in[1])] >> 4)); 385 | (base64_to_int[to_uchar (in[1])] >> 4));
410 --*outleft; 386 --*outleft;
411 } 387 }
412 388
@@ -420,6 +396,10 @@ decode_4 (char const *restrict in, idx_t inlen,
420 396
421 if (in[3] != '=') 397 if (in[3] != '=')
422 return_false; 398 return_false;
399
400 /* Reject non-canonical encodings. */
401 if (base64_to_int[to_uchar (in[1])] & 0x0f)
402 return_false;
423 } 403 }
424 else 404 else
425 { 405 {
@@ -428,8 +408,8 @@ decode_4 (char const *restrict in, idx_t inlen,
428 408
429 if (*outleft) 409 if (*outleft)
430 { 410 {
431 *out++ = (((b64[to_uchar (in[1])] << 4) & 0xf0) 411 *out++ = (((base64_to_int[to_uchar (in[1])] << 4) & 0xf0)
432 | (b64[to_uchar (in[2])] >> 2)); 412 | (base64_to_int[to_uchar (in[2])] >> 2));
433 --*outleft; 413 --*outleft;
434 } 414 }
435 415
@@ -440,6 +420,10 @@ decode_4 (char const *restrict in, idx_t inlen,
440 { 420 {
441 if (inlen != 4) 421 if (inlen != 4)
442 return_false; 422 return_false;
423
424 /* Reject non-canonical encodings. */
425 if (base64_to_int[to_uchar (in[2])] & 0x03)
426 return_false;
443 } 427 }
444 else 428 else
445 { 429 {
@@ -448,8 +432,8 @@ decode_4 (char const *restrict in, idx_t inlen,
448 432
449 if (*outleft) 433 if (*outleft)
450 { 434 {
451 *out++ = (((b64[to_uchar (in[2])] << 6) & 0xc0) 435 *out++ = (((base64_to_int[to_uchar (in[2])] << 6) & 0xc0)
452 | b64[to_uchar (in[3])]); 436 | base64_to_int[to_uchar (in[3])]);
453 --*outleft; 437 --*outleft;
454 } 438 }
455 } 439 }
diff --git a/gl/base64.h b/gl/base64.h
index 99137652..7691f6c4 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2004-2006, 2009-2024 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
@@ -16,18 +16,33 @@
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 BASE64_H 18#ifndef BASE64_H
19# define BASE64_H 19#define BASE64_H
20
21/* This file uses _GL_INLINE_HEADER_BEGIN. */
22#if !_GL_CONFIG_H_INCLUDED
23 #error "Please include config.h first."
24#endif
20 25
21/* Get idx_t. */ 26/* Get idx_t. */
22# include <idx.h> 27#include <idx.h>
28
29/* Pacify GCC in isubase64. */
30#if defined __GNUC__ && 4 < __GNUC__ + (3 <= __GNUC_MINOR__)
31# pragma GCC diagnostic ignored "-Wtype-limits"
32#endif
33
34_GL_INLINE_HEADER_BEGIN
35#ifndef BASE64_INLINE
36# define BASE64_INLINE _GL_INLINE
37#endif
23 38
24# ifdef __cplusplus 39#ifdef __cplusplus
25extern "C" { 40extern "C" {
26# endif 41#endif
27 42
28/* This uses that the expression (n+(k-1))/k means the smallest 43/* This uses that the expression (n+(k-1))/k means the smallest
29 integer >= n/k, i.e., the ceiling of n/k. */ 44 integer >= n/k, i.e., the ceiling of n/k. */
30# define BASE64_LENGTH(inlen) ((((inlen) + 2) / 3) * 4) 45#define BASE64_LENGTH(inlen) ((((inlen) + 2) / 3) * 4)
31 46
32struct base64_decode_context 47struct base64_decode_context
33{ 48{
@@ -35,14 +50,31 @@ struct base64_decode_context
35 char buf[4]; 50 char buf[4];
36}; 51};
37 52
38extern bool isbase64 (char ch) _GL_ATTRIBUTE_CONST; 53extern signed char const base64_to_int[256];
54
55BASE64_INLINE bool
56isubase64 (unsigned char ch)
57{
58 return ch < sizeof base64_to_int && 0 <= base64_to_int[ch];
59}
60
61BASE64_INLINE bool
62isbase64 (char ch)
63{
64 return isubase64 (ch);
65}
39 66
40extern void base64_encode (const char *restrict in, idx_t inlen, 67extern void base64_encode (const char *restrict in, idx_t inlen,
41 char *restrict out, idx_t outlen); 68 char *restrict out, idx_t outlen);
42 69
43extern idx_t base64_encode_alloc (const char *in, idx_t inlen, char **out); 70extern idx_t base64_encode_alloc (const char *in, idx_t inlen, char **out);
44 71
45extern void base64_decode_ctx_init (struct base64_decode_context *ctx); 72/* Initialize decode-context buffer, CTX. */
73BASE64_INLINE void
74base64_decode_ctx_init (struct base64_decode_context *ctx)
75{
76 ctx->i = 0;
77}
46 78
47extern bool base64_decode_ctx (struct base64_decode_context *ctx, 79extern bool base64_decode_ctx (struct base64_decode_context *ctx,
48 const char *restrict in, idx_t inlen, 80 const char *restrict in, idx_t inlen,
@@ -58,8 +90,10 @@ extern bool base64_decode_alloc_ctx (struct base64_decode_context *ctx,
58#define base64_decode_alloc(in, inlen, out, outlen) \ 90#define base64_decode_alloc(in, inlen, out, outlen) \
59 base64_decode_alloc_ctx (NULL, in, inlen, out, outlen) 91 base64_decode_alloc_ctx (NULL, in, inlen, out, outlen)
60 92
61# ifdef __cplusplus 93#ifdef __cplusplus
62} 94}
63# endif 95#endif
96
97_GL_INLINE_HEADER_END
64 98
65#endif /* BASE64_H */ 99#endif /* BASE64_H */
diff --git a/gl/basename-lgpl.c b/gl/basename-lgpl.c
index 6de60aa6..256f8460 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-2023 Free Software 3 Copyright (C) 1990, 1998-2001, 2003-2006, 2009-2024 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 5d996c1d..2a56be98 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-2023 Free Software Foundation, 3 Copyright (C) 1998, 2001, 2003-2006, 2009-2024 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
@@ -19,6 +19,11 @@
19#ifndef _BASENAME_LGPL_H 19#ifndef _BASENAME_LGPL_H
20#define _BASENAME_LGPL_H 20#define _BASENAME_LGPL_H
21 21
22/* This file uses _GL_ATTRIBUTE_PURE. */
23#if !_GL_CONFIG_H_INCLUDED
24 #error "Please include config.h first."
25#endif
26
22#include <stddef.h> 27#include <stddef.h>
23 28
24#ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT 29#ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT
diff --git a/gl/basename.c b/gl/basename.c
index 21fab1ef..c5a6bdc9 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-2023 Free Software 3 Copyright (C) 1990, 1998-2001, 2003-2006, 2009-2024 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 caadbd76..8bf21aa6 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2008, 2010-2024 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
@@ -22,6 +22,7 @@
22 22
23#include <stdio.h> 23#include <stdio.h>
24#include <stdlib.h> 24#include <stdlib.h>
25#include <string.h>
25 26
26wint_t 27wint_t
27btowc (int c) 28btowc (int c)
@@ -32,7 +33,14 @@ btowc (int c)
32 wchar_t wc; 33 wchar_t wc;
33 34
34 buf[0] = c; 35 buf[0] = c;
36#if HAVE_MBRTOWC
37 mbstate_t state;
38 mbszero (&state);
39 size_t ret = mbrtowc (&wc, buf, 1, &state);
40 if (!(ret == (size_t)(-1) || ret == (size_t)(-2)))
41#else
35 if (mbtowc (&wc, buf, 1) >= 0) 42 if (mbtowc (&wc, buf, 1) >= 0)
43#endif
36 return wc; 44 return wc;
37 } 45 }
38 return WEOF; 46 return WEOF;
diff --git a/gl/byteswap.in.h b/gl/byteswap.in.h
index e61be27e..8e49efad 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2005, 2007, 2009-2024 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
diff --git a/gl/c++defs.h b/gl/c++defs.h
index 8ad46951..eb66967b 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2010-2024 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
@@ -99,6 +99,12 @@
99 Example: 99 Example:
100 _GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...) 100 _GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...)
101 _GL_ARG_NONNULL ((1))); 101 _GL_ARG_NONNULL ((1)));
102
103 Note: Attributes, such as _GL_ATTRIBUTE_DEPRECATED, are supported in front
104 of a _GL_FUNCDECL_RPL invocation only in C mode, not in C++ mode. (That's
105 because
106 [[...]] extern "C" <declaration>;
107 is invalid syntax in C++.)
102 */ 108 */
103#define _GL_FUNCDECL_RPL(func,rettype,parameters_and_attributes) \ 109#define _GL_FUNCDECL_RPL(func,rettype,parameters_and_attributes) \
104 _GL_FUNCDECL_RPL_1 (rpl_##func, rettype, parameters_and_attributes) 110 _GL_FUNCDECL_RPL_1 (rpl_##func, rettype, parameters_and_attributes)
diff --git a/gl/calloc.c b/gl/calloc.c
index 08843acd..81dfd3ef 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2004-2007, 2009-2024 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/cdefs.h b/gl/cdefs.h
index 09a3d19b..d38382ad 100644
--- a/gl/cdefs.h
+++ b/gl/cdefs.h
@@ -1,4 +1,4 @@
1/* Copyright (C) 1992-2023 Free Software Foundation, Inc. 1/* Copyright (C) 1992-2024 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
@@ -42,8 +42,8 @@
42#if (defined __has_attribute \ 42#if (defined __has_attribute \
43 && (!defined __clang_minor__ \ 43 && (!defined __clang_minor__ \
44 || (defined __apple_build_version__ \ 44 || (defined __apple_build_version__ \
45 ? 6000000 <= __apple_build_version__ \ 45 ? 7000000 <= __apple_build_version__ \
46 : 3 < __clang_major__ + (5 <= __clang_minor__)))) 46 : 5 <= __clang_major__)))
47# define __glibc_has_attribute(attr) __has_attribute (attr) 47# define __glibc_has_attribute(attr) __has_attribute (attr)
48#else 48#else
49# define __glibc_has_attribute(attr) 0 49# define __glibc_has_attribute(attr) 0
@@ -140,32 +140,37 @@
140#endif 140#endif
141 141
142 142
143/* Gnulib avoids these definitions, as they don't work on non-glibc platforms.
144 In particular, __bos and __bos0 are defined differently in the Android libc.
145 */
146#ifndef __GNULIB_CDEFS
147
143/* Fortify support. */ 148/* Fortify support. */
144#define __bos(ptr) __builtin_object_size (ptr, __USE_FORTIFY_LEVEL > 1) 149# define __bos(ptr) __builtin_object_size (ptr, __USE_FORTIFY_LEVEL > 1)
145#define __bos0(ptr) __builtin_object_size (ptr, 0) 150# define __bos0(ptr) __builtin_object_size (ptr, 0)
146 151
147/* Use __builtin_dynamic_object_size at _FORTIFY_SOURCE=3 when available. */ 152/* Use __builtin_dynamic_object_size at _FORTIFY_SOURCE=3 when available. */
148#if __USE_FORTIFY_LEVEL == 3 && (__glibc_clang_prereq (9, 0) \ 153# if __USE_FORTIFY_LEVEL == 3 && (__glibc_clang_prereq (9, 0) \
149 || __GNUC_PREREQ (12, 0)) 154 || __GNUC_PREREQ (12, 0))
150# define __glibc_objsize0(__o) __builtin_dynamic_object_size (__o, 0) 155# define __glibc_objsize0(__o) __builtin_dynamic_object_size (__o, 0)
151# define __glibc_objsize(__o) __builtin_dynamic_object_size (__o, 1) 156# define __glibc_objsize(__o) __builtin_dynamic_object_size (__o, 1)
152#else 157# else
153# define __glibc_objsize0(__o) __bos0 (__o) 158# define __glibc_objsize0(__o) __bos0 (__o)
154# define __glibc_objsize(__o) __bos (__o) 159# define __glibc_objsize(__o) __bos (__o)
155#endif 160# endif
156 161
157/* Compile time conditions to choose between the regular, _chk and _chk_warn 162/* Compile time conditions to choose between the regular, _chk and _chk_warn
158 variants. These conditions should get evaluated to constant and optimized 163 variants. These conditions should get evaluated to constant and optimized
159 away. */ 164 away. */
160 165
161#define __glibc_safe_len_cond(__l, __s, __osz) ((__l) <= (__osz) / (__s)) 166# define __glibc_safe_len_cond(__l, __s, __osz) ((__l) <= (__osz) / (__s))
162#define __glibc_unsigned_or_positive(__l) \ 167# define __glibc_unsigned_or_positive(__l) \
163 ((__typeof (__l)) 0 < (__typeof (__l)) -1 \ 168 ((__typeof (__l)) 0 < (__typeof (__l)) -1 \
164 || (__builtin_constant_p (__l) && (__l) > 0)) 169 || (__builtin_constant_p (__l) && (__l) > 0))
165 170
166/* Length is known to be safe at compile time if the __L * __S <= __OBJSZ 171/* Length is known to be safe at compile time if the __L * __S <= __OBJSZ
167 condition can be folded to a constant and if it is true, or unknown (-1) */ 172 condition can be folded to a constant and if it is true, or unknown (-1) */
168#define __glibc_safe_or_unknown_len(__l, __s, __osz) \ 173# define __glibc_safe_or_unknown_len(__l, __s, __osz) \
169 ((__osz) == (__SIZE_TYPE__) -1 \ 174 ((__osz) == (__SIZE_TYPE__) -1 \
170 || (__glibc_unsigned_or_positive (__l) \ 175 || (__glibc_unsigned_or_positive (__l) \
171 && __builtin_constant_p (__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), \ 176 && __builtin_constant_p (__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), \
@@ -175,7 +180,7 @@
175/* Conversely, we know at compile time that the length is unsafe if the 180/* Conversely, we know at compile time that the length is unsafe if the
176 __L * __S <= __OBJSZ condition can be folded to a constant and if it is 181 __L * __S <= __OBJSZ condition can be folded to a constant and if it is
177 false. */ 182 false. */
178#define __glibc_unsafe_len(__l, __s, __osz) \ 183# define __glibc_unsafe_len(__l, __s, __osz) \
179 (__glibc_unsigned_or_positive (__l) \ 184 (__glibc_unsigned_or_positive (__l) \
180 && __builtin_constant_p (__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), \ 185 && __builtin_constant_p (__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), \
181 __s, __osz)) \ 186 __s, __osz)) \
@@ -184,7 +189,7 @@
184/* Fortify function f. __f_alias, __f_chk and __f_chk_warn must be 189/* Fortify function f. __f_alias, __f_chk and __f_chk_warn must be
185 declared. */ 190 declared. */
186 191
187#define __glibc_fortify(f, __l, __s, __osz, ...) \ 192# define __glibc_fortify(f, __l, __s, __osz, ...) \
188 (__glibc_safe_or_unknown_len (__l, __s, __osz) \ 193 (__glibc_safe_or_unknown_len (__l, __s, __osz) \
189 ? __ ## f ## _alias (__VA_ARGS__) \ 194 ? __ ## f ## _alias (__VA_ARGS__) \
190 : (__glibc_unsafe_len (__l, __s, __osz) \ 195 : (__glibc_unsafe_len (__l, __s, __osz) \
@@ -194,13 +199,16 @@
194/* Fortify function f, where object size argument passed to f is the number of 199/* Fortify function f, where object size argument passed to f is the number of
195 elements and not total size. */ 200 elements and not total size. */
196 201
197#define __glibc_fortify_n(f, __l, __s, __osz, ...) \ 202# define __glibc_fortify_n(f, __l, __s, __osz, ...) \
198 (__glibc_safe_or_unknown_len (__l, __s, __osz) \ 203 (__glibc_safe_or_unknown_len (__l, __s, __osz) \
199 ? __ ## f ## _alias (__VA_ARGS__) \ 204 ? __ ## f ## _alias (__VA_ARGS__) \
200 : (__glibc_unsafe_len (__l, __s, __osz) \ 205 : (__glibc_unsafe_len (__l, __s, __osz) \
201 ? __ ## f ## _chk_warn (__VA_ARGS__, (__osz) / (__s)) \ 206 ? __ ## f ## _chk_warn (__VA_ARGS__, (__osz) / (__s)) \
202 : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s)))) \ 207 : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s)))) \
203 208
209#endif
210
211
204#if __GNUC_PREREQ (4,3) 212#if __GNUC_PREREQ (4,3)
205# define __warnattr(msg) __attribute__((__warning__ (msg))) 213# define __warnattr(msg) __attribute__((__warning__ (msg)))
206# define __errordecl(name, msg) \ 214# define __errordecl(name, msg) \
diff --git a/gl/cloexec.c b/gl/cloexec.c
index e4cecbd2..cdb0d740 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 1991, 2004-2006, 2009-2024 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 057fd668..a7944d6d 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2004, 2009-2024 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,6 +15,11 @@
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#ifdef __cplusplus
19extern "C" {
20#endif
21
22
18/* Set the 'FD_CLOEXEC' flag of DESC if VALUE is true, 23/* Set the 'FD_CLOEXEC' flag of DESC if VALUE is true,
19 or clear the flag if VALUE is false. 24 or clear the flag if VALUE is false.
20 Return 0 on success, or -1 on error with 'errno' set. 25 Return 0 on success, or -1 on error with 'errno' set.
@@ -32,3 +37,8 @@ int set_cloexec_flag (int desc, bool value);
32 be duplicated. */ 37 be duplicated. */
33 38
34int dup_cloexec (int fd); 39int dup_cloexec (int fd);
40
41
42#ifdef __cplusplus
43}
44#endif
diff --git a/gl/close.c b/gl/close.c
index 3c1b09ea..830fd820 100644
--- a/gl/close.c
+++ b/gl/close.c
@@ -1,5 +1,5 @@
1/* close replacement. 1/* close replacement.
2 Copyright (C) 2008-2023 Free Software Foundation, Inc. 2 Copyright (C) 2008-2024 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 e9454af3..8333c0eb 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-2023 Free Software 3 Copyright (C) 1990, 1998, 2000-2001, 2003-2006, 2009-2024 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 e72f7130..393ec1b4 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-2023 Free Software 3 Copyright (C) 1990, 1998, 2000-2001, 2003-2006, 2009-2024 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 f98e83bd..33935ba9 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-2023 Free Software Foundation, 3 Copyright (C) 1998, 2001, 2003-2006, 2009-2024 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
@@ -19,6 +19,12 @@
19#ifndef DIRNAME_H_ 19#ifndef DIRNAME_H_
20# define DIRNAME_H_ 1 20# define DIRNAME_H_ 1
21 21
22/* This file uses _GL_ATTRIBUTE_MALLOC, _GL_ATTRIBUTE_PURE,
23 _GL_ATTRIBUTE_RETURNS_NONNULL. */
24#if !_GL_CONFIG_H_INCLUDED
25 #error "Please include config.h first."
26#endif
27
22# include <stdlib.h> 28# include <stdlib.h>
23# include "filename.h" 29# include "filename.h"
24# include "basename-lgpl.h" 30# include "basename-lgpl.h"
diff --git a/gl/dup2.c b/gl/dup2.c
index 7d197ca3..916e113d 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 1999, 2004-2007, 2009-2024 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 91559109..8940e81b 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-2023 Free Software Foundation, Inc. 2 Copyright 2021-2024 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 3dda9c26..aa658e62 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2008-2024 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/error.c b/gl/error.c
index 6875f134..c53dfeb6 100644
--- a/gl/error.c
+++ b/gl/error.c
@@ -1,5 +1,5 @@
1/* Error handler for noninteractive utilities 1/* Error handler for noninteractive utilities
2 Copyright (C) 1990-1998, 2000-2007, 2009-2023 Free Software Foundation, Inc. 2 Copyright (C) 1990-1998, 2000-2007, 2009-2024 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 This file is free software: you can redistribute it and/or modify
@@ -19,9 +19,10 @@
19 19
20#if !_LIBC 20#if !_LIBC
21# include <config.h> 21# include <config.h>
22# define _GL_NO_INLINE_ERROR
22#endif 23#endif
23 24
24#include "error.h" 25#include <error.h>
25 26
26#include <stdarg.h> 27#include <stdarg.h>
27#include <stdio.h> 28#include <stdio.h>
@@ -42,8 +43,6 @@
42# define USE_UNLOCKED_IO 0 43# define USE_UNLOCKED_IO 0
43# define _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(a, b) 44# define _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(a, b)
44# define _GL_ARG_NONNULL(a) 45# define _GL_ARG_NONNULL(a)
45#else
46# include "getprogname.h"
47#endif 46#endif
48 47
49#if USE_UNLOCKED_IO 48#if USE_UNLOCKED_IO
diff --git a/gl/error.h b/gl/error.h
deleted file mode 100644
index a240526a..00000000
--- a/gl/error.h
+++ /dev/null
@@ -1,66 +0,0 @@
1/* Declaration for error-reporting function
2 Copyright (C) 1995-1997, 2003, 2006, 2008-2023 Free Software Foundation,
3 Inc.
4 This file is part of the GNU C Library.
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 _ERROR_H
20#define _ERROR_H 1
21
22/* Get _GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, _GL_ATTRIBUTE_SPEC_PRINTF_SYSTEM. */
23#include <stdio.h>
24
25#ifdef __cplusplus
26extern "C" {
27#endif
28
29/* Print a message with 'fprintf (stderr, FORMAT, ...)';
30 if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM).
31 If STATUS is nonzero, terminate the program with 'exit (STATUS)'. */
32
33extern void error (int __status, int __errnum, const char *__format, ...)
34#if GNULIB_VFPRINTF_POSIX
35 _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 3, 4))
36#else
37 _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_SYSTEM, 3, 4))
38#endif
39 ;
40
41extern void error_at_line (int __status, int __errnum, const char *__fname,
42 unsigned int __lineno, const char *__format, ...)
43#if GNULIB_VFPRINTF_POSIX
44 _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 5, 6))
45#else
46 _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_SYSTEM, 5, 6))
47#endif
48 ;
49
50/* If NULL, error will flush stdout, then print on stderr the program
51 name, a colon and a space. Otherwise, error will call this
52 function without parameters instead. */
53extern void (*error_print_progname) (void);
54
55/* This variable is incremented each time 'error' is called. */
56extern unsigned int error_message_count;
57
58/* Sometimes we want to have at most one error per line. This
59 variable controls whether this mode is selected or not. */
60extern int error_one_per_line;
61
62#ifdef __cplusplus
63}
64#endif
65
66#endif /* error.h */
diff --git a/gl/error.in.h b/gl/error.in.h
new file mode 100644
index 00000000..51f8cafd
--- /dev/null
+++ b/gl/error.in.h
@@ -0,0 +1,216 @@
1/* Declarations for error-reporting functions.
2 Copyright (C) 1995-1997, 2003, 2006, 2008-2024 Free Software Foundation,
3 Inc.
4 This file is part of the GNU C Library.
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 _@GUARD_PREFIX@_ERROR_H
20
21/* No @PRAGMA_SYSTEM_HEADER@ here, because it would prevent
22 -Wimplicit-fallthrough warnings for missing FALLTHROUGH after error(...)
23 or error_at_line(...) invocations. */
24
25/* The include_next requires a split double-inclusion guard. */
26#if @HAVE_ERROR_H@
27# @INCLUDE_NEXT@ @NEXT_ERROR_H@
28#endif
29
30#ifndef _@GUARD_PREFIX@_ERROR_H
31#define _@GUARD_PREFIX@_ERROR_H
32
33/* This file uses _GL_ATTRIBUTE_ALWAYS_INLINE, _GL_ATTRIBUTE_FORMAT,
34 _GL_ATTRIBUTE_MAYBE_UNUSED. */
35#if !_GL_CONFIG_H_INCLUDED
36 #error "Please include config.h first."
37#endif
38
39/* Get 'unreachable'. */
40#include <stddef.h>
41
42/* Get _GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, _GL_ATTRIBUTE_SPEC_PRINTF_SYSTEM. */
43#include <stdio.h>
44
45/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
46
47#if GNULIB_VFPRINTF_POSIX
48# define _GL_ATTRIBUTE_SPEC_PRINTF_ERROR _GL_ATTRIBUTE_SPEC_PRINTF_STANDARD
49#else
50# define _GL_ATTRIBUTE_SPEC_PRINTF_ERROR _GL_ATTRIBUTE_SPEC_PRINTF_SYSTEM
51#endif
52
53/* Helper macro for supporting the compiler's control flow analysis better.
54 It evaluates its arguments only once.
55 Test case: Compile copy-file.c with "gcc -Wimplicit-fallthrough". */
56#if defined __GNUC__ || defined __clang__
57/* Use 'unreachable' to tell the compiler when the function call does not
58 return. */
59# define __gl_error_call1(function, status, ...) \
60 ((function) (status, __VA_ARGS__), \
61 (status) != 0 ? unreachable () : (void) 0)
62/* 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
64 statement in order to evaluate STATUS only once.
65 If STATUS is a constant, we don't use a compound statement, because that
66 would trigger a -Wimplicit-fallthrough warning even when STATUS is != 0,
67 when not optimizing. This causes STATUS to be evaluated twice, but
68 that's OK since it does not have side effects. */
69# define __gl_error_call(function, status, ...) \
70 (__builtin_constant_p (status) \
71 ? __gl_error_call1 (function, status, __VA_ARGS__) \
72 : __extension__ \
73 ({ \
74 int const __errstatus = status; \
75 __gl_error_call1 (function, __errstatus, __VA_ARGS__); \
76 }))
77#else
78# define __gl_error_call(function, status, ...) \
79 (function) (status, __VA_ARGS__)
80#endif
81
82#ifdef __cplusplus
83extern "C" {
84#endif
85
86/* Print a message with 'fprintf (stderr, FORMAT, ...)';
87 if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM).
88 If STATUS is nonzero, terminate the program with 'exit (STATUS)'. */
89#if @REPLACE_ERROR@
90# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
91# undef error
92# define error rpl_error
93# endif
94_GL_FUNCDECL_RPL (error, void,
95 (int __status, int __errnum, const char *__format, ...)
96 _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 3, 4)));
97_GL_CXXALIAS_RPL (error, void,
98 (int __status, int __errnum, const char *__format, ...));
99# ifndef _GL_NO_INLINE_ERROR
100# undef error
101# define error(status, ...) \
102 __gl_error_call (rpl_error, status, __VA_ARGS__)
103# endif
104#else
105# if ! @HAVE_ERROR@
106_GL_FUNCDECL_SYS (error, void,
107 (int __status, int __errnum, const char *__format, ...)
108 _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 3, 4)));
109# endif
110_GL_CXXALIAS_SYS (error, void,
111 (int __status, int __errnum, const char *__format, ...));
112# ifndef _GL_NO_INLINE_ERROR
113# ifdef error
114/* Only gcc ≥ 4.7 has __builtin_va_arg_pack. */
115# if _GL_GNUC_PREREQ (4, 7)
116# pragma GCC diagnostic push
117# pragma GCC diagnostic ignored "-Wattributes"
118_GL_ATTRIBUTE_MAYBE_UNUSED
119static void
120_GL_ATTRIBUTE_ALWAYS_INLINE
121_GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 3, 4))
122_gl_inline_error (int __status, int __errnum, const char *__format, ...)
123{
124 return error (__status, __errnum, __format, __builtin_va_arg_pack ());
125}
126# pragma GCC diagnostic pop
127# undef error
128# define error(status, ...) \
129 __gl_error_call (_gl_inline_error, status, __VA_ARGS__)
130# endif
131# else
132# define error(status, ...) \
133 __gl_error_call (error, status, __VA_ARGS__)
134# endif
135# endif
136#endif
137#if __GLIBC__ >= 2
138_GL_CXXALIASWARN (error);
139#endif
140
141/* Likewise. If FILENAME is non-NULL, include FILENAME:LINENO: in the
142 message. */
143#if @REPLACE_ERROR_AT_LINE@
144# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
145# undef error_at_line
146# define error_at_line rpl_error_at_line
147# endif
148_GL_FUNCDECL_RPL (error_at_line, void,
149 (int __status, int __errnum, const char *__filename,
150 unsigned int __lineno, const char *__format, ...)
151 _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 5, 6)));
152_GL_CXXALIAS_RPL (error_at_line, void,
153 (int __status, int __errnum, const char *__filename,
154 unsigned int __lineno, const char *__format, ...));
155# ifndef _GL_NO_INLINE_ERROR
156# undef error_at_line
157# define error_at_line(status, ...) \
158 __gl_error_call (rpl_error_at_line, status, __VA_ARGS__)
159# endif
160#else
161# if ! @HAVE_ERROR_AT_LINE@
162_GL_FUNCDECL_SYS (error_at_line, void,
163 (int __status, int __errnum, const char *__filename,
164 unsigned int __lineno, const char *__format, ...)
165 _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 5, 6)));
166# endif
167_GL_CXXALIAS_SYS (error_at_line, void,
168 (int __status, int __errnum, const char *__filename,
169 unsigned int __lineno, const char *__format, ...));
170# ifndef _GL_NO_INLINE_ERROR
171# ifdef error_at_line
172/* Only gcc ≥ 4.7 has __builtin_va_arg_pack. */
173# if _GL_GNUC_PREREQ (4, 7)
174# pragma GCC diagnostic push
175# pragma GCC diagnostic ignored "-Wattributes"
176_GL_ATTRIBUTE_MAYBE_UNUSED
177static void
178_GL_ATTRIBUTE_ALWAYS_INLINE
179_GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_ERROR, 5, 6))
180_gl_inline_error_at_line (int __status, int __errnum, const char *__filename,
181 unsigned int __lineno, const char *__format, ...)
182{
183 return error_at_line (__status, __errnum, __filename, __lineno, __format,
184 __builtin_va_arg_pack ());
185}
186# pragma GCC diagnostic pop
187# undef error_at_line
188# define error_at_line(status, ...) \
189 __gl_error_call (_gl_inline_error_at_line, status, __VA_ARGS__)
190# endif
191# else
192# define error_at_line(status, ...) \
193 __gl_error_call (error_at_line, status, __VA_ARGS__)
194# endif
195# endif
196#endif
197_GL_CXXALIASWARN (error_at_line);
198
199/* If NULL, error will flush stdout, then print on stderr the program
200 name, a colon and a space. Otherwise, error will call this
201 function without parameters instead. */
202extern void (*error_print_progname) (void);
203
204/* This variable is incremented each time 'error' is called. */
205extern unsigned int error_message_count;
206
207/* Sometimes we want to have at most one error per line. This
208 variable controls whether this mode is selected or not. */
209extern int error_one_per_line;
210
211#ifdef __cplusplus
212}
213#endif
214
215#endif /* _@GUARD_PREFIX@_ERROR_H */
216#endif /* _@GUARD_PREFIX@_ERROR_H */
diff --git a/gl/exitfail.c b/gl/exitfail.c
index d67a130c..8a5962e8 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2002-2003, 2005-2007, 2009-2024 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 85a6af64..fa264b5c 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2002, 2009-2024 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,4 +15,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 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#ifdef __cplusplus
19extern "C" {
20#endif
21
22
18extern int volatile exit_failure; 23extern int volatile exit_failure;
24
25
26#ifdef __cplusplus
27}
28#endif
diff --git a/gl/fcntl.c b/gl/fcntl.c
index e2208008..7cd3a0f9 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2009-2024 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.in.h b/gl/fcntl.in.h
index e034eaf9..eea3b954 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2006-2024 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
@@ -74,6 +74,11 @@
74#ifndef _@GUARD_PREFIX@_FCNTL_H 74#ifndef _@GUARD_PREFIX@_FCNTL_H
75#define _@GUARD_PREFIX@_FCNTL_H 75#define _@GUARD_PREFIX@_FCNTL_H
76 76
77/* This file uses GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */
78#if !_GL_CONFIG_H_INCLUDED
79 #error "Please include config.h first."
80#endif
81
77#ifndef __GLIBC__ /* Avoid namespace pollution on glibc systems. */ 82#ifndef __GLIBC__ /* Avoid namespace pollution on glibc systems. */
78# include <unistd.h> 83# include <unistd.h>
79#endif 84#endif
diff --git a/gl/fd-hook.c b/gl/fd-hook.c
index 36261150..75bbe49c 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2009-2024 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 6bf3c24d..2150460b 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2009-2024 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 f3689b3e..36cc14d1 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2007-2024 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/filename.h b/gl/filename.h
index a2400a9d..4f0f0fbc 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2001-2024 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 e7531e46..104f477f 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2009-2024 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 f81ff33d..a9ea40b0 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2011-2024 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/float.in.h b/gl/float.in.h
index bf2c502c..73e8d406 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2007-2024 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/floor.c b/gl/floor.c
index 238f4879..392f2044 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2010-2024 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 e465c180..f9785d0c 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2009-2024 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 f8469a0b..d3b57a98 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2007-2024 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,9 +33,13 @@ orig_fopen (const char *filename, const char *mode)
33} 33}
34 34
35/* Specification. */ 35/* Specification. */
36#ifdef __osf__
36/* Write "stdio.h" here, not <stdio.h>, otherwise OSF/1 5.1 DTK cc eliminates 37/* Write "stdio.h" here, not <stdio.h>, otherwise OSF/1 5.1 DTK cc eliminates
37 this include because of the preliminary #include <stdio.h> above. */ 38 this include because of the preliminary #include <stdio.h> above. */
38#include "stdio.h" 39# include "stdio.h"
40#else
41# include <stdio.h>
42#endif
39 43
40#include <errno.h> 44#include <errno.h>
41#include <fcntl.h> 45#include <fcntl.h>
@@ -225,5 +229,9 @@ rpl_fopen (const char *filename, const char *mode)
225 } 229 }
226#endif 230#endif
227 231
232 /* open_direction is sometimes used, sometimes unused.
233 Silence gcc's warning about this situation. */
234 (void) open_direction;
235
228 return orig_fopen (filename, mode); 236 return orig_fopen (filename, mode);
229} 237}
diff --git a/gl/fpurge.c b/gl/fpurge.c
index 0dcb2b79..52a3dcef 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2007-2024 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/freading.c b/gl/freading.c
index b9377cb0..c80d9aa8 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2007-2024 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/freading.h b/gl/freading.h
index 27b3abbc..943354f5 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2007-2024 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
@@ -14,6 +14,11 @@
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/* This file uses _GL_ATTRIBUTE_PURE, HAVE___FREADING, HAVE_STDIO_EXT_H. */
18#if !_GL_CONFIG_H_INCLUDED
19 #error "Please include config.h first."
20#endif
21
17#include <stdio.h> 22#include <stdio.h>
18 23
19/* Return true if the stream STREAM is opened read-only, or if the 24/* Return true if the stream STREAM is opened read-only, or if the
diff --git a/gl/free.c b/gl/free.c
index 372a6b0f..2f0c40ba 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2003, 2006, 2009-2024 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 9764375a..cebc1749 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2009-2024 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 89a70874..2c3b053a 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2007-2024 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/fstat.c b/gl/fstat.c
index 6a235002..205d5aab 100644
--- a/gl/fstat.c
+++ b/gl/fstat.c
@@ -1,5 +1,5 @@
1/* fstat() replacement. 1/* fstat() replacement.
2 Copyright (C) 2011-2023 Free Software Foundation, Inc. 2 Copyright (C) 2011-2024 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 f6f4b1c3..97d0eef7 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-2023 Free Software 3 Copyright (C) 1991-1992, 1996, 1998-1999, 2002-2006, 2009-2024 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 9630b04e..da878590 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-2023 Free Software 3 Copyright (C) 1991-1992, 1997, 2003-2006, 2009-2024 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
@@ -19,9 +19,14 @@
19/* Space usage statistics for a file system. Blocks are 512-byte. */ 19/* Space usage statistics for a file system. Blocks are 512-byte. */
20 20
21#if !defined FSUSAGE_H_ 21#if !defined FSUSAGE_H_
22# define FSUSAGE_H_ 22#define FSUSAGE_H_
23
24#include <stdint.h>
25
26#ifdef __cplusplus
27extern "C" {
28#endif
23 29
24# include <stdint.h>
25 30
26struct fs_usage 31struct fs_usage
27{ 32{
@@ -36,4 +41,9 @@ struct fs_usage
36 41
37int get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp); 42int get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp);
38 43
44
45#ifdef __cplusplus
46}
47#endif
48
39#endif 49#endif
diff --git a/gl/ftell.c b/gl/ftell.c
index ce2bd542..21cab439 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2007-2024 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 14184e5e..64119aab 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2009-2024 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/gai_strerror.c b/gl/gai_strerror.c
index 3436c07a..37092e29 100644
--- a/gl/gai_strerror.c
+++ b/gl/gai_strerror.c
@@ -1,4 +1,4 @@
1/* Copyright (C) 1997, 2001-2002, 2004-2006, 2008-2023 Free Software 1/* Copyright (C) 1997, 2001-2002, 2004-2006, 2008-2024 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.
diff --git a/gl/getaddrinfo.c b/gl/getaddrinfo.c
index 6586ee58..bf5d61f3 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 1997, 2001-2002, 2004-2024 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
diff --git a/gl/getdelim.c b/gl/getdelim.c
index 79ec3dd1..58063b15 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-2023 Free Software 2 Copyright (C) 1994, 1996-1998, 2001, 2003, 2005-2024 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
@@ -30,10 +30,6 @@
30#include <stdlib.h> 30#include <stdlib.h>
31#include <errno.h> 31#include <errno.h>
32 32
33#ifndef SSIZE_MAX
34# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
35#endif
36
37#if USE_UNLOCKED_IO 33#if USE_UNLOCKED_IO
38# include "unlocked-io.h" 34# include "unlocked-io.h"
39# define getc_maybe_unlocked(fp) getc(fp) 35# define getc_maybe_unlocked(fp) getc(fp)
diff --git a/gl/getdtablesize.c b/gl/getdtablesize.c
index ac2d1753..762c100b 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2008-2024 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 0c616c34..c075b6df 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 1992, 2003, 2006, 2008-2024 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 85f16ab8..2d03b646 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2005-2007, 2009-2024 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 59b53e79..c940e4c7 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-2023 Free Software 3 Copyright (C) 1985-1989, 1991-1995, 1997, 1999-2000, 2003-2024 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.
diff --git a/gl/getopt-cdefs.in.h b/gl/getopt-cdefs.in.h
index e76c78cb..a1d304d4 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 1989-2024 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.
@@ -57,7 +57,11 @@
57 57
58#ifndef __THROW 58#ifndef __THROW
59# if defined __cplusplus && (__GNUC_PREREQ (2,8) || __clang_major__ >= 4) 59# if defined __cplusplus && (__GNUC_PREREQ (2,8) || __clang_major__ >= 4)
60# define __THROW throw () 60# if __cplusplus >= 201103L
61# define __THROW noexcept (true)
62# else
63# define __THROW throw ()
64# endif
61# else 65# else
62# define __THROW 66# define __THROW
63# endif 67# endif
diff --git a/gl/getopt-core.h b/gl/getopt-core.h
index c5dd4936..12d09a25 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 1989-2024 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 d37c2932..e4b499d4 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 1989-2024 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 3a2fde5a..78b7816a 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 1989-2024 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.
@@ -47,7 +47,7 @@
47# define optind __GETOPT_ID (optind) 47# define optind __GETOPT_ID (optind)
48# define optopt __GETOPT_ID (optopt) 48# define optopt __GETOPT_ID (optopt)
49 49
50/* Work around a a problem on macOS, which declares getopt with a 50/* Work around a problem on macOS, which declares getopt with a
51 trailing __DARWIN_ALIAS(getopt) that would expand to something like 51 trailing __DARWIN_ALIAS(getopt) that would expand to something like
52 __asm("_" "rpl_getopt" "$UNIX2003") were it not for the following 52 __asm("_" "rpl_getopt" "$UNIX2003") were it not for the following
53 hack to suppress the macOS declaration <https://bugs.gnu.org/40205>. */ 53 hack to suppress the macOS declaration <https://bugs.gnu.org/40205>. */
diff --git a/gl/getopt-pfx-ext.h b/gl/getopt-pfx-ext.h
index 8578d725..f001c11e 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 1989-2024 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.
diff --git a/gl/getopt.c b/gl/getopt.c
index 1e2441c4..f66f119e 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 1987-2024 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
@@ -21,7 +21,7 @@
21# include <config.h> 21# include <config.h>
22#endif 22#endif
23 23
24#include "getopt.h" 24#include <getopt.h>
25 25
26#include <stdio.h> 26#include <stdio.h>
27#include <stdlib.h> 27#include <stdlib.h>
@@ -223,8 +223,9 @@ process_long_option (int argc, char **argv, const char *optstring,
223 { 223 {
224 /* Didn't find an exact match, so look for abbreviations. */ 224 /* Didn't find an exact match, so look for abbreviations. */
225 unsigned char *ambig_set = NULL; 225 unsigned char *ambig_set = NULL;
226 int ambig_malloced = 0; 226 /* Use simpler fallback diagnostic if ambig_set == &ambig_fallback. */
227 int ambig_fallback = 0; 227 unsigned char ambig_fallback;
228 void *ambig_malloced = NULL;
228 int indfound = -1; 229 int indfound = -1;
229 230
230 for (p = longopts, option_index = 0; p->name; p++, option_index++) 231 for (p = longopts, option_index = 0; p->name; p++, option_index++)
@@ -242,39 +243,42 @@ process_long_option (int argc, char **argv, const char *optstring,
242 || pfound->val != p->val) 243 || pfound->val != p->val)
243 { 244 {
244 /* Second or later nonexact match found. */ 245 /* Second or later nonexact match found. */
245 if (!ambig_fallback) 246 if (ambig_set != &ambig_fallback)
246 { 247 {
247 if (!print_errors) 248 if (!print_errors)
248 /* Don't waste effort tracking the ambig set if 249 /* Don't waste effort tracking the ambig set if
249 we're not going to print it anyway. */ 250 we're not going to print it anyway. */
250 ambig_fallback = 1; 251 ambig_set = &ambig_fallback;
251 else if (!ambig_set) 252 else if (!ambig_set)
252 { 253 {
253 if (__libc_use_alloca (n_options)) 254 if (__libc_use_alloca (n_options))
254 ambig_set = alloca (n_options); 255 ambig_set = alloca (n_options);
255 else if ((ambig_set = malloc (n_options)) == NULL)
256 /* Fall back to simpler error message. */
257 ambig_fallback = 1;
258 else 256 else
259 ambig_malloced = 1; 257 {
258 ambig_malloced = malloc (n_options);
259 /* Fall back to simpler diagnostic if
260 memory allocation fails. */
261 ambig_set = (ambig_malloced ? ambig_malloced
262 : &ambig_fallback);
263 }
260 264
261 if (ambig_set) 265 if (ambig_set != &ambig_fallback)
262 { 266 {
263 memset (ambig_set, 0, n_options); 267 memset (ambig_set, 0, n_options);
264 ambig_set[indfound] = 1; 268 ambig_set[indfound] = 1;
265 } 269 }
266 } 270 }
267 if (ambig_set) 271 if (ambig_set && ambig_set != &ambig_fallback)
268 ambig_set[option_index] = 1; 272 ambig_set[option_index] = 1;
269 } 273 }
270 } 274 }
271 } 275 }
272 276
273 if (ambig_set || ambig_fallback) 277 if (ambig_set)
274 { 278 {
275 if (print_errors) 279 if (print_errors)
276 { 280 {
277 if (ambig_fallback) 281 if (ambig_set == &ambig_fallback)
278 fprintf (stderr, _("%s: option '%s%s' is ambiguous\n"), 282 fprintf (stderr, _("%s: option '%s%s' is ambiguous\n"),
279 argv[0], prefix, d->__nextchar); 283 argv[0], prefix, d->__nextchar);
280 else 284 else
@@ -296,8 +300,7 @@ process_long_option (int argc, char **argv, const char *optstring,
296 funlockfile (stderr); 300 funlockfile (stderr);
297 } 301 }
298 } 302 }
299 if (ambig_malloced) 303 free (ambig_malloced);
300 free (ambig_set);
301 d->__nextchar += strlen (d->__nextchar); 304 d->__nextchar += strlen (d->__nextchar);
302 d->optind++; 305 d->optind++;
303 d->optopt = 0; 306 d->optopt = 0;
diff --git a/gl/getopt.in.h b/gl/getopt.in.h
index 0867d365..c2411a75 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 1989-2024 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
diff --git a/gl/getopt1.c b/gl/getopt1.c
index 49323aa8..c42d29f8 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 1987-2024 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
@@ -21,7 +21,7 @@
21# include <config.h> 21# include <config.h>
22#endif 22#endif
23 23
24#include "getopt.h" 24#include <getopt.h>
25#include "getopt_int.h" 25#include "getopt_int.h"
26 26
27int 27int
diff --git a/gl/getopt_int.h b/gl/getopt_int.h
index 4d9e24be..c00c0b69 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 1989-2024 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 32c96043..392a9a2f 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2016-2024 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
@@ -16,11 +16,10 @@
16 16
17#include <config.h> 17#include <config.h>
18 18
19/* Specification. */ 19/* Specification. Also get __argv declaration. */
20#include "getprogname.h" 20#include <stdlib.h>
21 21
22#include <errno.h> /* get program_invocation_name declaration */ 22#include <errno.h> /* get program_invocation_name declaration */
23#include <stdlib.h> /* get __argv declaration */
24 23
25#ifdef _AIX 24#ifdef _AIX
26# include <unistd.h> 25# include <unistd.h>
@@ -53,13 +52,12 @@
53 52
54#if defined __SCO_VERSION__ || defined __sysv5__ 53#if defined __SCO_VERSION__ || defined __sysv5__
55# include <fcntl.h> 54# include <fcntl.h>
56# include <stdlib.h>
57# include <string.h> 55# include <string.h>
58#endif 56#endif
59 57
60#include "basename-lgpl.h" 58#include "basename-lgpl.h"
61 59
62#ifndef HAVE_GETPROGNAME /* not Mac OS X, FreeBSD, NetBSD, OpenBSD >= 5.4, Cygwin */ 60#ifndef HAVE_GETPROGNAME /* not Mac OS X, FreeBSD, NetBSD, OpenBSD >= 5.4, Solaris >= 11, Cygwin, Android API level >= 21 */
63char const * 61char const *
64getprogname (void) 62getprogname (void)
65{ 63{
@@ -214,7 +212,19 @@ getprogname (void)
214 { 212 {
215 char *s = strdup (last_component (buf.ps_pathptr)); 213 char *s = strdup (last_component (buf.ps_pathptr));
216 if (s) 214 if (s)
217 p = s; 215 {
216# if defined __XPLINK__ && __CHARSET_LIB == 1
217 /* The compiler option -qascii is in use.
218 https://makingdeveloperslivesbetter.wordpress.com/2022/01/07/is-z-os-ascii-or-ebcdic-yes/
219 https://www.ibm.com/docs/en/zos/2.5.0?topic=features-macros-related-compiler-option-settings
220 So, convert the result from EBCDIC to ASCII.
221 https://www.ibm.com/docs/en/zos/2.5.0?topic=functions-e2a-s-convert-string-from-ebcdic-ascii */
222 if (__e2a_s (s) == (size_t)-1)
223 free (s);
224 else
225# endif
226 p = s;
227 }
218 break; 228 break;
219 } 229 }
220 } 230 }
diff --git a/gl/getprogname.h b/gl/getprogname.h
index 4b9126f9..bee1c1a2 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2016-2024 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
@@ -19,22 +19,8 @@
19 19
20#include <stdlib.h> 20#include <stdlib.h>
21 21
22#ifdef __cplusplus 22#if __GNUC__ || (__clang_major__ >= 4)
23extern "C" { 23# warning "The include file getprogname.h is deprecated. Use <stdlib.h> instead."
24#endif
25
26/* Return the base name of the executing program.
27 On native Windows this will usually end in ".exe" or ".EXE". */
28#ifndef HAVE_GETPROGNAME
29extern char const *getprogname (void)
30# ifdef HAVE_DECL_PROGRAM_INVOCATION_NAME
31 _GL_ATTRIBUTE_PURE
32# endif
33 ;
34#endif
35
36#ifdef __cplusplus
37}
38#endif 24#endif
39 25
40#endif 26#endif
diff --git a/gl/gettext.h b/gl/gettext.h
index d0462c47..39d5ae4d 100644
--- a/gl/gettext.h
+++ b/gl/gettext.h
@@ -1,5 +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-2023 Free Software 2 Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009-2024 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/gl_openssl.h b/gl/gl_openssl.h
index f63c386e..06864732 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2013-2024 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,13 +17,15 @@
17 17
18/* Written by Pádraig Brady */ 18/* Written by Pádraig Brady */
19 19
20/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE. */
21#if !_GL_CONFIG_H_INCLUDED
22 #error "Please include config.h first."
23#endif
24
20#ifndef GL_OPENSSL_NAME 25#ifndef GL_OPENSSL_NAME
21# error "Please define GL_OPENSSL_NAME to 1,5,256 etc." 26# error "Please define GL_OPENSSL_NAME to 1,5,256 etc."
22#endif 27#endif
23 28
24#ifndef _GL_INLINE_HEADER_BEGIN
25# error "Please include config.h first."
26#endif
27_GL_INLINE_HEADER_BEGIN 29_GL_INLINE_HEADER_BEGIN
28#ifndef GL_OPENSSL_INLINE 30#ifndef GL_OPENSSL_INLINE
29# define GL_OPENSSL_INLINE _GL_INLINE 31# define GL_OPENSSL_INLINE _GL_INLINE
diff --git a/gl/glthread/lock.c b/gl/glthread/lock.c
index 82fb7553..6661ad6a 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2005-2024 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/glthread/lock.h b/gl/glthread/lock.h
index ae3ee2d6..2d5cb320 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2005-2024 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
@@ -77,6 +77,14 @@
77#ifndef _LOCK_H 77#ifndef _LOCK_H
78#define _LOCK_H 78#define _LOCK_H
79 79
80/* This file uses HAVE_THREADS_H, HAVE_PTHREAD_RWLOCK,
81 HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER,
82 PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
83 HAVE_PTHREAD_MUTEX_RECURSIVE. */
84#if !_GL_CONFIG_H_INCLUDED
85 #error "Please include config.h first."
86#endif
87
80#include <errno.h> 88#include <errno.h>
81#include <stdlib.h> 89#include <stdlib.h>
82 90
diff --git a/gl/glthread/threadlib.c b/gl/glthread/threadlib.c
index 5ecf827f..7a776768 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2005-2024 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 0a28552e..653c5809 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-2023 Free Software 3 Copyright (C) 1997-1999, 2002-2004, 2006-2007, 2009-2024 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
@@ -21,6 +21,7 @@
21#include "hard-locale.h" 21#include "hard-locale.h"
22 22
23#include <locale.h> 23#include <locale.h>
24#include <stdlib.h>
24#include <string.h> 25#include <string.h>
25 26
26bool 27bool
@@ -31,5 +32,16 @@ hard_locale (int category)
31 if (setlocale_null_r (category, locale, sizeof (locale))) 32 if (setlocale_null_r (category, locale, sizeof (locale)))
32 return false; 33 return false;
33 34
34 return !(strcmp (locale, "C") == 0 || strcmp (locale, "POSIX") == 0); 35 if (!(strcmp (locale, "C") == 0 || strcmp (locale, "POSIX") == 0))
36 return true;
37
38#if defined __ANDROID__
39 /* On Android 5.0 or newer, it is possible to set a locale that has the same
40 name as the "C" locale but in fact uses UTF-8 encoding. Cf. test case 2 in
41 <https://lists.gnu.org/archive/html/bug-gnulib/2023-01/msg00141.html>. */
42 if (MB_CUR_MAX > 1)
43 return true;
44#endif
45
46 return false;
35} 47}
diff --git a/gl/hard-locale.h b/gl/hard-locale.h
index 880c9e85..5d40e522 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 1999, 2003-2004, 2009-2024 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
@@ -16,11 +16,23 @@
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 HARD_LOCALE_H_ 18#ifndef HARD_LOCALE_H_
19# define HARD_LOCALE_H_ 1 19#define HARD_LOCALE_H_ 1
20
21#ifdef __cplusplus
22extern "C" {
23#endif
24
20 25
21/* Return true if the specified CATEGORY of the current locale is hard, i.e. 26/* Return true if the specified CATEGORY of the current locale is hard, i.e.
22 different from the C or POSIX locale that has a fixed behavior. 27 different from the C or POSIX locale that has a fixed behavior.
23 CATEGORY must be one of the LC_* values, but not LC_ALL. */ 28 CATEGORY must be one of the LC_* values, but not LC_ALL.
29 Note: This function uses the current global locale; it ignores the
30 per-thread locale. */
24extern bool hard_locale (int category); 31extern bool hard_locale (int category);
25 32
33
34#ifdef __cplusplus
35}
36#endif
37
26#endif /* HARD_LOCALE_H_ */ 38#endif /* HARD_LOCALE_H_ */
diff --git a/gl/ialloc.c b/gl/ialloc.c
index cd44d8ca..8564a15b 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-2023 Free Software Foundation, Inc. 3 Copyright 2021-2024 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 1d43faf3..2aa94ae7 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-2023 Free Software Foundation, Inc. 3 Copyright 2021-2024 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
@@ -18,15 +18,21 @@
18#ifndef IALLOC_H_ 18#ifndef IALLOC_H_
19#define IALLOC_H_ 19#define IALLOC_H_
20 20
21/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE, _GL_ATTRIBUTE_COLD,
22 _GL_ATTRIBUTE_MALLOC. */
23#if !_GL_CONFIG_H_INCLUDED
24 #error "Please include config.h first."
25#endif
26
21#include "idx.h" 27#include "idx.h"
22 28
23#include <errno.h> 29#include <errno.h>
24#include <stdint.h> 30#include <stdint.h>
25#include <stdlib.h> 31#include <stdlib.h>
26 32#if defined __CHERI_PURE_CAPABILITY__
27#ifndef _GL_INLINE_HEADER_BEGIN 33# include <cheri.h>
28 #error "Please include config.h first."
29#endif 34#endif
35
30_GL_INLINE_HEADER_BEGIN 36_GL_INLINE_HEADER_BEGIN
31#ifndef IALLOC_INLINE 37#ifndef IALLOC_INLINE
32# define IALLOC_INLINE _GL_INLINE 38# define IALLOC_INLINE _GL_INLINE
@@ -43,6 +49,9 @@ _gl_alloc_nomem (void)
43 return NULL; 49 return NULL;
44} 50}
45 51
52/* imalloc (size) is like malloc (size).
53 It returns a non-NULL pointer to size bytes of memory.
54 Upon failure, it returns NULL with errno set. */
46IALLOC_INLINE 55IALLOC_INLINE
47_GL_ATTRIBUTE_MALLOC /*_GL_ATTRIBUTE_DEALLOC_FREE*/ 56_GL_ATTRIBUTE_MALLOC /*_GL_ATTRIBUTE_DEALLOC_FREE*/
48void * 57void *
@@ -51,16 +60,32 @@ imalloc (idx_t s)
51 return s <= SIZE_MAX ? malloc (s) : _gl_alloc_nomem (); 60 return s <= SIZE_MAX ? malloc (s) : _gl_alloc_nomem ();
52} 61}
53 62
63/* irealloc (ptr, size) is like realloc (ptr, size).
64 It returns a non-NULL pointer to size bytes of memory.
65 Upon failure, it returns NULL with errno set. */
54IALLOC_INLINE 66IALLOC_INLINE
55/*_GL_ATTRIBUTE_DEALLOC_FREE*/ 67/*_GL_ATTRIBUTE_DEALLOC_FREE*/
56void * 68void *
57irealloc (void *p, idx_t s) 69irealloc (void *p, idx_t s)
58{ 70{
59 /* Work around GNU realloc glitch by treating a zero size as if it 71 if (s <= SIZE_MAX)
60 were 1, so that returning NULL is equivalent to failing. */ 72 {
61 return s <= SIZE_MAX ? realloc (p, s | !s) : _gl_alloc_nomem (); 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 ();
62} 84}
63 85
86/* icalloc (num, size) is like calloc (num, size).
87 It returns a non-NULL pointer to num * size bytes of memory.
88 Upon failure, it returns NULL with errno set. */
64IALLOC_INLINE 89IALLOC_INLINE
65_GL_ATTRIBUTE_MALLOC /*_GL_ATTRIBUTE_DEALLOC_FREE*/ 90_GL_ATTRIBUTE_MALLOC /*_GL_ATTRIBUTE_DEALLOC_FREE*/
66void * 91void *
@@ -81,20 +106,35 @@ icalloc (idx_t n, idx_t s)
81 return calloc (n, s); 106 return calloc (n, s);
82} 107}
83 108
109/* ireallocarray (ptr, num, size) is like reallocarray (ptr, num, size).
110 It returns a non-NULL pointer to num * size bytes of memory.
111 Upon failure, it returns NULL with errno set. */
84IALLOC_INLINE void * 112IALLOC_INLINE void *
85ireallocarray (void *p, idx_t n, idx_t s) 113ireallocarray (void *p, idx_t n, idx_t s)
86{ 114{
87 /* Work around GNU reallocarray glitch by treating a zero size as if 115 if (n <= SIZE_MAX && s <= SIZE_MAX)
88 it were 1, so that returning NULL is equivalent to failing. */ 116 {
89 if (n == 0 || s == 0) 117 /* Work around GNU reallocarray glitch by treating a zero size as if
90 n = s = 1; 118 it were 1, so that returning NULL is equivalent to failing. */
91 return (n <= SIZE_MAX && s <= SIZE_MAX 119 size_t nx = n;
92 ? reallocarray (p, n, s) 120 size_t sx = s;
93 : _gl_alloc_nomem ()); 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 ();
94} 132}
95 133
96#ifdef __cplusplus 134#ifdef __cplusplus
97} 135}
98#endif 136#endif
99 137
138_GL_INLINE_HEADER_END
139
100#endif 140#endif
diff --git a/gl/idpriv-droptemp.c b/gl/idpriv-droptemp.c
index 2a85431a..eb882dea 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2009-2024 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/idpriv.h b/gl/idpriv.h
index 99f87c08..a3ae5926 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2009-2024 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 23020b7e..43793f2d 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2020-2024 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
@@ -111,6 +111,11 @@
111 help producing good code and good warnings. The type 'idx_t' could 111 help producing good code and good warnings. The type 'idx_t' could
112 then be typedef'ed to a range type that is signed after promotion. */ 112 then be typedef'ed to a range type that is signed after promotion. */
113 113
114#ifdef __cplusplus
115extern "C" {
116#endif
117
118
114/* In the future, idx_t could be typedef'ed to a signed range type. 119/* In the future, idx_t could be typedef'ed to a signed range type.
115 The clang "extended integer types", supported in Clang 11 or newer 120 The clang "extended integer types", supported in Clang 11 or newer
116 <https://clang.llvm.org/docs/LanguageExtensions.html#extended-integer-types>, 121 <https://clang.llvm.org/docs/LanguageExtensions.html#extended-integer-types>,
@@ -131,4 +136,9 @@ typedef ptrdiff_t idx_t;
131 Perhaps there should be another macro IDX_VALUE_BITS that does not 136 Perhaps there should be another macro IDX_VALUE_BITS that does not
132 count the sign bit and is therefore one less than PTRDIFF_WIDTH. */ 137 count the sign bit and is therefore one less than PTRDIFF_WIDTH. */
133 138
139
140#ifdef __cplusplus
141}
142#endif
143
134#endif /* _IDX_H */ 144#endif /* _IDX_H */
diff --git a/gl/inet_ntop.c b/gl/inet_ntop.c
index 9e2d412e..0a4ba20e 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2005-2006, 2008-2024 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/intprops-internal.h b/gl/intprops-internal.h
index 0467a9ca..b5ba8d7c 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2001-2024 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
@@ -20,6 +20,11 @@
20 20
21#include <limits.h> 21#include <limits.h>
22 22
23/* Pacify GCC 13.2 in some calls to _GL_EXPR_SIGNED. */
24#if defined __GNUC__ && 4 < __GNUC__ + (3 <= __GNUC_MINOR__)
25# pragma GCC diagnostic ignored "-Wtype-limits"
26#endif
27
23/* Return a value with the common real type of E and V and the value of V. 28/* Return a value with the common real type of E and V and the value of V.
24 Do not evaluate E. */ 29 Do not evaluate E. */
25#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v)) 30#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v))
@@ -164,7 +169,9 @@
164 /* Work around GCC bug 91450. */ 169 /* Work around GCC bug 91450. */
165# define _GL_INT_MULTIPLY_WRAPV(a, b, r) \ 170# define _GL_INT_MULTIPLY_WRAPV(a, b, r) \
166 ((!_GL_SIGNED_TYPE_OR_EXPR (*(r)) && _GL_EXPR_SIGNED (a) && _GL_EXPR_SIGNED (b) \ 171 ((!_GL_SIGNED_TYPE_OR_EXPR (*(r)) && _GL_EXPR_SIGNED (a) && _GL_EXPR_SIGNED (b) \
167 && _GL_INT_MULTIPLY_RANGE_OVERFLOW (a, b, 0, (__typeof__ (*(r))) -1)) \ 172 && _GL_INT_MULTIPLY_RANGE_OVERFLOW (a, b, \
173 (__typeof__ (*(r))) 0, \
174 (__typeof__ (*(r))) -1)) \
168 ? ((void) __builtin_mul_overflow (a, b, r), 1) \ 175 ? ((void) __builtin_mul_overflow (a, b, r), 1) \
169 : __builtin_mul_overflow (a, b, r)) 176 : __builtin_mul_overflow (a, b, r))
170# endif 177# endif
diff --git a/gl/intprops.h b/gl/intprops.h
index 44b5e60f..43734f34 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2001-2024 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
diff --git a/gl/inttypes.in.h b/gl/inttypes.in.h
index 50a2bbfc..b9ab8a4b 100644
--- a/gl/inttypes.in.h
+++ b/gl/inttypes.in.h
@@ -1,4 +1,4 @@
1/* Copyright (C) 2006-2023 Free Software Foundation, Inc. 1/* Copyright (C) 2006-2024 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
@@ -46,6 +46,11 @@
46#if ! defined INTTYPES_H && ! defined _GL_JUST_INCLUDE_SYSTEM_INTTYPES_H 46#if ! defined INTTYPES_H && ! defined _GL_JUST_INCLUDE_SYSTEM_INTTYPES_H
47#define INTTYPES_H 47#define INTTYPES_H
48 48
49/* This file uses GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */
50#if !_GL_CONFIG_H_INCLUDED
51 #error "Please include config.h first."
52#endif
53
49/* Include <stdint.h> or the gnulib replacement. 54/* Include <stdint.h> or the gnulib replacement.
50 But avoid namespace pollution on glibc systems. */ 55 But avoid namespace pollution on glibc systems. */
51#ifndef __GLIBC__ 56#ifndef __GLIBC__
@@ -903,8 +908,21 @@ extern "C" {
903#endif 908#endif
904 909
905#if @GNULIB_IMAXABS@ 910#if @GNULIB_IMAXABS@
906# if !@HAVE_DECL_IMAXABS@ 911# if @REPLACE_IMAXABS@
907extern intmax_t imaxabs (intmax_t); 912# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
913# undef imaxabs
914# define imaxabs rpl_imaxabs
915# endif
916_GL_FUNCDECL_RPL (imaxabs, intmax_t, (intmax_t x));
917_GL_CXXALIAS_RPL (imaxabs, intmax_t, (intmax_t x));
918# else
919# if !@HAVE_DECL_IMAXABS@
920_GL_FUNCDECL_SYS (imaxabs, intmax_t, (intmax_t x));
921# endif
922_GL_CXXALIAS_SYS (imaxabs, intmax_t, (intmax_t x));
923# endif
924# if __GLIBC__ >= 2
925_GL_CXXALIASWARN (imaxabs);
908# endif 926# endif
909#elif defined GNULIB_POSIXCHECK 927#elif defined GNULIB_POSIXCHECK
910# undef imaxabs 928# undef imaxabs
@@ -921,8 +939,21 @@ typedef struct { intmax_t quot; intmax_t rem; } imaxdiv_t;
921# define GNULIB_defined_imaxdiv_t 1 939# define GNULIB_defined_imaxdiv_t 1
922# endif 940# endif
923# endif 941# endif
924# if !@HAVE_DECL_IMAXDIV@ 942# if @REPLACE_IMAXDIV@
925extern imaxdiv_t imaxdiv (intmax_t, intmax_t); 943# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
944# undef imaxdiv
945# define imaxdiv rpl_imaxdiv
946# endif
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));
949# else
950# if !@HAVE_DECL_IMAXDIV@
951_GL_FUNCDECL_SYS (imaxdiv, imaxdiv_t, (intmax_t numer, intmax_t denom));
952# endif
953_GL_CXXALIAS_SYS (imaxdiv, imaxdiv_t, (intmax_t numer, intmax_t denom));
954# endif
955# if __GLIBC__ >= 2
956_GL_CXXALIASWARN (imaxdiv);
926# endif 957# endif
927#elif defined GNULIB_POSIXCHECK 958#elif defined GNULIB_POSIXCHECK
928# undef imaxdiv 959# undef imaxdiv
diff --git a/gl/iswblank.c b/gl/iswblank.c
new file mode 100644
index 00000000..f699850a
--- /dev/null
+++ b/gl/iswblank.c
@@ -0,0 +1,26 @@
1/* Test wide character for being blank.
2 Copyright (C) 2008-2024 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 <wctype.h>
21
22int
23iswblank (wint_t wc)
24{
25 return wc == ' ' || wc == '\t';
26}
diff --git a/gl/iswctype-impl.h b/gl/iswctype-impl.h
new file mode 100644
index 00000000..999f220c
--- /dev/null
+++ b/gl/iswctype-impl.h
@@ -0,0 +1,22 @@
1/* Test whether a wide character has a given property.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2011.
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
18int
19iswctype (wint_t wc, wctype_t desc)
20{
21 return ((int (*) (wint_t)) desc) (wc);
22}
diff --git a/gl/iswctype.c b/gl/iswctype.c
new file mode 100644
index 00000000..f4e6f015
--- /dev/null
+++ b/gl/iswctype.c
@@ -0,0 +1,36 @@
1/* Test whether a wide character has a given property.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2011.
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 <wctype.h>
22
23#if GNULIB_defined_wint_t && !GNULIB_defined_wctype_t
24
25int
26iswctype (wint_t wc, wctype_t desc)
27# undef iswctype
28{
29 return ((wchar_t) wc == wc ? iswctype ((wchar_t) wc, desc) : 0);
30}
31
32#else
33
34# include "iswctype-impl.h"
35
36#endif
diff --git a/gl/iswdigit.c b/gl/iswdigit.c
new file mode 100644
index 00000000..57363ab8
--- /dev/null
+++ b/gl/iswdigit.c
@@ -0,0 +1,26 @@
1/* Test wide character for being a digit.
2 Copyright (C) 2020-2024 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 <wctype.h>
21
22int
23iswdigit (wint_t wc)
24{
25 return wc >= '0' && wc <= '9';
26}
diff --git a/gl/iswpunct.c b/gl/iswpunct.c
new file mode 100644
index 00000000..c7cb28b5
--- /dev/null
+++ b/gl/iswpunct.c
@@ -0,0 +1,33 @@
1/* Test wide character for being a punctuation or symbol character.
2 Copyright (C) 2023-2024 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 <wctype.h>
21
22#include <ctype.h>
23
24int
25iswpunct (wint_t wc)
26#undef iswpunct
27{
28#if defined __ANDROID__
29 if ((unsigned int) wc < 128)
30 return ispunct ((unsigned int) wc);
31#endif
32 return iswpunct (wc);
33}
diff --git a/gl/iswxdigit.c b/gl/iswxdigit.c
new file mode 100644
index 00000000..d32e3b0f
--- /dev/null
+++ b/gl/iswxdigit.c
@@ -0,0 +1,33 @@
1/* Test wide character for being a hexadecimal digit.
2 Copyright (C) 2020-2024 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 <wctype.h>
21
22int
23iswxdigit (wint_t wc)
24{
25 return ((wc >= '0' && wc <= '9')
26#if 'A' == 0x41 && 'a' == 0x61
27 /* Optimization, assuming ASCII */
28 || ((wc & ~0x20) >= 'A' && (wc & ~0x20) <= 'F')
29#else
30 || (wc >= 'A' && wc <= 'F') || (wc >= 'a' && wc <= 'f')
31#endif
32 );
33}
diff --git a/gl/itold.c b/gl/itold.c
index 0ef4464e..e6fbcff4 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2011-2024 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 c7555a6a..febbd25f 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2009-2024 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
@@ -34,6 +34,11 @@
34#ifndef _@GUARD_PREFIX@_LANGINFO_H 34#ifndef _@GUARD_PREFIX@_LANGINFO_H
35#define _@GUARD_PREFIX@_LANGINFO_H 35#define _@GUARD_PREFIX@_LANGINFO_H
36 36
37/* This file uses GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */
38#if !_GL_CONFIG_H_INCLUDED
39 #error "Please include config.h first."
40#endif
41
37 42
38#if !@HAVE_LANGINFO_H@ 43#if !@HAVE_LANGINFO_H@
39 44
@@ -208,7 +213,9 @@ _GL_FUNCDECL_SYS (nl_langinfo, char *, (nl_item item));
208# endif 213# endif
209_GL_CXXALIAS_SYS (nl_langinfo, char *, (nl_item item)); 214_GL_CXXALIAS_SYS (nl_langinfo, char *, (nl_item item));
210# endif 215# endif
216# if __GLIBC__ >= 2
211_GL_CXXALIASWARN (nl_langinfo); 217_GL_CXXALIASWARN (nl_langinfo);
218# endif
212#elif defined GNULIB_POSIXCHECK 219#elif defined GNULIB_POSIXCHECK
213# undef nl_langinfo 220# undef nl_langinfo
214# if HAVE_RAW_DECL_NL_LANGINFO 221# if HAVE_RAW_DECL_NL_LANGINFO
diff --git a/gl/lc-charset-dispatch.c b/gl/lc-charset-dispatch.c
index cd74466b..e2f8b2f5 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2018-2024 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 c82b6a60..4c1cf5f1 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2018-2024 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 1d28e58c..70114608 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-2023 Free Software Foundation, Inc. 3 Copyright 2017-2024 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
@@ -137,8 +137,6 @@
137# undef __attribute_returns_twice__ 137# undef __attribute_returns_twice__
138# undef __attribute_used__ 138# undef __attribute_used__
139# undef __attribute_warn_unused_result__ 139# undef __attribute_warn_unused_result__
140# undef __bos
141# undef __bos0
142# undef __errordecl 140# undef __errordecl
143# undef __extension__ 141# undef __extension__
144# undef __extern_always_inline 142# undef __extern_always_inline
@@ -147,21 +145,13 @@
147# undef __fortified_attr_access 145# undef __fortified_attr_access
148# undef __fortify_function 146# undef __fortify_function
149# undef __glibc_c99_flexarr_available 147# undef __glibc_c99_flexarr_available
150# undef __glibc_fortify
151# undef __glibc_fortify_n
152# undef __glibc_has_attribute 148# undef __glibc_has_attribute
153# undef __glibc_has_builtin 149# undef __glibc_has_builtin
154# undef __glibc_has_extension 150# undef __glibc_has_extension
155# undef __glibc_likely 151# undef __glibc_likely
156# undef __glibc_macro_warning 152# undef __glibc_macro_warning
157# undef __glibc_macro_warning1 153# undef __glibc_macro_warning1
158# undef __glibc_objsize
159# undef __glibc_objsize0
160# undef __glibc_safe_len_cond
161# undef __glibc_safe_or_unknown_len
162# undef __glibc_unlikely 154# undef __glibc_unlikely
163# undef __glibc_unsafe_len
164# undef __glibc_unsigned_or_positive
165# undef __inline 155# undef __inline
166# undef __ptr_t 156# undef __ptr_t
167# undef __restrict 157# undef __restrict
@@ -170,6 +160,18 @@
170# undef __va_arg_pack_len 160# undef __va_arg_pack_len
171# undef __warnattr 161# undef __warnattr
172# undef __wur 162# undef __wur
163# ifndef __GNULIB_CDEFS
164# undef __bos
165# undef __bos0
166# undef __glibc_fortify
167# undef __glibc_fortify_n
168# undef __glibc_objsize
169# undef __glibc_objsize0
170# undef __glibc_safe_len_cond
171# undef __glibc_safe_or_unknown_len
172# undef __glibc_unsafe_len
173# undef __glibc_unsigned_or_positive
174# endif
173 175
174/* Include our copy of glibc <sys/cdefs.h>. */ 176/* Include our copy of glibc <sys/cdefs.h>. */
175# include <cdefs.h> 177# include <cdefs.h>
diff --git a/gl/limits.in.h b/gl/limits.in.h
index eaeac472..c65eb4c1 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-2023 Free Software Foundation, Inc. 3 Copyright 2016-2024 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
@@ -99,6 +99,11 @@
99# endif 99# endif
100#endif 100#endif
101 101
102/* Assume no multibyte character is longer than 16 bytes. */
103#ifndef MB_LEN_MAX
104# define MB_LEN_MAX 16
105#endif
106
102/* Macros specified by C23 and by ISO/IEC TS 18661-1:2014. */ 107/* Macros specified by C23 and by ISO/IEC TS 18661-1:2014. */
103 108
104#if (! defined ULLONG_WIDTH \ 109#if (! defined ULLONG_WIDTH \
@@ -119,11 +124,26 @@
119 124
120/* Macros specified by C23. */ 125/* Macros specified by C23. */
121 126
122#if (! defined BOOL_WIDTH \ 127#if (defined _GNU_SOURCE \
123 && (defined _GNU_SOURCE \ 128 || (defined __STDC_VERSION__ && 201710 < __STDC_VERSION__))
124 || (defined __STDC_VERSION__ && 201710 < __STDC_VERSION__))) 129# if ! defined BOOL_WIDTH
125# define BOOL_MAX 1 130# define BOOL_WIDTH 1
126# define BOOL_WIDTH 1 131# define BOOL_MAX 1
132# elif ! defined BOOL_MAX
133# define BOOL_MAX 1
134# endif
135#endif
136
137/* Macro specified by POSIX. */
138
139/* The maximum ssize_t value. Although it might not be of ssize_t type
140 as it should be, it's too much trouble to fix this minor detail. */
141#ifndef SSIZE_MAX
142# ifdef _WIN64
143# define SSIZE_MAX LLONG_MAX
144# else
145# define SSIZE_MAX LONG_MAX
146# endif
127#endif 147#endif
128 148
129#endif /* _@GUARD_PREFIX@_LIMITS_H */ 149#endif /* _@GUARD_PREFIX@_LIMITS_H */
diff --git a/gl/localcharset.c b/gl/localcharset.c
index 7ed9c957..93c4baa4 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2000-2006, 2008-2024 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
@@ -1054,7 +1054,7 @@ locale_charset (void)
1054 } 1054 }
1055 } 1055 }
1056 if (0) 1056 if (0)
1057 done_table_lookup: ; 1057 done_table_lookup: {}
1058 else 1058 else
1059# endif 1059# endif
1060 { 1060 {
diff --git a/gl/localcharset.h b/gl/localcharset.h
index 29ee8dc0..47214024 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2000-2003, 2009-2024 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
@@ -104,10 +104,8 @@ extern const char * locale_charset (void);
104 GBK glibc aix osf solaris freebsd darwin cygwin windows dos 104 GBK glibc aix osf solaris freebsd darwin cygwin windows dos
105 GB18030 glibc hpux solaris freebsd netbsd darwin 105 GB18030 glibc hpux solaris freebsd netbsd darwin
106 SHIFT_JIS Y hpux osf solaris freebsd netbsd darwin 106 SHIFT_JIS Y hpux osf solaris freebsd netbsd darwin
107 JOHAB glibc solaris windows 107 JOHAB solaris windows
108 TIS-620 glibc aix hpux osf solaris cygwin zos 108 TIS-620 glibc aix hpux osf solaris cygwin zos
109 VISCII Y glibc
110 TCVN5712-1 glibc
111 ARMSCII-8 glibc freebsd netbsd darwin 109 ARMSCII-8 glibc freebsd netbsd darwin
112 GEORGIAN-PS glibc cygwin 110 GEORGIAN-PS glibc cygwin
113 PT154 glibc netbsd cygwin 111 PT154 glibc netbsd cygwin
diff --git a/gl/locale.in.h b/gl/locale.in.h
index 538b8341..1b11a41c 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2007-2024 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
@@ -44,6 +44,11 @@
44#ifndef _@GUARD_PREFIX@_LOCALE_H 44#ifndef _@GUARD_PREFIX@_LOCALE_H
45#define _@GUARD_PREFIX@_LOCALE_H 45#define _@GUARD_PREFIX@_LOCALE_H
46 46
47/* This file uses GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */
48#if !_GL_CONFIG_H_INCLUDED
49 #error "Please include config.h first."
50#endif
51
47/* NetBSD 5.0 mis-defines NULL. */ 52/* NetBSD 5.0 mis-defines NULL. */
48#include <stddef.h> 53#include <stddef.h>
49 54
@@ -211,7 +216,7 @@ _GL_WARN_ON_USE (setlocale, "setlocale works differently on native Windows - "
211# include "setlocale_null.h" 216# include "setlocale_null.h"
212#endif 217#endif
213 218
214#if /*@GNULIB_NEWLOCALE@ ||*/ (@GNULIB_LOCALENAME@ && @LOCALENAME_ENHANCE_LOCALE_FUNCS@ && @HAVE_NEWLOCALE@) 219#if /*@GNULIB_NEWLOCALE@ ||*/ (@GNULIB_LOCALENAME_UNSAFE@ && @LOCALENAME_ENHANCE_LOCALE_FUNCS@ && @HAVE_NEWLOCALE@)
215# if @REPLACE_NEWLOCALE@ 220# if @REPLACE_NEWLOCALE@
216# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 221# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
217# undef newlocale 222# undef newlocale
@@ -229,7 +234,7 @@ _GL_CXXALIAS_SYS (newlocale, locale_t,
229 (int category_mask, const char *name, locale_t base)); 234 (int category_mask, const char *name, locale_t base));
230# endif 235# endif
231# endif 236# endif
232# if @HAVE_NEWLOCALE@ 237# if __GLIBC__ >= 2 && @HAVE_NEWLOCALE@
233_GL_CXXALIASWARN (newlocale); 238_GL_CXXALIASWARN (newlocale);
234# endif 239# endif
235# if @HAVE_NEWLOCALE@ || @REPLACE_NEWLOCALE@ 240# if @HAVE_NEWLOCALE@ || @REPLACE_NEWLOCALE@
@@ -244,24 +249,24 @@ _GL_WARN_ON_USE (newlocale, "newlocale is not portable");
244# endif 249# endif
245#endif 250#endif
246 251
247#if @GNULIB_DUPLOCALE@ || (@GNULIB_LOCALENAME@ && @LOCALENAME_ENHANCE_LOCALE_FUNCS@ && @HAVE_DUPLOCALE@) 252#if @GNULIB_DUPLOCALE@ || (@GNULIB_LOCALENAME_UNSAFE@ && @LOCALENAME_ENHANCE_LOCALE_FUNCS@ && @HAVE_DUPLOCALE@)
248# if @REPLACE_DUPLOCALE@ 253# if @HAVE_DUPLOCALE@ /* locale_t may be undefined if !@HAVE_DUPLOCALE@. */
249# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 254# if @REPLACE_DUPLOCALE@
250# undef duplocale 255# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
251# define duplocale rpl_duplocale 256# undef duplocale
252# define GNULIB_defined_duplocale 1 257# define duplocale rpl_duplocale
253# endif 258# define GNULIB_defined_duplocale 1
259# endif
254_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)));
255_GL_CXXALIAS_RPL (duplocale, locale_t, (locale_t locale)); 261_GL_CXXALIAS_RPL (duplocale, locale_t, (locale_t locale));
256# else 262# else
257# if @HAVE_DUPLOCALE@
258_GL_CXXALIAS_SYS (duplocale, locale_t, (locale_t locale)); 263_GL_CXXALIAS_SYS (duplocale, locale_t, (locale_t locale));
259# endif 264# endif
260# endif 265# endif
261# if @HAVE_DUPLOCALE@ 266# if __GLIBC__ >= 2 && @HAVE_DUPLOCALE@
262_GL_CXXALIASWARN (duplocale); 267_GL_CXXALIASWARN (duplocale);
263# endif 268# endif
264# if @HAVE_DUPLOCALE@ || @REPLACE_DUPLOCALE@ 269# if @HAVE_DUPLOCALE@
265# ifndef HAVE_WORKING_DUPLOCALE 270# ifndef HAVE_WORKING_DUPLOCALE
266# define HAVE_WORKING_DUPLOCALE 1 271# define HAVE_WORKING_DUPLOCALE 1
267# endif 272# endif
@@ -274,7 +279,7 @@ _GL_WARN_ON_USE (duplocale, "duplocale is buggy on some glibc systems - "
274# endif 279# endif
275#endif 280#endif
276 281
277#if /*@GNULIB_FREELOCALE@ ||*/ (@GNULIB_LOCALENAME@ && @LOCALENAME_ENHANCE_LOCALE_FUNCS@ && @HAVE_FREELOCALE@) 282#if /*@GNULIB_FREELOCALE@ ||*/ (@GNULIB_LOCALENAME_UNSAFE@ && @LOCALENAME_ENHANCE_LOCALE_FUNCS@ && @HAVE_FREELOCALE@)
278# if @REPLACE_FREELOCALE@ 283# if @REPLACE_FREELOCALE@
279# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 284# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
280# undef freelocale 285# undef freelocale
@@ -290,7 +295,7 @@ _GL_CXXALIAS_RPL (freelocale, void, (locale_t locale));
290_GL_CXXALIAS_SYS_CAST (freelocale, void, (locale_t locale)); 295_GL_CXXALIAS_SYS_CAST (freelocale, void, (locale_t locale));
291# endif 296# endif
292# endif 297# endif
293# if @HAVE_FREELOCALE@ 298# if __GLIBC__ >= 2 && @HAVE_FREELOCALE@
294_GL_CXXALIASWARN (freelocale); 299_GL_CXXALIASWARN (freelocale);
295# endif 300# endif
296#elif defined GNULIB_POSIXCHECK 301#elif defined GNULIB_POSIXCHECK
diff --git a/gl/localeconv.c b/gl/localeconv.c
index 60c050f4..10fc7b74 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2012-2024 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,10 +19,14 @@
19/* Specification. */ 19/* Specification. */
20#include <locale.h> 20#include <locale.h>
21 21
22#include <limits.h>
23
22#if HAVE_STRUCT_LCONV_DECIMAL_POINT 24#if HAVE_STRUCT_LCONV_DECIMAL_POINT
23 25
26# define FIX_CHAR_VALUE(x) ((x) >= 0 ? (x) : CHAR_MAX)
27
24/* Override for platforms where 'struct lconv' lacks the int_p_*, int_n_* 28/* Override for platforms where 'struct lconv' lacks the int_p_*, int_n_*
25 members. */ 29 members or where fields of type 'char' are set to -1 instead of CHAR_MAX. */
26 30
27struct lconv * 31struct lconv *
28localeconv (void) 32localeconv (void)
@@ -41,21 +45,30 @@ localeconv (void)
41 result.positive_sign = sys_result->positive_sign; 45 result.positive_sign = sys_result->positive_sign;
42 result.negative_sign = sys_result->negative_sign; 46 result.negative_sign = sys_result->negative_sign;
43 result.currency_symbol = sys_result->currency_symbol; 47 result.currency_symbol = sys_result->currency_symbol;
44 result.frac_digits = sys_result->frac_digits; 48 result.frac_digits = FIX_CHAR_VALUE (sys_result->frac_digits);
45 result.p_cs_precedes = sys_result->p_cs_precedes; 49 result.p_cs_precedes = FIX_CHAR_VALUE (sys_result->p_cs_precedes);
46 result.p_sign_posn = sys_result->p_sign_posn; 50 result.p_sign_posn = FIX_CHAR_VALUE (sys_result->p_sign_posn);
47 result.p_sep_by_space = sys_result->p_sep_by_space; 51 result.p_sep_by_space = FIX_CHAR_VALUE (sys_result->p_sep_by_space);
48 result.n_cs_precedes = sys_result->n_cs_precedes; 52 result.n_cs_precedes = FIX_CHAR_VALUE (sys_result->n_cs_precedes);
49 result.n_sign_posn = sys_result->n_sign_posn; 53 result.n_sign_posn = FIX_CHAR_VALUE (sys_result->n_sign_posn);
50 result.n_sep_by_space = sys_result->n_sep_by_space; 54 result.n_sep_by_space = FIX_CHAR_VALUE (sys_result->n_sep_by_space);
51 result.int_curr_symbol = sys_result->int_curr_symbol; 55 result.int_curr_symbol = sys_result->int_curr_symbol;
52 result.int_frac_digits = sys_result->int_frac_digits; 56 result.int_frac_digits = FIX_CHAR_VALUE (sys_result->int_frac_digits);
53 result.int_p_cs_precedes = sys_result->p_cs_precedes; 57# if HAVE_STRUCT_LCONV_INT_P_CS_PRECEDES
54 result.int_p_sign_posn = sys_result->p_sign_posn; 58 result.int_p_cs_precedes = FIX_CHAR_VALUE (sys_result->int_p_cs_precedes);
55 result.int_p_sep_by_space = sys_result->p_sep_by_space; 59 result.int_p_sign_posn = FIX_CHAR_VALUE (sys_result->int_p_sign_posn);
56 result.int_n_cs_precedes = sys_result->n_cs_precedes; 60 result.int_p_sep_by_space = FIX_CHAR_VALUE (sys_result->int_p_sep_by_space);
57 result.int_n_sign_posn = sys_result->n_sign_posn; 61 result.int_n_cs_precedes = FIX_CHAR_VALUE (sys_result->int_n_cs_precedes);
58 result.int_n_sep_by_space = sys_result->n_sep_by_space; 62 result.int_n_sign_posn = FIX_CHAR_VALUE (sys_result->int_n_sign_posn);
63 result.int_n_sep_by_space = FIX_CHAR_VALUE (sys_result->int_n_sep_by_space);
64# else
65 result.int_p_cs_precedes = FIX_CHAR_VALUE (sys_result->p_cs_precedes);
66 result.int_p_sign_posn = FIX_CHAR_VALUE (sys_result->p_sign_posn);
67 result.int_p_sep_by_space = FIX_CHAR_VALUE (sys_result->p_sep_by_space);
68 result.int_n_cs_precedes = FIX_CHAR_VALUE (sys_result->n_cs_precedes);
69 result.int_n_sign_posn = FIX_CHAR_VALUE (sys_result->n_sign_posn);
70 result.int_n_sep_by_space = FIX_CHAR_VALUE (sys_result->n_sep_by_space);
71# endif
59 72
60 return &result; 73 return &result;
61} 74}
@@ -64,8 +77,6 @@ localeconv (void)
64 77
65/* Override for platforms where 'struct lconv' is a dummy. */ 78/* Override for platforms where 'struct lconv' is a dummy. */
66 79
67# include <limits.h>
68
69struct lconv * 80struct lconv *
70localeconv (void) 81localeconv (void)
71{ 82{
diff --git a/gl/lseek.c b/gl/lseek.c
index 7919b03c..61bd9fcb 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2007, 2009-2024 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/m4/00gnulib.m4 b/gl/m4/00gnulib.m4
index 7fe03e0b..cd167718 100644
--- a/gl/m4/00gnulib.m4
+++ b/gl/m4/00gnulib.m4
@@ -1,5 +1,6 @@
1# 00gnulib.m4 serial 8 1# 00gnulib.m4
2dnl Copyright (C) 2009-2023 Free Software Foundation, Inc. 2# serial 9
3dnl Copyright (C) 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -49,14 +50,14 @@ dnl AC_REQUIRE([gl_COMPILER_CLANG])
49 [if test $gl_cv_compiler_clang = yes; then 50 [if test $gl_cv_compiler_clang = yes; then
50 dnl Test whether the compiler supports the option 51 dnl Test whether the compiler supports the option
51 dnl '-Werror=implicit-function-declaration'. 52 dnl '-Werror=implicit-function-declaration'.
52 save_ac_compile="$ac_compile" 53 saved_ac_compile="$ac_compile"
53 ac_compile="$ac_compile -Werror=implicit-function-declaration" 54 ac_compile="$ac_compile -Werror=implicit-function-declaration"
54 dnl Use _AC_COMPILE_IFELSE instead of AC_COMPILE_IFELSE, to avoid a 55 dnl Use _AC_COMPILE_IFELSE instead of AC_COMPILE_IFELSE, to avoid a
55 dnl warning "AC_COMPILE_IFELSE was called before AC_USE_SYSTEM_EXTENSIONS". 56 dnl warning "AC_COMPILE_IFELSE was called before AC_USE_SYSTEM_EXTENSIONS".
56 _AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],[[]])], 57 _AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],[[]])],
57 [gl_cv_compiler_check_decl_option='-Werror=implicit-function-declaration'], 58 [gl_cv_compiler_check_decl_option='-Werror=implicit-function-declaration'],
58 [gl_cv_compiler_check_decl_option=none]) 59 [gl_cv_compiler_check_decl_option=none])
59 ac_compile="$save_ac_compile" 60 ac_compile="$saved_ac_compile"
60 else 61 else
61 gl_cv_compiler_check_decl_option=none 62 gl_cv_compiler_check_decl_option=none
62 fi 63 fi
@@ -71,11 +72,11 @@ dnl Redefine _AC_CHECK_DECL_BODY so that it references ac_compile_for_check_decl
71dnl instead of ac_compile. If, for whatever reason, the override of AC_PROG_CC 72dnl instead of ac_compile. If, for whatever reason, the override of AC_PROG_CC
72dnl in zzgnulib.m4 is inactive, use the original ac_compile. 73dnl in zzgnulib.m4 is inactive, use the original ac_compile.
73m4_define([_AC_CHECK_DECL_BODY], 74m4_define([_AC_CHECK_DECL_BODY],
74[ ac_save_ac_compile="$ac_compile" 75[ ac_saved_ac_compile="$ac_compile"
75 if test -n "$ac_compile_for_check_decl"; then 76 if test -n "$ac_compile_for_check_decl"; then
76 ac_compile="$ac_compile_for_check_decl" 77 ac_compile="$ac_compile_for_check_decl"
77 fi] 78 fi]
78m4_defn([_AC_CHECK_DECL_BODY])[ ac_compile="$ac_save_ac_compile" 79m4_defn([_AC_CHECK_DECL_BODY])[ ac_compile="$ac_saved_ac_compile"
79]) 80])
80 81
81# gl_00GNULIB 82# gl_00GNULIB
diff --git a/gl/m4/__inline.m4 b/gl/m4/__inline.m4
index acf8668b..20baf164 100644
--- a/gl/m4/__inline.m4
+++ b/gl/m4/__inline.m4
@@ -1,9 +1,12 @@
1# Test for __inline keyword 1# __inline.m4
2dnl Copyright 2017-2023 Free Software Foundation, Inc. 2# serial 1
3dnl Copyright 2017-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
6 7
8# Test for __inline keyword
9
7AC_DEFUN([gl___INLINE], 10AC_DEFUN([gl___INLINE],
8[ 11[
9 AC_CACHE_CHECK([whether the compiler supports the __inline keyword], 12 AC_CACHE_CHECK([whether the compiler supports the __inline keyword],
diff --git a/gl/m4/absolute-header.m4 b/gl/m4/absolute-header.m4
index e7947648..0abd6d90 100644
--- a/gl/m4/absolute-header.m4
+++ b/gl/m4/absolute-header.m4
@@ -1,5 +1,6 @@
1# absolute-header.m4 serial 17 1# absolute-header.m4
2dnl Copyright (C) 2006-2023 Free Software Foundation, Inc. 2# serial 18
3dnl Copyright (C) 2006-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -66,7 +67,7 @@ AC_DEFUN([gl_ABSOLUTE_HEADER_ONE],
66 esac 67 esac
67changequote(,) 68changequote(,)
68 case "$host_os" in 69 case "$host_os" in
69 mingw*) 70 mingw* | windows*)
70 dnl For the sake of native Windows compilers (excluding gcc), 71 dnl For the sake of native Windows compilers (excluding gcc),
71 dnl treat backslash as a directory separator, like /. 72 dnl treat backslash as a directory separator, like /.
72 dnl Actually, these compilers use a double-backslash as 73 dnl Actually, these compilers use a double-backslash as
diff --git a/gl/m4/af_alg.m4 b/gl/m4/af_alg.m4
index f4c0d624..33b74945 100644
--- a/gl/m4/af_alg.m4
+++ b/gl/m4/af_alg.m4
@@ -1,5 +1,6 @@
1# af_alg.m4 serial 6 1# af_alg.m4
2dnl Copyright 2018-2023 Free Software Foundation, Inc. 2# serial 6
3dnl Copyright 2018-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/alloca.m4 b/gl/m4/alloca.m4
index c685fac9..dc78dc19 100644
--- a/gl/m4/alloca.m4
+++ b/gl/m4/alloca.m4
@@ -1,5 +1,6 @@
1# alloca.m4 serial 21 1# alloca.m4
2dnl Copyright (C) 2002-2004, 2006-2007, 2009-2023 Free Software Foundation, 2# serial 21
3dnl Copyright (C) 2002-2004, 2006-2007, 2009-2024 Free Software Foundation,
3dnl Inc. 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,
diff --git a/gl/m4/arpa_inet_h.m4 b/gl/m4/arpa_inet_h.m4
index fa5fe831..9eac86d7 100644
--- a/gl/m4/arpa_inet_h.m4
+++ b/gl/m4/arpa_inet_h.m4
@@ -1,5 +1,6 @@
1# arpa_inet_h.m4 serial 17 1# arpa_inet_h.m4
2dnl Copyright (C) 2006, 2008-2023 Free Software Foundation, Inc. 2# serial 17
3dnl Copyright (C) 2006, 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/assert_h.m4 b/gl/m4/assert_h.m4
index abba4fa3..b90d0f19 100644
--- a/gl/m4/assert_h.m4
+++ b/gl/m4/assert_h.m4
@@ -1,5 +1,6 @@
1# assert-h.m4 1# assert_h.m4
2dnl Copyright (C) 2011-2023 Free Software Foundation, Inc. 2# serial 1
3dnl Copyright (C) 2011-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -9,16 +10,16 @@ dnl From Paul Eggert.
9AC_DEFUN([gl_ASSERT_H], 10AC_DEFUN([gl_ASSERT_H],
10[ 11[
11 AC_CACHE_CHECK([for static_assert], [gl_cv_static_assert], 12 AC_CACHE_CHECK([for static_assert], [gl_cv_static_assert],
12 [gl_save_CFLAGS=$CFLAGS 13 [gl_saved_CFLAGS=$CFLAGS
13 for gl_working in "yes, a keyword" "yes, an <assert.h> macro"; do 14 for gl_working in "yes, a keyword" "yes, an <assert.h> macro"; do
14 AS_CASE([$gl_working], 15 AS_CASE([$gl_working],
15 [*assert.h*], [CFLAGS="$gl_save_CFLAGS -DINCLUDE_ASSERT_H"]) 16 [*assert.h*], [CFLAGS="$gl_saved_CFLAGS -DINCLUDE_ASSERT_H"])
16 17
17 AC_COMPILE_IFELSE( 18 AC_COMPILE_IFELSE(
18 [AC_LANG_PROGRAM( 19 [AC_LANG_PROGRAM(
19 [[#if defined __clang__ && __STDC_VERSION__ < 202311 20 [[#if defined __clang__ && __STDC_VERSION__ < 202311
20 #pragma clang diagnostic error "-Wc2x-extensions" 21 #pragma clang diagnostic error "-Wc2x-extensions"
21 #pragma clang diagnostic error "-Wc++17-extensions" 22 #pragma clang diagnostic error "-Wc++1z-extensions"
22 #endif 23 #endif
23 #ifdef INCLUDE_ASSERT_H 24 #ifdef INCLUDE_ASSERT_H
24 #include <assert.h> 25 #include <assert.h>
@@ -32,7 +33,7 @@ AC_DEFUN([gl_ASSERT_H],
32 ]])], 33 ]])],
33 [gl_cv_static_assert=$gl_working], 34 [gl_cv_static_assert=$gl_working],
34 [gl_cv_static_assert=no]) 35 [gl_cv_static_assert=no])
35 CFLAGS=$gl_save_CFLAGS 36 CFLAGS=$gl_saved_CFLAGS
36 test "$gl_cv_static_assert" != no && break 37 test "$gl_cv_static_assert" != no && break
37 done]) 38 done])
38 39
@@ -46,10 +47,13 @@ AC_DEFUN([gl_ASSERT_H],
46 gl_NEXT_HEADERS([assert.h])]) 47 gl_NEXT_HEADERS([assert.h])])
47 48
48 dnl The "zz" puts this toward config.h's end, to avoid potential 49 dnl The "zz" puts this toward config.h's end, to avoid potential
49 dnl collisions with other definitions. #undef assert so that 50 dnl collisions with other definitions.
50 dnl programs are not tempted to use it without specifically 51 dnl #undef assert so that programs are not tempted to use it without
51 dnl including assert.h. Break the #undef apart with a comment 52 dnl specifically including assert.h.
52 dnl so that 'configure' does not comment it out. 53 dnl #undef __ASSERT_H__ so that on IRIX, when programs later include
54 dnl <assert.h>, this include actually defines assert.
55 dnl Break the #undef_s apart with a comment so that 'configure' does
56 dnl not comment them out.
53 AH_VERBATIM([zzstatic_assert], 57 AH_VERBATIM([zzstatic_assert],
54[#if (!defined HAVE_C_STATIC_ASSERT && !defined assert \ 58[#if (!defined HAVE_C_STATIC_ASSERT && !defined assert \
55 && (!defined __cplusplus \ 59 && (!defined __cplusplus \
@@ -57,6 +61,9 @@ AC_DEFUN([gl_ASSERT_H],
57 && __GNUG__ < 6 && __clang_major__ < 6))) 61 && __GNUG__ < 6 && __clang_major__ < 6)))
58 #include <assert.h> 62 #include <assert.h>
59 #undef/**/assert 63 #undef/**/assert
64 #ifdef __sgi
65 #undef/**/__ASSERT_H__
66 #endif
60 /* Solaris 11.4 <assert.h> defines static_assert as a macro with 2 arguments. 67 /* Solaris 11.4 <assert.h> defines static_assert as a macro with 2 arguments.
61 We need it also to be invocable with a single argument. */ 68 We need it also to be invocable with a single argument. */
62 #if defined __sun && (__STDC_VERSION__ - 0 >= 201112L) && !defined __cplusplus 69 #if defined __sun && (__STDC_VERSION__ - 0 >= 201112L) && !defined __cplusplus
diff --git a/gl/m4/base64.m4 b/gl/m4/base64.m4
index 987930ab..26f2af41 100644
--- a/gl/m4/base64.m4
+++ b/gl/m4/base64.m4
@@ -1,5 +1,6 @@
1# base64.m4 serial 4 1# base64.m4
2dnl Copyright (C) 2004, 2006, 2009-2023 Free Software Foundation, Inc. 2# serial 4
3dnl Copyright (C) 2004, 2006, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/btowc.m4 b/gl/m4/btowc.m4
index 77218a7d..d9dd7036 100644
--- a/gl/m4/btowc.m4
+++ b/gl/m4/btowc.m4
@@ -1,5 +1,6 @@
1# btowc.m4 serial 12 1# btowc.m4
2dnl Copyright (C) 2008-2023 Free Software Foundation, Inc. 2# serial 14
3dnl Copyright (C) 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -40,12 +41,12 @@ int main ()
40 [ 41 [
41changequote(,)dnl 42changequote(,)dnl
42 case "$host_os" in 43 case "$host_os" in
43 # Guess no on Cygwin. 44 # Guess no on Cygwin.
44 cygwin*) gl_cv_func_btowc_nul="guessing no" ;; 45 cygwin*) gl_cv_func_btowc_nul="guessing no" ;;
45 # Guess yes on native Windows. 46 # Guess yes on native Windows.
46 mingw*) gl_cv_func_btowc_nul="guessing yes" ;; 47 mingw* | windows*) gl_cv_func_btowc_nul="guessing yes" ;;
47 # Guess yes otherwise. 48 # Guess yes otherwise.
48 *) gl_cv_func_btowc_nul="guessing yes" ;; 49 *) gl_cv_func_btowc_nul="guessing yes" ;;
49 esac 50 esac
50changequote([,])dnl 51changequote([,])dnl
51 ]) 52 ])
@@ -59,12 +60,12 @@ changequote([,])dnl
59 dnl is present. 60 dnl is present.
60changequote(,)dnl 61changequote(,)dnl
61 case "$host_os" in 62 case "$host_os" in
62 # Guess no on IRIX. 63 # Guess no on IRIX.
63 irix*) gl_cv_func_btowc_eof="guessing no" ;; 64 irix*) gl_cv_func_btowc_eof="guessing no" ;;
64 # Guess yes on native Windows. 65 # Guess yes on native Windows.
65 mingw*) gl_cv_func_btowc_eof="guessing yes" ;; 66 mingw* | windows*) gl_cv_func_btowc_eof="guessing yes" ;;
66 # Guess yes otherwise. 67 # Guess yes otherwise.
67 *) gl_cv_func_btowc_eof="guessing yes" ;; 68 *) gl_cv_func_btowc_eof="guessing yes" ;;
68 esac 69 esac
69changequote([,])dnl 70changequote([,])dnl
70 if test $LOCALE_FR != none; then 71 if test $LOCALE_FR != none; then
@@ -88,6 +89,50 @@ int main ()
88 fi 89 fi
89 ]) 90 ])
90 91
92 dnl On mingw, in the C locale, btowc is inconsistent with mbrtowc:
93 dnl mbrtowc avoids calling MultiByteToWideChar when MB_CUR_MAX is 1 and
94 dnl ___lc_codepage_func() is 0, but btowc is lacking this special case.
95 AC_CHECK_FUNCS_ONCE([mbrtowc])
96 AC_CACHE_CHECK([whether btowc is consistent with mbrtowc in the C locale],
97 [gl_cv_func_btowc_consistent],
98 [
99 AC_RUN_IFELSE(
100 [AC_LANG_SOURCE([[
101#include <stdlib.h>
102#include <string.h>
103#include <wchar.h>
104int main ()
105{
106#if HAVE_MBRTOWC
107 wint_t wc1 = btowc (0x80);
108 wchar_t wc2 = (wchar_t) 0xbadface;
109 char buf[1] = { 0x80 };
110 mbstate_t state;
111 memset (&state, 0, sizeof (mbstate_t));
112 if (mbrtowc (&wc2, buf, 1, &state) != 1 || wc1 != wc2)
113 return 1;
114#endif
115 return 0;
116}]])],
117 [gl_cv_func_btowc_consistent=yes],
118 [gl_cv_func_btowc_consistent=no],
119 [case "$host_os" in
120 # Guess no on mingw.
121 mingw* | windows*)
122 AC_EGREP_CPP([Problem], [
123#ifdef __MINGW32__
124 Problem
125#endif
126 ],
127 [gl_cv_func_btowc_consistent="guessing no"],
128 [gl_cv_func_btowc_consistent="guessing yes"])
129 ;;
130 # Guess yes otherwise.
131 *) gl_cv_func_btowc_consistent="guessing yes" ;;
132 esac
133 ])
134 ])
135
91 case "$gl_cv_func_btowc_nul" in 136 case "$gl_cv_func_btowc_nul" in
92 *yes) ;; 137 *yes) ;;
93 *) REPLACE_BTOWC=1 ;; 138 *) REPLACE_BTOWC=1 ;;
@@ -96,10 +141,22 @@ int main ()
96 *yes) ;; 141 *yes) ;;
97 *) REPLACE_BTOWC=1 ;; 142 *) REPLACE_BTOWC=1 ;;
98 esac 143 esac
144 case "$gl_cv_func_btowc_consistent" in
145 *yes) ;;
146 *) REPLACE_BTOWC=1 ;;
147 esac
148 if test $REPLACE_BTOWC = 0; then
149 gl_MBRTOWC_C_LOCALE
150 case "$gl_cv_func_mbrtowc_C_locale_sans_EILSEQ" in
151 *yes) ;;
152 *) REPLACE_BTOWC=1 ;;
153 esac
154 fi
99 fi 155 fi
100]) 156])
101 157
102# Prerequisites of lib/btowc.c. 158# Prerequisites of lib/btowc.c.
103AC_DEFUN([gl_PREREQ_BTOWC], [ 159AC_DEFUN([gl_PREREQ_BTOWC], [
104 : 160 :
161 AC_CHECK_FUNCS_ONCE([mbrtowc])
105]) 162])
diff --git a/gl/m4/builtin-expect.m4 b/gl/m4/builtin-expect.m4
index 531ed48a..c7af926b 100644
--- a/gl/m4/builtin-expect.m4
+++ b/gl/m4/builtin-expect.m4
@@ -1,10 +1,12 @@
1dnl Check for __builtin_expect. 1# builtin-expect.m4
2 2# serial 1
3dnl Copyright 2016-2023 Free Software Foundation, Inc. 3dnl Copyright 2016-2024 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 7
8dnl Check for __builtin_expect.
9
8dnl Written by Paul Eggert. 10dnl Written by Paul Eggert.
9 11
10AC_DEFUN([gl___BUILTIN_EXPECT], 12AC_DEFUN([gl___BUILTIN_EXPECT],
diff --git a/gl/m4/byteswap.m4 b/gl/m4/byteswap.m4
index 8058d178..0c76fe93 100644
--- a/gl/m4/byteswap.m4
+++ b/gl/m4/byteswap.m4
@@ -1,5 +1,6 @@
1# byteswap.m4 serial 5 1# byteswap.m4
2dnl Copyright (C) 2005, 2007, 2009-2023 Free Software Foundation, Inc. 2# serial 5
3dnl Copyright (C) 2005, 2007, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/c-bool.m4 b/gl/m4/c-bool.m4
index f614371b..0fb0de3b 100644
--- a/gl/m4/c-bool.m4
+++ b/gl/m4/c-bool.m4
@@ -1,10 +1,12 @@
1# Check for bool that conforms to C2023. 1# c-bool.m4
2 2# serial 1
3dnl Copyright 2022-2023 Free Software Foundation, Inc. 3dnl Copyright 2022-2024 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 7
8# Check for bool that conforms to C2023.
9
8AC_DEFUN([gl_C_BOOL], 10AC_DEFUN([gl_C_BOOL],
9[ 11[
10 AC_CACHE_CHECK([for bool, true, false], [gl_cv_c_bool], 12 AC_CACHE_CHECK([for bool, true, false], [gl_cv_c_bool],
diff --git a/gl/m4/calloc.m4 b/gl/m4/calloc.m4
index 23c0dd9f..550cf5cc 100644
--- a/gl/m4/calloc.m4
+++ b/gl/m4/calloc.m4
@@ -1,9 +1,9 @@
1# calloc.m4 serial 29 1# calloc.m4
2 2# serial 31
3# Copyright (C) 2004-2023 Free Software Foundation, Inc. 3dnl Copyright (C) 2004-2024 Free Software Foundation, Inc.
4# This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5# gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6# with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7 7
8# Written by Jim Meyering. 8# Written by Jim Meyering.
9 9
@@ -36,14 +36,14 @@ AC_DEFUN([_AC_FUNC_CALLOC_IF],
36 [ac_cv_func_calloc_0_nonnull=no]) 36 [ac_cv_func_calloc_0_nonnull=no])
37 else 37 else
38 case "$host_os" in 38 case "$host_os" in
39 # Guess yes on glibc systems. 39 # Guess yes on glibc systems.
40 *-gnu* | gnu*) ac_cv_func_calloc_0_nonnull="guessing yes" ;; 40 *-gnu* | gnu*) ac_cv_func_calloc_0_nonnull="guessing yes" ;;
41 # Guess yes on musl systems. 41 # Guess yes on musl systems.
42 *-musl*) ac_cv_func_calloc_0_nonnull="guessing yes" ;; 42 *-musl* | midipix*) ac_cv_func_calloc_0_nonnull="guessing yes" ;;
43 # Guess yes on native Windows. 43 # Guess yes on native Windows.
44 mingw*) ac_cv_func_calloc_0_nonnull="guessing yes" ;; 44 mingw* | windows*) ac_cv_func_calloc_0_nonnull="guessing yes" ;;
45 # If we don't know, obey --enable-cross-guesses. 45 # If we don't know, obey --enable-cross-guesses.
46 *) ac_cv_func_calloc_0_nonnull="$gl_cross_guess_normal" ;; 46 *) ac_cv_func_calloc_0_nonnull="$gl_cross_guess_normal" ;;
47 esac 47 esac
48 fi 48 fi
49 ]) 49 ])
diff --git a/gl/m4/close.m4 b/gl/m4/close.m4
index 9f95c670..88c37fab 100644
--- a/gl/m4/close.m4
+++ b/gl/m4/close.m4
@@ -1,10 +1,11 @@
1# close.m4 serial 9 1# close.m4
2dnl Copyright (C) 2008-2023 Free Software Foundation, Inc. 2# serial 10
3dnl Copyright (C) 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
6 7
7AC_DEFUN([gl_FUNC_CLOSE], 8AC_DEFUN_ONCE([gl_FUNC_CLOSE],
8[ 9[
9 AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) 10 AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
10 m4_ifdef([gl_MSVC_INVAL], [ 11 m4_ifdef([gl_MSVC_INVAL], [
diff --git a/gl/m4/codeset.m4 b/gl/m4/codeset.m4
index 5804f472..e69b7402 100644
--- a/gl/m4/codeset.m4
+++ b/gl/m4/codeset.m4
@@ -1,5 +1,6 @@
1# codeset.m4 serial 5 (gettext-0.18.2) 1# codeset.m4
2dnl Copyright (C) 2000-2002, 2006, 2008-2014, 2016, 2019-2023 Free Software 2# serial 5 (gettext-0.18.2)
3dnl Copyright (C) 2000-2002, 2006, 2008-2014, 2016, 2019-2024 Free Software
3dnl Foundation, Inc. 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,
diff --git a/gl/m4/double-slash-root.m4 b/gl/m4/double-slash-root.m4
index 1776e5eb..3437c699 100644
--- a/gl/m4/double-slash-root.m4
+++ b/gl/m4/double-slash-root.m4
@@ -1,5 +1,6 @@
1# double-slash-root.m4 serial 4 -*- Autoconf -*- 1# double-slash-root.m4
2dnl Copyright (C) 2006, 2008-2023 Free Software Foundation, Inc. 2# serial 4 -*- Autoconf -*-
3dnl Copyright (C) 2006, 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/dup2.m4 b/gl/m4/dup2.m4
index e1cc73e1..786121fd 100644
--- a/gl/m4/dup2.m4
+++ b/gl/m4/dup2.m4
@@ -1,5 +1,6 @@
1#serial 27 1# dup2.m4
2dnl Copyright (C) 2002, 2005, 2007, 2009-2023 Free Software Foundation, Inc. 2# serial 28
3dnl Copyright (C) 2002, 2005, 2007, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -67,7 +68,7 @@ AC_DEFUN([gl_FUNC_DUP2],
67 ], 68 ],
68 [gl_cv_func_dup2_works=yes], [gl_cv_func_dup2_works=no], 69 [gl_cv_func_dup2_works=yes], [gl_cv_func_dup2_works=no],
69 [case "$host_os" in 70 [case "$host_os" in
70 mingw*) # on this platform, dup2 always returns 0 for success 71 mingw* | windows*) # on this platform, dup2 always returns 0 for success
71 gl_cv_func_dup2_works="guessing no" ;; 72 gl_cv_func_dup2_works="guessing no" ;;
72 cygwin*) # on cygwin 1.5.x, dup2(1,1) returns 0 73 cygwin*) # on cygwin 1.5.x, dup2(1,1) returns 0
73 gl_cv_func_dup2_works="guessing no" ;; 74 gl_cv_func_dup2_works="guessing no" ;;
diff --git a/gl/m4/eealloc.m4 b/gl/m4/eealloc.m4
index cb3e08fe..8a15e705 100644
--- a/gl/m4/eealloc.m4
+++ b/gl/m4/eealloc.m4
@@ -1,5 +1,6 @@
1# eealloc.m4 serial 3 1# eealloc.m4
2dnl Copyright (C) 2003, 2009-2023 Free Software Foundation, Inc. 2# serial 3
3dnl Copyright (C) 2003, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/environ.m4 b/gl/m4/environ.m4
index 741dfc56..107960b2 100644
--- a/gl/m4/environ.m4
+++ b/gl/m4/environ.m4
@@ -1,5 +1,6 @@
1# environ.m4 serial 8 1# environ.m4
2dnl Copyright (C) 2001-2004, 2006-2023 Free Software Foundation, Inc. 2# serial 8
3dnl Copyright (C) 2001-2004, 2006-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/errno_h.m4 b/gl/m4/errno_h.m4
index 4c70d225..b6050e5d 100644
--- a/gl/m4/errno_h.m4
+++ b/gl/m4/errno_h.m4
@@ -1,5 +1,6 @@
1# errno_h.m4 serial 14 1# errno_h.m4
2dnl Copyright (C) 2004, 2006, 2008-2023 Free Software Foundation, Inc. 2# serial 14
3dnl Copyright (C) 2004, 2006, 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/error.m4 b/gl/m4/error.m4
index 8cc75dff..273b636b 100644
--- a/gl/m4/error.m4
+++ b/gl/m4/error.m4
@@ -1,22 +1,12 @@
1#serial 15 1# error.m4
2 2# serial 16
3# Copyright (C) 1996-1998, 2001-2004, 2009-2023 Free Software Foundation, Inc. 3dnl Copyright (C) 1996-1998, 2001-2004, 2009-2024 Free Software Foundation, Inc.
4# 4dnl This file is free software; the Free Software Foundation
5# This file is free software; the Free Software Foundation 5dnl gives unlimited permission to copy and/or distribute it,
6# gives unlimited permission to copy and/or distribute it, 6dnl with or without modifications, as long as this notice is preserved.
7# with or without modifications, as long as this notice is preserved.
8 7
9AC_DEFUN([gl_ERROR], 8AC_DEFUN([gl_ERROR],
10[ 9[
11 dnl We don't use AC_FUNC_ERROR_AT_LINE any more, because it is no longer
12 dnl maintained in Autoconf and because it invokes AC_LIBOBJ.
13 AC_CACHE_CHECK([for error_at_line], [ac_cv_lib_error_at_line],
14 [AC_LINK_IFELSE(
15 [AC_LANG_PROGRAM(
16 [[#include <error.h>]],
17 [[error_at_line (0, 0, "", 0, "an error occurred");]])],
18 [ac_cv_lib_error_at_line=yes],
19 [ac_cv_lib_error_at_line=no])])
20]) 10])
21 11
22# Prerequisites of lib/error.c. 12# Prerequisites of lib/error.c.
diff --git a/gl/m4/error_h.m4 b/gl/m4/error_h.m4
new file mode 100644
index 00000000..050a410c
--- /dev/null
+++ b/gl/m4/error_h.m4
@@ -0,0 +1,125 @@
1# error_h.m4
2# serial 4
3dnl Copyright (C) 1996-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 Provide a working <error.h>.
10
11AC_DEFUN_ONCE([gl_ERROR_H],
12[
13 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
14
15 gl_CHECK_NEXT_HEADERS([error.h])
16 if test $ac_cv_header_error_h = yes; then
17 HAVE_ERROR_H=1
18 else
19 HAVE_ERROR_H=0
20 fi
21 AC_SUBST([HAVE_ERROR_H])
22
23 REPLACE_ERROR=0
24
25 gl_CHECK_FUNCS_ANDROID([error], [[#include <error.h>]])
26 if test $ac_cv_func_error = yes; then
27 HAVE_ERROR=1
28 else
29 HAVE_ERROR=0
30 case "$gl_cv_onwards_func_error" in
31 future*) REPLACE_ERROR=1 ;;
32 esac
33 fi
34
35 dnl We don't use AC_FUNC_ERROR_AT_LINE any more, because it is no longer
36 dnl maintained in Autoconf and because it invokes AC_LIBOBJ.
37 dnl We need to notice a missing declaration, like gl_CHECK_FUNCS_ANDROID does.
38 AC_CHECK_DECL([error_at_line], , , [[#include <error.h>]])
39 if test $ac_cv_have_decl_error_at_line = yes; then
40 AC_CACHE_CHECK([for error_at_line], [ac_cv_lib_error_at_line],
41 [AC_LINK_IFELSE(
42 [AC_LANG_PROGRAM(
43 [[#include <error.h>]],
44 [[error_at_line (0, 0, "", 0, "an error occurred");]])],
45 [ac_cv_lib_error_at_line=yes],
46 [ac_cv_lib_error_at_line=no])])
47 else
48 ac_cv_lib_error_at_line=no
49 fi
50 if test $ac_cv_lib_error_at_line = yes; then
51 HAVE_ERROR_AT_LINE=1
52 else
53 HAVE_ERROR_AT_LINE=0
54 fi
55 REPLACE_ERROR_AT_LINE=0
56
57 if test $ac_cv_func_error = yes && test $ac_cv_lib_error_at_line = yes; then
58 dnl On Android 11, when error_print_progname is set, the output of the
59 dnl error() function contains an extra space.
60 AC_CACHE_CHECK([for working error function],
61 [gl_cv_func_working_error],
62 [if test $cross_compiling != yes; then
63 AC_LINK_IFELSE(
64 [AC_LANG_PROGRAM([[
65 #include <error.h>
66 static void print_no_progname (void) {}
67 ]], [[
68 error_print_progname = print_no_progname;
69 error (0, 0, "foo");
70 ]])
71 ],
72 [rm -f conftest.out
73 if test -s conftest$ac_exeext \
74 && ./conftest$ac_exeext 2> conftest.out; then
75 if grep ' ' conftest.out >/dev/null; then
76 gl_cv_func_working_error=no
77 else
78 gl_cv_func_working_error=yes
79 fi
80 else
81 gl_cv_func_working_error=no
82 fi
83 rm -f conftest.out
84 ],
85 [gl_cv_func_working_error=no])
86 else
87 AC_COMPILE_IFELSE(
88 [AC_LANG_PROGRAM([[
89 #include <error.h>
90 ]], [[
91 error (0, 0, "foo");
92 ]])
93 ],
94 [case "$host_os" in
95 # Guess yes on glibc systems.
96 *-gnu* | gnu*) gl_cv_func_working_error="guessing yes" ;;
97 # Guess no on Android.
98 linux*-android*) gl_cv_func_working_error="guessing no" ;;
99 # If we don't know, obey --enable-cross-guesses.
100 *) gl_cv_func_working_error="$gl_cross_guess_normal" ;;
101 esac
102 ],
103 [gl_cv_func_working_error=no])
104 fi
105 ])
106 case "$gl_cv_func_working_error" in
107 *no)
108 REPLACE_ERROR=1
109 REPLACE_ERROR_AT_LINE=1
110 ;;
111 esac
112 fi
113
114 if test $HAVE_ERROR = 0 || test $REPLACE_ERROR = 1 \
115 || test $HAVE_ERROR_AT_LINE = 0 || test $REPLACE_ERROR_AT_LINE = 1; then
116 COMPILE_ERROR_C=1
117 else
118 COMPILE_ERROR_C=0
119 fi
120
121 AC_SUBST([HAVE_ERROR])
122 AC_SUBST([HAVE_ERROR_AT_LINE])
123 AC_SUBST([REPLACE_ERROR])
124 AC_SUBST([REPLACE_ERROR_AT_LINE])
125])
diff --git a/gl/m4/exponentd.m4 b/gl/m4/exponentd.m4
index 2ef46437..db597afc 100644
--- a/gl/m4/exponentd.m4
+++ b/gl/m4/exponentd.m4
@@ -1,9 +1,10 @@
1# exponentd.m4 serial 3 1# exponentd.m4
2dnl Copyright (C) 2007-2008, 2010-2023 Free Software Foundation, Inc. 2# serial 4
3dnl Copyright (C) 2007-2008, 2010-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
6AC_DEFUN([gl_DOUBLE_EXPONENT_LOCATION], 7AC_DEFUN_ONCE([gl_DOUBLE_EXPONENT_LOCATION],
7[ 8[
8 AC_CACHE_CHECK([where to find the exponent in a 'double'], 9 AC_CACHE_CHECK([where to find the exponent in a 'double'],
9 [gl_cv_cc_double_expbit0], 10 [gl_cv_cc_double_expbit0],
diff --git a/gl/m4/extensions.m4 b/gl/m4/extensions.m4
index 5336b8da..1fb68956 100644
--- a/gl/m4/extensions.m4
+++ b/gl/m4/extensions.m4
@@ -1,10 +1,11 @@
1# serial 23 -*- Autoconf -*- 1# extensions.m4
2# Enable extensions on systems that normally disable them. 2# serial 25 -*- Autoconf -*-
3dnl Copyright (C) 2003, 2006-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.
3 7
4# Copyright (C) 2003, 2006-2023 Free Software Foundation, Inc. 8# Enable extensions on systems that normally disable them.
5# This file is free software; the Free Software Foundation
6# gives unlimited permission to copy and/or distribute it,
7# with or without modifications, as long as this notice is preserved.
8 9
9dnl Define to empty for the benefit of Autoconf 2.69 and earlier, so that 10dnl Define to empty for the benefit of Autoconf 2.69 and earlier, so that
10dnl AC_USE_SYSTEM_EXTENSIONS (below) can be used unchanged from Autoconf 2.70+. 11dnl AC_USE_SYSTEM_EXTENSIONS (below) can be used unchanged from Autoconf 2.70+.
@@ -229,4 +230,15 @@ AC_DEFUN_ONCE([gl_USE_SYSTEM_EXTENSIONS],
229 [Define to enable the declarations of ISO C 11 types and functions.]) 230 [Define to enable the declarations of ISO C 11 types and functions.])
230 ;; 231 ;;
231 esac 232 esac
233
234 dnl On OpenSolaris derivatives, the include files contains a couple of
235 dnl declarations that are only activated with an explicit
236 dnl -D__STDC_WANT_LIB_EXT1__.
237 AH_VERBATIM([USE_ISO_C_23_ANNEX_K_EXTENSIONS],
238[/* Define to enable the declarations of ISO C 23 Annex K types and functions. */
239#if !(defined __STDC_WANT_LIB_EXT1__ && __STDC_WANT_LIB_EXT1__)
240#undef/**/__STDC_WANT_LIB_EXT1__
241#define __STDC_WANT_LIB_EXT1__ 1
242#endif
243])
232]) 244])
diff --git a/gl/m4/extern-inline.m4 b/gl/m4/extern-inline.m4
index c001b1cf..547da82a 100644
--- a/gl/m4/extern-inline.m4
+++ b/gl/m4/extern-inline.m4
@@ -1,10 +1,12 @@
1dnl 'extern inline' a la ISO C99. 1# extern-inline.m4
2 2# serial 1
3dnl Copyright 2012-2023 Free Software Foundation, Inc. 3dnl Copyright 2012-2024 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 7
8dnl 'extern inline' a la ISO C99.
9
8AC_DEFUN([gl_EXTERN_INLINE], 10AC_DEFUN([gl_EXTERN_INLINE],
9[ 11[
10 AC_CACHE_CHECK([whether ctype.h defines __header_inline], 12 AC_CACHE_CHECK([whether ctype.h defines __header_inline],
@@ -79,7 +81,8 @@ AC_DEFUN([gl_EXTERN_INLINE],
79# define _GL_EXTERN_INLINE_STDHEADER_BUG 81# define _GL_EXTERN_INLINE_STDHEADER_BUG
80#endif 82#endif
81#if ((__GNUC__ \ 83#if ((__GNUC__ \
82 ? defined __GNUC_STDC_INLINE__ && __GNUC_STDC_INLINE__ \ 84 ? (defined __GNUC_STDC_INLINE__ && __GNUC_STDC_INLINE__ \
85 && !defined __PCC__) \
83 : (199901L <= __STDC_VERSION__ \ 86 : (199901L <= __STDC_VERSION__ \
84 && !defined __HP_cc \ 87 && !defined __HP_cc \
85 && !defined __PGI \ 88 && !defined __PGI \
@@ -89,6 +92,7 @@ AC_DEFUN([gl_EXTERN_INLINE],
89# define _GL_EXTERN_INLINE extern inline 92# define _GL_EXTERN_INLINE extern inline
90# define _GL_EXTERN_INLINE_IN_USE 93# define _GL_EXTERN_INLINE_IN_USE
91#elif (2 < __GNUC__ + (7 <= __GNUC_MINOR__) && !defined __STRICT_ANSI__ \ 94#elif (2 < __GNUC__ + (7 <= __GNUC_MINOR__) && !defined __STRICT_ANSI__ \
95 && !defined __PCC__ \
92 && !defined _GL_EXTERN_INLINE_STDHEADER_BUG) 96 && !defined _GL_EXTERN_INLINE_STDHEADER_BUG)
93# if defined __GNUC_GNU_INLINE__ && __GNUC_GNU_INLINE__ 97# if defined __GNUC_GNU_INLINE__ && __GNUC_GNU_INLINE__
94 /* __gnu_inline__ suppresses a GCC 4.2 diagnostic. */ 98 /* __gnu_inline__ suppresses a GCC 4.2 diagnostic. */
diff --git a/gl/m4/fclose.m4 b/gl/m4/fclose.m4
new file mode 100644
index 00000000..0c1358ed
--- /dev/null
+++ b/gl/m4/fclose.m4
@@ -0,0 +1,99 @@
1# fclose.m4
2# serial 12
3dnl Copyright (C) 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
8AC_DEFUN_ONCE([gl_FUNC_FCLOSE],
9[
10 AC_REQUIRE([gl_STDIO_H_DEFAULTS])
11 AC_REQUIRE([AC_CANONICAL_HOST])
12
13 gl_FUNC_FFLUSH_STDIN
14 case "$gl_cv_func_fflush_stdin" in
15 *yes) ;;
16 *) REPLACE_FCLOSE=1 ;;
17 esac
18
19 AC_REQUIRE([gl_FUNC_CLOSE])
20 if test $REPLACE_CLOSE = 1; then
21 REPLACE_FCLOSE=1
22 fi
23
24 case "$host_os" in
25 openedition) REPLACE_FCLOSE=1 ;;
26 esac
27
28 if test $REPLACE_FCLOSE = 0; then
29 gl_FUNC_FCLOSE_STDIN
30 case "$gl_cv_func_fclose_stdin" in
31 *yes) ;;
32 *) REPLACE_FCLOSE=1 ;;
33 esac
34 fi
35])
36
37dnl Determine whether fclose works on input streams.
38dnl Sets gl_cv_func_fclose_stdin.
39
40AC_DEFUN([gl_FUNC_FCLOSE_STDIN],
41[
42 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
43 AC_CHECK_HEADERS_ONCE([unistd.h])
44 AC_CACHE_CHECK([whether fclose works on input streams],
45 [gl_cv_func_fclose_stdin],
46 [echo hello world > conftest.txt
47 AC_RUN_IFELSE(
48 [AC_LANG_PROGRAM(
49 [[#include <fcntl.h>
50 #include <stdio.h>
51 #if HAVE_UNISTD_H
52 # include <unistd.h>
53 #else /* on Windows with MSVC */
54 # include <io.h>
55 #endif
56 ]GL_MDA_DEFINES],
57 [[int fd;
58 int fd2;
59 FILE *fp;
60 fd = open ("conftest.txt", O_RDONLY);
61 if (fd < 0)
62 return 1;
63 if (lseek (fd, 1, SEEK_SET) != 1)
64 return 2;
65 fd2 = dup (fd);
66 if (fd2 < 0)
67 return 3;
68 fp = fdopen (fd2, "r");
69 if (fp == NULL)
70 return 4;
71 if (fgetc (fp) != 'e')
72 { fclose (fp); return 5; }
73 /* This fclose() call should reposition the underlying file
74 descriptor. */
75 if (fclose (fp) != 0)
76 return 6;
77 if (lseek (fd2, 0, SEEK_CUR) != -1) /* should fail with EBADF */
78 return 7;
79 /* Verify the file position. */
80 if (lseek (fd, 0, SEEK_CUR) != 2)
81 return 8;
82 return 0;
83 ]])],
84 [gl_cv_func_fclose_stdin=yes],
85 [gl_cv_func_fclose_stdin=no],
86 [case "$host_os" in
87 # Guess no on glibc systems.
88 *-gnu* | gnu*) gl_cv_func_fclose_stdin="guessing no" ;;
89 # Guess yes on musl systems.
90 *-musl* | midipix*) gl_cv_func_fclose_stdin="guessing yes" ;;
91 # Guess no on native Windows.
92 mingw* | windows*) gl_cv_func_fclose_stdin="guessing no" ;;
93 # If we don't know, obey --enable-cross-guesses.
94 *) gl_cv_func_fclose_stdin="$gl_cross_guess_normal" ;;
95 esac
96 ])
97 rm conftest.txt
98 ])
99])
diff --git a/gl/m4/fcntl-o.m4 b/gl/m4/fcntl-o.m4
index 59d558bd..43aa1325 100644
--- a/gl/m4/fcntl-o.m4
+++ b/gl/m4/fcntl-o.m4
@@ -1,5 +1,6 @@
1# fcntl-o.m4 serial 7 1# fcntl-o.m4
2dnl Copyright (C) 2006, 2009-2023 Free Software Foundation, Inc. 2# serial 8
3dnl Copyright (C) 2006, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -117,9 +118,9 @@ AC_DEFUN([gl_FCNTL_O_FLAGS],
117 *) gl_cv_header_working_fcntl_h='no';; 118 *) gl_cv_header_working_fcntl_h='no';;
118 esac], 119 esac],
119 [case "$host_os" in 120 [case "$host_os" in
120 # Guess 'no' on native Windows. 121 # Guess 'no' on native Windows.
121 mingw*) gl_cv_header_working_fcntl_h='no' ;; 122 mingw* | windows*) gl_cv_header_working_fcntl_h='no' ;;
122 *) gl_cv_header_working_fcntl_h=cross-compiling ;; 123 *) gl_cv_header_working_fcntl_h=cross-compiling ;;
123 esac 124 esac
124 ]) 125 ])
125 ]) 126 ])
diff --git a/gl/m4/fcntl.m4 b/gl/m4/fcntl.m4
index 524a99af..f6d0f377 100644
--- a/gl/m4/fcntl.m4
+++ b/gl/m4/fcntl.m4
@@ -1,5 +1,6 @@
1# fcntl.m4 serial 11 1# fcntl.m4
2dnl Copyright (C) 2009-2023 Free Software Foundation, Inc. 2# serial 12
3dnl Copyright (C) 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -82,7 +83,7 @@ AC_DEFUN([gl_FUNC_FCNTL],
82 esac 83 esac
83 84
84 dnl Many systems lack F_DUPFD_CLOEXEC. 85 dnl Many systems lack F_DUPFD_CLOEXEC.
85 dnl NetBSD 9.0 declares F_DUPFD_CLOEXEC but it works only like F_DUPFD. 86 dnl NetBSD 10.0 declares F_DUPFD_CLOEXEC but it works only like F_DUPFD.
86 AC_CACHE_CHECK([whether fcntl understands F_DUPFD_CLOEXEC], 87 AC_CACHE_CHECK([whether fcntl understands F_DUPFD_CLOEXEC],
87 [gl_cv_func_fcntl_f_dupfd_cloexec], 88 [gl_cv_func_fcntl_f_dupfd_cloexec],
88 [AC_RUN_IFELSE( 89 [AC_RUN_IFELSE(
diff --git a/gl/m4/fcntl_h.m4 b/gl/m4/fcntl_h.m4
index 68f4e648..b69f7a0c 100644
--- a/gl/m4/fcntl_h.m4
+++ b/gl/m4/fcntl_h.m4
@@ -1,10 +1,12 @@
1# fcntl_h.m4
1# serial 20 2# serial 20
2# Configure fcntl.h. 3dnl Copyright (C) 2006-2007, 2009-2024 Free Software Foundation, Inc.
3dnl Copyright (C) 2006-2007, 2009-2023 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 7
8# Configure fcntl.h.
9
8dnl Written by Paul Eggert. 10dnl Written by Paul Eggert.
9 11
10AC_DEFUN_ONCE([gl_FCNTL_H], 12AC_DEFUN_ONCE([gl_FCNTL_H],
diff --git a/gl/m4/fflush.m4 b/gl/m4/fflush.m4
index 3e3c8903..43fc3bf3 100644
--- a/gl/m4/fflush.m4
+++ b/gl/m4/fflush.m4
@@ -1,9 +1,9 @@
1# fflush.m4 serial 18 1# fflush.m4
2 2# serial 19
3# Copyright (C) 2007-2023 Free Software Foundation, Inc. 3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
4# This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5# gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6# with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7 7
8dnl From Eric Blake 8dnl From Eric Blake
9 9
@@ -79,9 +79,9 @@ AC_DEFUN([gl_FUNC_FFLUSH_STDIN],
79 [gl_cv_func_fflush_stdin=yes], 79 [gl_cv_func_fflush_stdin=yes],
80 [gl_cv_func_fflush_stdin=no], 80 [gl_cv_func_fflush_stdin=no],
81 [case "$host_os" in 81 [case "$host_os" in
82 # Guess no on native Windows. 82 # Guess no on native Windows.
83 mingw*) gl_cv_func_fflush_stdin="guessing no" ;; 83 mingw* | windows*) gl_cv_func_fflush_stdin="guessing no" ;;
84 *) gl_cv_func_fflush_stdin=cross ;; 84 *) gl_cv_func_fflush_stdin=cross ;;
85 esac 85 esac
86 ]) 86 ])
87 rm conftest.txt 87 rm conftest.txt
diff --git a/gl/m4/float_h.m4 b/gl/m4/float_h.m4
index 2f0c9c4e..c95d4171 100644
--- a/gl/m4/float_h.m4
+++ b/gl/m4/float_h.m4
@@ -1,5 +1,6 @@
1# float_h.m4 serial 13 1# float_h.m4
2dnl Copyright (C) 2007, 2009-2023 Free Software Foundation, Inc. 2# serial 14
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -84,9 +85,11 @@ int main ()
84 [gl_cv_func_itold_works="guessing no"], 85 [gl_cv_func_itold_works="guessing no"],
85 [gl_cv_func_itold_works="guessing yes"]) 86 [gl_cv_func_itold_works="guessing yes"])
86 ;; 87 ;;
87 # Guess yes on native Windows. 88 # Guess yes on native Windows.
88 mingw*) gl_cv_func_itold_works="guessing yes" ;; 89 mingw* | windows*)
89 *) gl_cv_func_itold_works="guessing yes" ;; 90 gl_cv_func_itold_works="guessing yes" ;;
91 *)
92 gl_cv_func_itold_works="guessing yes" ;;
90 esac 93 esac
91 ]) 94 ])
92 ]) 95 ])
diff --git a/gl/m4/floorf.m4 b/gl/m4/floorf.m4
index c49ffa6b..2572c848 100644
--- a/gl/m4/floorf.m4
+++ b/gl/m4/floorf.m4
@@ -1,5 +1,6 @@
1# floorf.m4 serial 18 1# floorf.m4
2dnl Copyright (C) 2007, 2009-2023 Free Software Foundation, Inc. 2# serial 21
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -26,7 +27,7 @@ AC_DEFUN([gl_FUNC_FLOORF],
26 AC_CACHE_CHECK([whether floorf works according to ISO C 99 with IEC 60559], 27 AC_CACHE_CHECK([whether floorf works according to ISO C 99 with IEC 60559],
27 [gl_cv_func_floorf_ieee], 28 [gl_cv_func_floorf_ieee],
28 [ 29 [
29 save_LIBS="$LIBS" 30 saved_LIBS="$LIBS"
30 LIBS="$LIBS $FLOORF_LIBM" 31 LIBS="$LIBS $FLOORF_LIBM"
31 AC_RUN_IFELSE( 32 AC_RUN_IFELSE(
32 [AC_LANG_SOURCE([[ 33 [AC_LANG_SOURCE([[
@@ -49,17 +50,17 @@ int main (int argc, char *argv[])
49 [gl_cv_func_floorf_ieee=yes], 50 [gl_cv_func_floorf_ieee=yes],
50 [gl_cv_func_floorf_ieee=no], 51 [gl_cv_func_floorf_ieee=no],
51 [case "$host_os" in 52 [case "$host_os" in
52 # Guess yes on glibc systems. 53 # Guess yes on glibc systems.
53 *-gnu* | gnu*) gl_cv_func_floorf_ieee="guessing yes" ;; 54 *-gnu* | gnu*) gl_cv_func_floorf_ieee="guessing yes" ;;
54 # Guess yes on musl systems. 55 # Guess yes on musl systems.
55 *-musl*) gl_cv_func_floorf_ieee="guessing yes" ;; 56 *-musl* | midipix*) gl_cv_func_floorf_ieee="guessing yes" ;;
56 # Guess yes on native Windows. 57 # Guess yes on native Windows.
57 mingw*) gl_cv_func_floorf_ieee="guessing yes" ;; 58 mingw* | windows*) gl_cv_func_floorf_ieee="guessing yes" ;;
58 # If we don't know, obey --enable-cross-guesses. 59 # If we don't know, obey --enable-cross-guesses.
59 *) gl_cv_func_floorf_ieee="$gl_cross_guess_normal" ;; 60 *) gl_cv_func_floorf_ieee="$gl_cross_guess_normal" ;;
60 esac 61 esac
61 ]) 62 ])
62 LIBS="$save_LIBS" 63 LIBS="$saved_LIBS"
63 ]) 64 ])
64 case "$gl_cv_func_floorf_ieee" in 65 case "$gl_cv_func_floorf_ieee" in
65 *yes) ;; 66 *yes) ;;
@@ -94,7 +95,7 @@ AC_DEFUN([gl_FUNC_FLOORF_LIBS],
94 [[x = funcptr(x) + floorf(x);]])], 95 [[x = funcptr(x) + floorf(x);]])],
95 [gl_cv_func_floorf_libm=]) 96 [gl_cv_func_floorf_libm=])
96 if test "$gl_cv_func_floorf_libm" = "?"; then 97 if test "$gl_cv_func_floorf_libm" = "?"; then
97 save_LIBS="$LIBS" 98 saved_LIBS="$LIBS"
98 LIBS="$LIBS -lm" 99 LIBS="$LIBS -lm"
99 AC_LINK_IFELSE( 100 AC_LINK_IFELSE(
100 [AC_LANG_PROGRAM( 101 [AC_LANG_PROGRAM(
@@ -106,7 +107,7 @@ AC_DEFUN([gl_FUNC_FLOORF_LIBS],
106 float x;]], 107 float x;]],
107 [[x = funcptr(x) + floorf(x);]])], 108 [[x = funcptr(x) + floorf(x);]])],
108 [gl_cv_func_floorf_libm="-lm"]) 109 [gl_cv_func_floorf_libm="-lm"])
109 LIBS="$save_LIBS" 110 LIBS="$saved_LIBS"
110 fi 111 fi
111 ]) 112 ])
112 FLOORF_LIBM="$gl_cv_func_floorf_libm" 113 FLOORF_LIBM="$gl_cv_func_floorf_libm"
diff --git a/gl/m4/fopen.m4 b/gl/m4/fopen.m4
index 9c39ff72..f3b7aadd 100644
--- a/gl/m4/fopen.m4
+++ b/gl/m4/fopen.m4
@@ -1,15 +1,16 @@
1# fopen.m4 serial 13 1# fopen.m4
2dnl Copyright (C) 2007-2023 Free Software Foundation, Inc. 2# serial 16
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
6 7
7AC_DEFUN([gl_FUNC_FOPEN], 8AC_DEFUN([gl_FUNC_FOPEN_ITSELF],
8[ 9[
9 AC_REQUIRE([gl_STDIO_H_DEFAULTS]) 10 AC_REQUIRE([gl_STDIO_H_DEFAULTS])
10 AC_REQUIRE([AC_CANONICAL_HOST]) 11 AC_REQUIRE([AC_CANONICAL_HOST])
11 case "$host_os" in 12 case "$host_os" in
12 mingw* | pw*) 13 mingw* | windows* | pw*)
13 dnl Replace fopen, for handling of "/dev/null". 14 dnl Replace fopen, for handling of "/dev/null".
14 REPLACE_FOPEN=1 15 REPLACE_FOPEN=1
15 dnl fopen on mingw also has the trailing slash bug. 16 dnl fopen on mingw also has the trailing slash bug.
@@ -58,6 +59,15 @@ changequote([,])dnl
58 esac 59 esac
59]) 60])
60 61
62AC_DEFUN([gl_FUNC_FOPEN],
63[
64 AC_REQUIRE([gl_FUNC_FOPEN_ITSELF])
65 AC_REQUIRE([gl_FUNC_FCLOSE])
66 if test $REPLACE_FCLOSE = 1; then
67 REPLACE_FOPEN=1
68 fi
69])
70
61AC_DEFUN([gl_FUNC_FOPEN_GNU], 71AC_DEFUN([gl_FUNC_FOPEN_GNU],
62[ 72[
63 AC_REQUIRE([gl_FUNC_FOPEN]) 73 AC_REQUIRE([gl_FUNC_FOPEN])
@@ -87,7 +97,7 @@ int main ()
87 [gl_cv_func_fopen_mode_x=no], 97 [gl_cv_func_fopen_mode_x=no],
88 [case "$host_os" in 98 [case "$host_os" in
89 # Guess yes on glibc and musl systems. 99 # Guess yes on glibc and musl systems.
90 linux*-gnu* | gnu* | kfreebsd*-gnu | *-musl*) 100 linux*-gnu* | gnu* | kfreebsd*-gnu | *-musl* | midipix*)
91 gl_cv_func_fopen_mode_x="guessing yes" ;; 101 gl_cv_func_fopen_mode_x="guessing yes" ;;
92 # If we don't know, obey --enable-cross-guesses. 102 # If we don't know, obey --enable-cross-guesses.
93 *) 103 *)
@@ -124,10 +134,10 @@ int main ()
124 [gl_cv_func_fopen_mode_e=no], 134 [gl_cv_func_fopen_mode_e=no],
125 [case "$host_os" in 135 [case "$host_os" in
126 # Guess yes on glibc and musl systems. 136 # Guess yes on glibc and musl systems.
127 linux*-gnu* | gnu* | kfreebsd*-gnu | *-musl*) 137 linux*-gnu* | gnu* | kfreebsd*-gnu | *-musl* | midipix*)
128 gl_cv_func_fopen_mode_e="guessing yes" ;; 138 gl_cv_func_fopen_mode_e="guessing yes" ;;
129 # Guess no on native Windows. 139 # Guess no on native Windows.
130 mingw*) 140 mingw* | windows*)
131 gl_cv_func_fopen_mode_e="guessing no" ;; 141 gl_cv_func_fopen_mode_e="guessing no" ;;
132 # If we don't know, obey --enable-cross-guesses. 142 # If we don't know, obey --enable-cross-guesses.
133 *) 143 *)
diff --git a/gl/m4/fpurge.m4 b/gl/m4/fpurge.m4
index b365409d..a77f5b96 100644
--- a/gl/m4/fpurge.m4
+++ b/gl/m4/fpurge.m4
@@ -1,5 +1,6 @@
1# fpurge.m4 serial 12 1# fpurge.m4
2dnl Copyright (C) 2007, 2009-2023 Free Software Foundation, Inc. 2# serial 14
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -10,7 +11,7 @@ AC_DEFUN([gl_FUNC_FPURGE],
10 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles 11 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
11 AC_CHECK_HEADERS_ONCE([stdio_ext.h]) 12 AC_CHECK_HEADERS_ONCE([stdio_ext.h])
12 AC_CHECK_FUNCS_ONCE([fpurge]) 13 AC_CHECK_FUNCS_ONCE([fpurge])
13 AC_CHECK_FUNCS_ONCE([__fpurge]) 14 gl_CHECK_FUNCS_ANDROID([__fpurge], [[#include <stdio_ext.h>]])
14 AC_CHECK_DECLS([fpurge], , , [[#include <stdio.h>]]) 15 AC_CHECK_DECLS([fpurge], , , [[#include <stdio.h>]])
15 if test "x$ac_cv_func_fpurge" = xyes; then 16 if test "x$ac_cv_func_fpurge" = xyes; then
16 HAVE_FPURGE=1 17 HAVE_FPURGE=1
@@ -53,10 +54,10 @@ AC_DEFUN([gl_FUNC_FPURGE],
53 [gl_cv_func_fpurge_works=yes], 54 [gl_cv_func_fpurge_works=yes],
54 [gl_cv_func_fpurge_works=no], 55 [gl_cv_func_fpurge_works=no],
55 [case "$host_os" in 56 [case "$host_os" in
56 # Guess yes on musl systems. 57 # Guess yes on musl systems.
57 *-musl*) gl_cv_func_fpurge_works="guessing yes" ;; 58 *-musl* | midipix*) gl_cv_func_fpurge_works="guessing yes" ;;
58 # Otherwise obey --enable-cross-guesses. 59 # Otherwise obey --enable-cross-guesses.
59 *) gl_cv_func_fpurge_works="$gl_cross_guess_normal" ;; 60 *) gl_cv_func_fpurge_works="$gl_cross_guess_normal" ;;
60 esac 61 esac
61 ]) 62 ])
62 ]) 63 ])
diff --git a/gl/m4/freading.m4 b/gl/m4/freading.m4
index 35333369..be899456 100644
--- a/gl/m4/freading.m4
+++ b/gl/m4/freading.m4
@@ -1,5 +1,6 @@
1# freading.m4 serial 2 1# freading.m4
2dnl Copyright (C) 2007, 2009-2023 Free Software Foundation, Inc. 2# serial 3
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -7,5 +8,8 @@ dnl with or without modifications, as long as this notice is preserved.
7AC_DEFUN([gl_FUNC_FREADING], 8AC_DEFUN([gl_FUNC_FREADING],
8[ 9[
9 AC_CHECK_HEADERS_ONCE([stdio_ext.h]) 10 AC_CHECK_HEADERS_ONCE([stdio_ext.h])
10 AC_CHECK_FUNCS_ONCE([__freading]) 11 gl_CHECK_FUNCS_ANDROID([__freading],
12 [[#include <stdio.h>
13 #include <stdio_ext.h>
14 ]])
11]) 15])
diff --git a/gl/m4/free.m4 b/gl/m4/free.m4
index 0389dea3..a2b596d6 100644
--- a/gl/m4/free.m4
+++ b/gl/m4/free.m4
@@ -1,8 +1,9 @@
1# free.m4 serial 6 1# free.m4
2# Copyright (C) 2003-2005, 2009-2023 Free Software Foundation, Inc. 2# serial 6
3# This file is free software; the Free Software Foundation 3dnl Copyright (C) 2003-2005, 2009-2024 Free Software Foundation, Inc.
4# gives unlimited permission to copy and/or distribute it, 4dnl This file is free software; the Free Software Foundation
5# with or without modifications, as long as this notice is preserved. 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
6 7
7# Written by Paul Eggert and Bruno Haible. 8# Written by Paul Eggert and Bruno Haible.
8 9
diff --git a/gl/m4/fseek.m4 b/gl/m4/fseek.m4
index c5fe688c..fb220a1f 100644
--- a/gl/m4/fseek.m4
+++ b/gl/m4/fseek.m4
@@ -1,5 +1,6 @@
1# fseek.m4 serial 4 1# fseek.m4
2dnl Copyright (C) 2007, 2009-2023 Free Software Foundation, Inc. 2# serial 4
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/fseeko.m4 b/gl/m4/fseeko.m4
index 05ee06bc..5682a1f2 100644
--- a/gl/m4/fseeko.m4
+++ b/gl/m4/fseeko.m4
@@ -1,5 +1,6 @@
1# fseeko.m4 serial 20 1# fseeko.m4
2dnl Copyright (C) 2007-2023 Free Software Foundation, Inc. 2# serial 20
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/fstat.m4 b/gl/m4/fstat.m4
index 7cb2edb0..47777b0c 100644
--- a/gl/m4/fstat.m4
+++ b/gl/m4/fstat.m4
@@ -1,5 +1,6 @@
1# fstat.m4 serial 8 1# fstat.m4
2dnl Copyright (C) 2011-2023 Free Software Foundation, Inc. 2# serial 10
3dnl Copyright (C) 2011-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -10,10 +11,10 @@ AC_DEFUN([gl_FUNC_FSTAT],
10 AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS]) 11 AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])
11 12
12 case "$host_os" in 13 case "$host_os" in
13 mingw* | solaris*) 14 darwin* | mingw* | windows* | solaris*)
15 dnl macOS and Solaris stat can return a negative tv_nsec.
14 dnl On MinGW, the original stat() returns st_atime, st_mtime, 16 dnl On MinGW, the original stat() returns st_atime, st_mtime,
15 dnl st_ctime values that are affected by the time zone. 17 dnl st_ctime values that are affected by the time zone.
16 dnl Solaris stat can return a negative tv_nsec.
17 REPLACE_FSTAT=1 18 REPLACE_FSTAT=1
18 ;; 19 ;;
19 esac 20 esac
diff --git a/gl/m4/fstypename.m4 b/gl/m4/fstypename.m4
index f65c459f..05a68805 100644
--- a/gl/m4/fstypename.m4
+++ b/gl/m4/fstypename.m4
@@ -1,4 +1,10 @@
1#serial 6 1# fstypename.m4
2# serial 6
3dnl Copyright (C) 1998-1999, 2001, 2004, 2006, 2009-2024 Free Software
4dnl Foundation, Inc.
5dnl This file is free software; the Free Software Foundation
6dnl gives unlimited permission to copy and/or distribute it,
7dnl with or without modifications, as long as this notice is preserved.
2 8
3dnl From Jim Meyering. 9dnl From Jim Meyering.
4dnl 10dnl
@@ -6,12 +12,6 @@ dnl See if struct statfs has the f_fstypename member.
6dnl If so, define HAVE_STRUCT_STATFS_F_FSTYPENAME. 12dnl If so, define HAVE_STRUCT_STATFS_F_FSTYPENAME.
7dnl 13dnl
8 14
9# Copyright (C) 1998-1999, 2001, 2004, 2006, 2009-2023 Free Software
10# Foundation, Inc.
11# This file is free software; the Free Software Foundation
12# gives unlimited permission to copy and/or distribute it,
13# with or without modifications, as long as this notice is preserved.
14
15AC_DEFUN([gl_FSTYPENAME], 15AC_DEFUN([gl_FSTYPENAME],
16[ 16[
17 AC_CHECK_MEMBERS([struct statfs.f_fstypename],,, 17 AC_CHECK_MEMBERS([struct statfs.f_fstypename],,,
diff --git a/gl/m4/fsusage.m4 b/gl/m4/fsusage.m4
index 88f3ca81..1ce90660 100644
--- a/gl/m4/fsusage.m4
+++ b/gl/m4/fsusage.m4
@@ -1,11 +1,11 @@
1# fsusage.m4
1# serial 35 2# serial 35
2# Obtaining file system usage information. 3dnl Copyright (C) 1997-1998, 2000-2001, 2003-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.
3 7
4# Copyright (C) 1997-1998, 2000-2001, 2003-2023 Free Software Foundation, Inc. 8# Obtaining file system usage information.
5#
6# This file is free software; the Free Software Foundation
7# gives unlimited permission to copy and/or distribute it,
8# with or without modifications, as long as this notice is preserved.
9 9
10# Written by Jim Meyering. 10# Written by Jim Meyering.
11 11
@@ -269,7 +269,7 @@ int check_f_blocks_size[sizeof fsd.f_blocks * CHAR_BIT <= 32 ? -1 : 1];
269 269
270# Check for SunOS statfs brokenness wrt partitions 2GB and larger. 270# Check for SunOS statfs brokenness wrt partitions 2GB and larger.
271# If <sys/vfs.h> exists and struct statfs has a member named f_spare, 271# If <sys/vfs.h> exists and struct statfs has a member named f_spare,
272# enable the work-around code in fsusage.c. 272# enable the workaround code in fsusage.c.
273AC_DEFUN([gl_STATFS_TRUNCATES], 273AC_DEFUN([gl_STATFS_TRUNCATES],
274[ 274[
275 AC_CACHE_CHECK([for statfs that truncates block counts], 275 AC_CACHE_CHECK([for statfs that truncates block counts],
diff --git a/gl/m4/ftell.m4 b/gl/m4/ftell.m4
index 79f1aaf2..ab10736b 100644
--- a/gl/m4/ftell.m4
+++ b/gl/m4/ftell.m4
@@ -1,5 +1,6 @@
1# ftell.m4 serial 3 1# ftell.m4
2dnl Copyright (C) 2007, 2009-2023 Free Software Foundation, Inc. 2# serial 3
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/ftello.m4 b/gl/m4/ftello.m4
index 4901b168..0eb8fa0d 100644
--- a/gl/m4/ftello.m4
+++ b/gl/m4/ftello.m4
@@ -1,5 +1,6 @@
1# ftello.m4 serial 14 1# ftello.m4
2dnl Copyright (C) 2007-2023 Free Software Foundation, Inc. 2# serial 16
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -37,13 +38,24 @@ AC_DEFUN([gl_FUNC_FTELLO],
37 if test $gl_cv_var_stdin_large_offset = no; then 38 if test $gl_cv_var_stdin_large_offset = no; then
38 REPLACE_FTELLO=1 39 REPLACE_FTELLO=1
39 fi 40 fi
41 AC_REQUIRE([AC_CANONICAL_HOST])
42 if test $REPLACE_FTELLO = 0; then
43 dnl On native Windows, in some circumstances, ftell(), ftello(),
44 dnl fgetpos(), lseek(), _lseeki64() all succeed on devices of type
45 dnl FILE_TYPE_PIPE. However, to match POSIX behaviour, we want
46 dnl ftell(), ftello(), fgetpos(), lseek() to fail when the argument fd
47 dnl designates a pipe. See also
48 dnl https://github.com/python/cpython/issues/78961#issuecomment-1093800325
49 case "$host_os" in
50 mingw* | windows*) REPLACE_FTELLO=1 ;;
51 esac
52 fi
40 if test $REPLACE_FTELLO = 0; then 53 if test $REPLACE_FTELLO = 0; then
41 dnl Detect bug on Solaris. 54 dnl Detect bug on Solaris.
42 dnl ftell and ftello produce incorrect results after putc that followed a 55 dnl ftell and ftello produce incorrect results after putc that followed a
43 dnl getc call that reached EOF on Solaris. This is because the _IOREAD 56 dnl getc call that reached EOF on Solaris. This is because the _IOREAD
44 dnl flag does not get cleared in this case, even though _IOWRT gets set, 57 dnl flag does not get cleared in this case, even though _IOWRT gets set,
45 dnl and ftell and ftello look whether the _IOREAD flag is set. 58 dnl and ftell and ftello look whether the _IOREAD flag is set.
46 AC_REQUIRE([AC_CANONICAL_HOST])
47 AC_CACHE_CHECK([whether ftello works], 59 AC_CACHE_CHECK([whether ftello works],
48 [gl_cv_func_ftello_works], 60 [gl_cv_func_ftello_works],
49 [ 61 [
@@ -51,12 +63,12 @@ AC_DEFUN([gl_FUNC_FTELLO],
51 dnl be opened. 63 dnl be opened.
52changequote(,)dnl 64changequote(,)dnl
53 case "$host_os" in 65 case "$host_os" in
54 # Guess no on Solaris. 66 # Guess no on Solaris.
55 solaris*) gl_cv_func_ftello_works="guessing no" ;; 67 solaris*) gl_cv_func_ftello_works="guessing no" ;;
56 # Guess yes on native Windows. 68 # Guess yes on native Windows.
57 mingw*) gl_cv_func_ftello_works="guessing yes" ;; 69 mingw* | windows*) gl_cv_func_ftello_works="guessing yes" ;;
58 # Guess yes otherwise. 70 # Guess yes otherwise.
59 *) gl_cv_func_ftello_works="guessing yes" ;; 71 *) gl_cv_func_ftello_works="guessing yes" ;;
60 esac 72 esac
61changequote([,])dnl 73changequote([,])dnl
62 AC_RUN_IFELSE( 74 AC_RUN_IFELSE(
diff --git a/gl/m4/getaddrinfo.m4 b/gl/m4/getaddrinfo.m4
index 15f09ffb..8e209177 100644
--- a/gl/m4/getaddrinfo.m4
+++ b/gl/m4/getaddrinfo.m4
@@ -1,5 +1,6 @@
1# getaddrinfo.m4 serial 34 1# getaddrinfo.m4
2dnl Copyright (C) 2004-2023 Free Software Foundation, Inc. 2# serial 35
3dnl Copyright (C) 2004-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -41,7 +42,7 @@ AC_DEFUN([gl_GETADDRINFO],
41 AC_CACHE_CHECK([for getaddrinfo in ws2tcpip.h and -lws2_32], 42 AC_CACHE_CHECK([for getaddrinfo in ws2tcpip.h and -lws2_32],
42 gl_cv_w32_getaddrinfo, [ 43 gl_cv_w32_getaddrinfo, [
43 gl_cv_w32_getaddrinfo=no 44 gl_cv_w32_getaddrinfo=no
44 am_save_LIBS="$LIBS" 45 gl_saved_LIBS="$LIBS"
45 LIBS="$LIBS -lws2_32" 46 LIBS="$LIBS -lws2_32"
46 AC_LINK_IFELSE([AC_LANG_PROGRAM([[ 47 AC_LINK_IFELSE([AC_LANG_PROGRAM([[
47#ifdef HAVE_WS2TCPIP_H 48#ifdef HAVE_WS2TCPIP_H
@@ -49,7 +50,7 @@ AC_DEFUN([gl_GETADDRINFO],
49#endif 50#endif
50#include <stddef.h> 51#include <stddef.h>
51]], [[getaddrinfo(NULL, NULL, NULL, NULL);]])], [gl_cv_w32_getaddrinfo=yes]) 52]], [[getaddrinfo(NULL, NULL, NULL, NULL);]])], [gl_cv_w32_getaddrinfo=yes])
52 LIBS="$am_save_LIBS" 53 LIBS="$gl_saved_LIBS"
53 ]) 54 ])
54 if test "$gl_cv_w32_getaddrinfo" = "yes"; then 55 if test "$gl_cv_w32_getaddrinfo" = "yes"; then
55 GETADDRINFO_LIB="-lws2_32" 56 GETADDRINFO_LIB="-lws2_32"
diff --git a/gl/m4/getdelim.m4 b/gl/m4/getdelim.m4
index 9aaed202..61139039 100644
--- a/gl/m4/getdelim.m4
+++ b/gl/m4/getdelim.m4
@@ -1,6 +1,7 @@
1# getdelim.m4 serial 16 1# getdelim.m4
2# serial 19
2 3
3dnl Copyright (C) 2005-2007, 2009-2023 Free Software Foundation, Inc. 4dnl Copyright (C) 2005-2007, 2009-2024 Free Software Foundation, Inc.
4dnl 5dnl
5dnl This file is free software; the Free Software Foundation 6dnl This file is free software; the Free Software Foundation
6dnl gives unlimited permission to copy and/or distribute it, 7dnl gives unlimited permission to copy and/or distribute it,
@@ -18,7 +19,7 @@ AC_DEFUN([gl_FUNC_GETDELIM],
18 19
19 AC_CHECK_DECLS_ONCE([getdelim]) 20 AC_CHECK_DECLS_ONCE([getdelim])
20 21
21 AC_CHECK_FUNCS_ONCE([getdelim]) 22 gl_CHECK_FUNCS_ANDROID([getdelim], [[#include <stdio.h>]])
22 if test $ac_cv_func_getdelim = yes; then 23 if test $ac_cv_func_getdelim = yes; then
23 HAVE_GETDELIM=1 24 HAVE_GETDELIM=1
24 dnl Found it in some library. Verify that it works. 25 dnl Found it in some library. Verify that it works.
@@ -82,8 +83,8 @@ AC_DEFUN([gl_FUNC_GETDELIM],
82 ], 83 ],
83 [gl_cv_func_working_getdelim="guessing yes"], 84 [gl_cv_func_working_getdelim="guessing yes"],
84 [case "$host_os" in 85 [case "$host_os" in
85 *-musl*) gl_cv_func_working_getdelim="guessing yes" ;; 86 *-musl* | midipix*) gl_cv_func_working_getdelim="guessing yes" ;;
86 *) gl_cv_func_working_getdelim="$gl_cross_guess_normal" ;; 87 *) gl_cv_func_working_getdelim="$gl_cross_guess_normal" ;;
87 esac 88 esac
88 ]) 89 ])
89 ]) 90 ])
@@ -96,6 +97,9 @@ AC_DEFUN([gl_FUNC_GETDELIM],
96 esac 97 esac
97 else 98 else
98 HAVE_GETDELIM=0 99 HAVE_GETDELIM=0
100 case "$gl_cv_onwards_func_getdelim" in
101 future*) REPLACE_GETDELIM=1 ;;
102 esac
99 fi 103 fi
100 104
101 if test $ac_cv_have_decl_getdelim = no; then 105 if test $ac_cv_have_decl_getdelim = no; then
diff --git a/gl/m4/getdtablesize.m4 b/gl/m4/getdtablesize.m4
index 8bcda905..aaefe9b2 100644
--- a/gl/m4/getdtablesize.m4
+++ b/gl/m4/getdtablesize.m4
@@ -1,5 +1,6 @@
1# getdtablesize.m4 serial 8 1# getdtablesize.m4
2dnl Copyright (C) 2008-2023 Free Software Foundation, Inc. 2# serial 8
3dnl Copyright (C) 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/gethostname.m4 b/gl/m4/gethostname.m4
index 63f5f636..2f743b7d 100644
--- a/gl/m4/gethostname.m4
+++ b/gl/m4/gethostname.m4
@@ -1,5 +1,6 @@
1# gethostname.m4 serial 15 1# gethostname.m4
2dnl Copyright (C) 2002, 2008-2023 Free Software Foundation, Inc. 2# serial 16
3dnl Copyright (C) 2002, 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -20,7 +21,7 @@ AC_DEFUN([gl_FUNC_GETHOSTNAME],
20 AC_CACHE_CHECK([for gethostname in winsock2.h and -lws2_32], 21 AC_CACHE_CHECK([for gethostname in winsock2.h and -lws2_32],
21 [gl_cv_w32_gethostname], 22 [gl_cv_w32_gethostname],
22 [gl_cv_w32_gethostname=no 23 [gl_cv_w32_gethostname=no
23 gl_save_LIBS="$LIBS" 24 gl_saved_LIBS="$LIBS"
24 LIBS="$LIBS -lws2_32" 25 LIBS="$LIBS -lws2_32"
25 AC_LINK_IFELSE([AC_LANG_PROGRAM([[ 26 AC_LINK_IFELSE([AC_LANG_PROGRAM([[
26#ifdef HAVE_WINSOCK2_H 27#ifdef HAVE_WINSOCK2_H
@@ -28,7 +29,7 @@ AC_DEFUN([gl_FUNC_GETHOSTNAME],
28#endif 29#endif
29#include <stddef.h> 30#include <stddef.h>
30]], [[gethostname(NULL, 0);]])], [gl_cv_w32_gethostname=yes]) 31]], [[gethostname(NULL, 0);]])], [gl_cv_w32_gethostname=yes])
31 LIBS="$gl_save_LIBS" 32 LIBS="$gl_saved_LIBS"
32 ]) 33 ])
33 if test "$gl_cv_w32_gethostname" = "yes"; then 34 if test "$gl_cv_w32_gethostname" = "yes"; then
34 GETHOSTNAME_LIB="-lws2_32" 35 GETHOSTNAME_LIB="-lws2_32"
diff --git a/gl/m4/getline.m4 b/gl/m4/getline.m4
index 03569f06..36513cd4 100644
--- a/gl/m4/getline.m4
+++ b/gl/m4/getline.m4
@@ -1,6 +1,7 @@
1# getline.m4 serial 30 1# getline.m4
2# serial 33
2 3
3dnl Copyright (C) 1998-2003, 2005-2007, 2009-2023 Free Software Foundation, 4dnl Copyright (C) 1998-2003, 2005-2007, 2009-2024 Free Software Foundation,
4dnl Inc. 5dnl Inc.
5dnl 6dnl
6dnl This file is free software; the Free Software Foundation 7dnl This file is free software; the Free Software Foundation
@@ -23,12 +24,9 @@ AC_DEFUN([gl_FUNC_GETLINE],
23 24
24 AC_CHECK_DECLS_ONCE([getline]) 25 AC_CHECK_DECLS_ONCE([getline])
25 26
26 gl_getline_needs_run_time_check=no 27 gl_CHECK_FUNCS_ANDROID([getline], [[#include <stdio.h>]])
27 AC_CHECK_FUNC([getline], 28 if test $ac_cv_func_getline = yes; then
28 [dnl Found it in some library. Verify that it works. 29 dnl Found it in some library. Verify that it works.
29 gl_getline_needs_run_time_check=yes],
30 [am_cv_func_working_getline=no])
31 if test $gl_getline_needs_run_time_check = yes; then
32 AC_CACHE_CHECK([for working getline function], 30 AC_CACHE_CHECK([for working getline function],
33 [am_cv_func_working_getline], 31 [am_cv_func_working_getline],
34 [echo fooNbarN | tr -d '\012' | tr N '\012' > conftest.data 32 [echo fooNbarN | tr -d '\012' | tr N '\012' > conftest.data
@@ -79,12 +77,17 @@ AC_DEFUN([gl_FUNC_GETLINE],
79 ], 77 ],
80 [am_cv_func_working_getline="guessing yes"], 78 [am_cv_func_working_getline="guessing yes"],
81 [case "$host_os" in 79 [case "$host_os" in
82 *-musl*) am_cv_func_working_getline="guessing yes" ;; 80 *-musl* | midipix*) am_cv_func_working_getline="guessing yes" ;;
83 *) am_cv_func_working_getline="$gl_cross_guess_normal" ;; 81 *) am_cv_func_working_getline="$gl_cross_guess_normal" ;;
84 esac 82 esac
85 ]) 83 ])
86 ]) 84 ])
87 ]) 85 ])
86 else
87 am_cv_func_working_getline=no
88 case "$gl_cv_onwards_func_getline" in
89 future*) REPLACE_GETLINE=1 ;;
90 esac
88 fi 91 fi
89 92
90 if test $ac_cv_have_decl_getline = no; then 93 if test $ac_cv_have_decl_getline = no; then
diff --git a/gl/m4/getloadavg.m4 b/gl/m4/getloadavg.m4
index 79e420ba..0918bcd2 100644
--- a/gl/m4/getloadavg.m4
+++ b/gl/m4/getloadavg.m4
@@ -1,13 +1,12 @@
1# Check for getloadavg. 1# getloadavg.m4
2 2# serial 13
3# Copyright (C) 1992-1996, 1999-2000, 2002-2003, 2006, 2008-2023 Free Software 3dnl Copyright (C) 1992-1996, 1999-2000, 2002-2003, 2006, 2008-2024 Free Software
4# Foundation, Inc. 4dnl Foundation, Inc.
5dnl This file is free software; the Free Software Foundation
6dnl gives unlimited permission to copy and/or distribute it,
7dnl with or without modifications, as long as this notice is preserved.
5 8
6# This file is free software; the Free Software Foundation 9# Check for getloadavg.
7# gives unlimited permission to copy and/or distribute it,
8# with or without modifications, as long as this notice is preserved.
9
10#serial 10
11 10
12# Autoconf defines AC_FUNC_GETLOADAVG, but that is obsolescent. 11# Autoconf defines AC_FUNC_GETLOADAVG, but that is obsolescent.
13# New applications should use gl_GETLOADAVG instead. 12# New applications should use gl_GETLOADAVG instead.
@@ -20,13 +19,18 @@ AC_DEFUN([gl_GETLOADAVG],
20# Persuade glibc <stdlib.h> to declare getloadavg(). 19# Persuade glibc <stdlib.h> to declare getloadavg().
21AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) 20AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
22 21
23gl_save_LIBS=$LIBS 22gl_saved_LIBS=$LIBS
24 23
25# getloadavg is present in libc on glibc >= 2.2, Mac OS X, FreeBSD >= 2.0, 24# getloadavg is present in libc on glibc >= 2.2, Mac OS X, FreeBSD >= 2.0,
26# NetBSD >= 0.9, OpenBSD >= 2.0, Solaris >= 7. 25# NetBSD >= 0.9, OpenBSD >= 2.0, Solaris >= 7.
27HAVE_GETLOADAVG=1 26HAVE_GETLOADAVG=1
28AC_CHECK_FUNC([getloadavg], [], 27gl_CHECK_FUNCS_ANDROID([getloadavg], [[#include <stdlib.h>]])
29 [gl_func_getloadavg_done=no 28if test $ac_cv_func_getloadavg != yes; then
29 case "$gl_cv_onwards_func_getloadavg" in
30 future*) REPLACE_GETLOADAVG=1 ;;
31 esac
32
33 gl_func_getloadavg_done=no
30 34
31 # Some systems with -lutil have (and need) -lkvm as well, some do not. 35 # Some systems with -lutil have (and need) -lkvm as well, some do not.
32 # On Solaris, -lkvm requires nlist from -lelf, so check that first 36 # On Solaris, -lkvm requires nlist from -lelf, so check that first
@@ -73,14 +77,15 @@ AC_CHECK_FUNC([getloadavg], [],
73 AC_DEFINE([DGUX], [1], [Define to 1 for DGUX with <sys/dg_sys_info.h>.]) 77 AC_DEFINE([DGUX], [1], [Define to 1 for DGUX with <sys/dg_sys_info.h>.])
74 AC_CHECK_LIB([dgc], [dg_sys_info])]) 78 AC_CHECK_LIB([dgc], [dg_sys_info])])
75 fi 79 fi
76 fi]) 80 fi
81fi
77 82
78if test "x$gl_save_LIBS" = x; then 83if test "x$gl_saved_LIBS" = x; then
79 GETLOADAVG_LIBS=$LIBS 84 GETLOADAVG_LIBS=$LIBS
80else 85else
81 GETLOADAVG_LIBS=`echo "$LIBS" | sed "s!$gl_save_LIBS!!"` 86 GETLOADAVG_LIBS=`echo "$LIBS" | sed "s!$gl_saved_LIBS!!"`
82fi 87fi
83LIBS=$gl_save_LIBS 88LIBS=$gl_saved_LIBS
84 89
85AC_SUBST([GETLOADAVG_LIBS])dnl 90AC_SUBST([GETLOADAVG_LIBS])dnl
86 91
diff --git a/gl/m4/getopt.m4 b/gl/m4/getopt.m4
index 7981a095..297722ea 100644
--- a/gl/m4/getopt.m4
+++ b/gl/m4/getopt.m4
@@ -1,5 +1,6 @@
1# getopt.m4 serial 48 1# getopt.m4
2dnl Copyright (C) 2002-2006, 2008-2023 Free Software Foundation, Inc. 2# serial 49
3dnl Copyright (C) 2002-2006, 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -197,8 +198,8 @@ main ()
197 fi 198 fi
198 else 199 else
199 case "$host_os" in 200 case "$host_os" in
200 darwin* | aix* | mingw*) gl_cv_func_getopt_posix="guessing no";; 201 darwin* | aix* | mingw* | windows*) gl_cv_func_getopt_posix="guessing no";;
201 *) gl_cv_func_getopt_posix="guessing yes";; 202 *) gl_cv_func_getopt_posix="guessing yes";;
202 esac 203 esac
203 fi 204 fi
204 ]) 205 ])
diff --git a/gl/m4/getprogname.m4 b/gl/m4/getprogname.m4
index b67c527c..b24f4480 100644
--- a/gl/m4/getprogname.m4
+++ b/gl/m4/getprogname.m4
@@ -1,16 +1,33 @@
1# getprogname.m4 - check for getprogname or replacements for it 1# getprogname.m4
2# serial 8
3dnl Copyright (C) 2016-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.
2 7
3# Copyright (C) 2016-2023 Free Software Foundation, Inc. 8# Check for getprogname or replacements for it
4# This file is free software; the Free Software Foundation
5# gives unlimited permission to copy and/or distribute it,
6# with or without modifications, as long as this notice is preserved.
7
8# serial 4
9 9
10AC_DEFUN([gl_FUNC_GETPROGNAME], 10AC_DEFUN([gl_FUNC_GETPROGNAME],
11[ 11[
12 AC_CHECK_FUNCS_ONCE([getprogname getexecname]) 12 AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
13 AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
14 gl_CHECK_FUNCS_ANDROID([getprogname], [[#include <stdlib.h>]])
15 if test $ac_cv_func_getprogname = no; then
16 HAVE_GETPROGNAME=0
17 case "$gl_cv_onwards_func_getprogname" in
18 future*) REPLACE_GETPROGNAME=1 ;;
19 esac
20 fi
21 AC_CHECK_DECLS([program_invocation_name],
22 [],
23 [HAVE_DECL_PROGRAM_INVOCATION_NAME=0],
24 [[#include <errno.h>]])
25])
26
27AC_DEFUN([gl_PREREQ_GETPROGNAME],
28[
13 AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) 29 AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
30 AC_CHECK_FUNCS_ONCE([getexecname])
14 ac_found=0 31 ac_found=0
15 AC_CHECK_DECLS([program_invocation_name], [ac_found=1], [], 32 AC_CHECK_DECLS([program_invocation_name], [ac_found=1], [],
16 [#include <errno.h>]) 33 [#include <errno.h>])
diff --git a/gl/m4/gl-openssl.m4 b/gl/m4/gl-openssl.m4
index 7eab4e10..c5e1f7ba 100644
--- a/gl/m4/gl-openssl.m4
+++ b/gl/m4/gl-openssl.m4
@@ -1,5 +1,6 @@
1# gl-openssl.m4 serial 6 1# gl-openssl.m4
2dnl Copyright (C) 2013-2023 Free Software Foundation, Inc. 2# serial 7
3dnl Copyright (C) 2013-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -39,6 +40,9 @@ AC_DEFUN([gl_CRYPTO_CHECK],
39 AC_SUBST([LIB_CRYPTO]) 40 AC_SUBST([LIB_CRYPTO])
40 if test "x$with_openssl" != xno; then 41 if test "x$with_openssl" != xno; then
41 if test "x$with_openssl" = xauto-gpl-compat; then 42 if test "x$with_openssl" = xauto-gpl-compat; then
43 dnl OpenSSL versions < 3 are under the OpenSSL license, which is not
44 dnl GPL compatible.
45 dnl See <https://www.gnu.org/licenses/license-list.en.html#OpenSSL>.
42 AC_CACHE_CHECK([whether openssl is GPL compatible], 46 AC_CACHE_CHECK([whether openssl is GPL compatible],
43 [gl_cv_openssl_gpl_compat], 47 [gl_cv_openssl_gpl_compat],
44 [AC_COMPILE_IFELSE( 48 [AC_COMPILE_IFELSE(
diff --git a/gl/m4/gnulib-cache.m4 b/gl/m4/gnulib-cache.m4
index 267f0692..fcf84226 100644
--- a/gl/m4/gnulib-cache.m4
+++ b/gl/m4/gnulib-cache.m4
@@ -1,4 +1,4 @@
1# Copyright (C) 2002-2023 Free Software Foundation, Inc. 1# Copyright (C) 2002-2024 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 facc3404..cb730449 100644
--- a/gl/m4/gnulib-common.m4
+++ b/gl/m4/gnulib-common.m4
@@ -1,5 +1,6 @@
1# gnulib-common.m4 serial 75a 1# gnulib-common.m4
2dnl Copyright (C) 2007-2023 Free Software Foundation, Inc. 2# serial 93
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -15,6 +16,10 @@ AC_DEFUN([gl_COMMON], [
15 AC_REQUIRE([gl_ZZGNULIB]) 16 AC_REQUIRE([gl_ZZGNULIB])
16]) 17])
17AC_DEFUN([gl_COMMON_BODY], [ 18AC_DEFUN([gl_COMMON_BODY], [
19 AH_VERBATIM([0witness],
20[/* Witness that <config.h> has been included. */
21#define _GL_CONFIG_H_INCLUDED 1
22])
18 AH_VERBATIM([_GL_GNUC_PREREQ], 23 AH_VERBATIM([_GL_GNUC_PREREQ],
19[/* True if the compiler says it groks GNU C version MAJOR.MINOR. */ 24[/* True if the compiler says it groks GNU C version MAJOR.MINOR. */
20#if defined __GNUC__ && defined __GNUC_MINOR__ 25#if defined __GNUC__ && defined __GNUC_MINOR__
@@ -72,50 +77,74 @@ AC_DEFUN([gl_COMMON_BODY], [
72#endif]) 77#endif])
73 AH_VERBATIM([attribute], 78 AH_VERBATIM([attribute],
74[/* Attributes. */ 79[/* Attributes. */
75#if (defined __has_attribute \ 80/* Define _GL_HAS_ATTRIBUTE only once, because on FreeBSD, with gcc < 5, if
76 && (!defined __clang_minor__ \ 81 <config.h> gets included once again after <sys/cdefs.h>, __has_attribute(x)
77 || (defined __apple_build_version__ \ 82 expands to 0 always, and redefining _GL_HAS_ATTRIBUTE would turn off all
78 ? 6000000 <= __apple_build_version__ \ 83 attributes. */
79 : 3 < __clang_major__ + (5 <= __clang_minor__)))) 84#ifndef _GL_HAS_ATTRIBUTE
80# define _GL_HAS_ATTRIBUTE(attr) __has_attribute (__##attr##__) 85# if (defined __has_attribute \
81#else 86 && (!defined __clang_minor__ \
82# define _GL_HAS_ATTRIBUTE(attr) _GL_ATTR_##attr 87 || (defined __apple_build_version__ \
83# define _GL_ATTR_alloc_size _GL_GNUC_PREREQ (4, 3) 88 ? 7000000 <= __apple_build_version__ \
84# define _GL_ATTR_always_inline _GL_GNUC_PREREQ (3, 2) 89 : 5 <= __clang_major__)))
85# define _GL_ATTR_artificial _GL_GNUC_PREREQ (4, 3) 90# define _GL_HAS_ATTRIBUTE(attr) __has_attribute (__##attr##__)
86# define _GL_ATTR_cold _GL_GNUC_PREREQ (4, 3)
87# define _GL_ATTR_const _GL_GNUC_PREREQ (2, 95)
88# define _GL_ATTR_deprecated _GL_GNUC_PREREQ (3, 1)
89# define _GL_ATTR_diagnose_if 0
90# define _GL_ATTR_error _GL_GNUC_PREREQ (4, 3)
91# define _GL_ATTR_externally_visible _GL_GNUC_PREREQ (4, 1)
92# define _GL_ATTR_fallthrough _GL_GNUC_PREREQ (7, 0)
93# define _GL_ATTR_format _GL_GNUC_PREREQ (2, 7)
94# define _GL_ATTR_leaf _GL_GNUC_PREREQ (4, 6)
95# define _GL_ATTR_malloc _GL_GNUC_PREREQ (3, 0)
96# ifdef _ICC
97# define _GL_ATTR_may_alias 0
98# else 91# else
99# define _GL_ATTR_may_alias _GL_GNUC_PREREQ (3, 3) 92# define _GL_HAS_ATTRIBUTE(attr) _GL_ATTR_##attr
93# define _GL_ATTR_alloc_size _GL_GNUC_PREREQ (4, 3)
94# define _GL_ATTR_always_inline _GL_GNUC_PREREQ (3, 2)
95# define _GL_ATTR_artificial _GL_GNUC_PREREQ (4, 3)
96# define _GL_ATTR_cold _GL_GNUC_PREREQ (4, 3)
97# define _GL_ATTR_const _GL_GNUC_PREREQ (2, 95)
98# define _GL_ATTR_deprecated _GL_GNUC_PREREQ (3, 1)
99# define _GL_ATTR_diagnose_if 0
100# define _GL_ATTR_error _GL_GNUC_PREREQ (4, 3)
101# define _GL_ATTR_externally_visible _GL_GNUC_PREREQ (4, 1)
102# define _GL_ATTR_fallthrough _GL_GNUC_PREREQ (7, 0)
103# define _GL_ATTR_format _GL_GNUC_PREREQ (2, 7)
104# define _GL_ATTR_leaf _GL_GNUC_PREREQ (4, 6)
105# define _GL_ATTR_malloc _GL_GNUC_PREREQ (3, 0)
106# ifdef _ICC
107# define _GL_ATTR_may_alias 0
108# else
109# define _GL_ATTR_may_alias _GL_GNUC_PREREQ (3, 3)
110# endif
111# define _GL_ATTR_noinline _GL_GNUC_PREREQ (3, 1)
112# define _GL_ATTR_nonnull _GL_GNUC_PREREQ (3, 3)
113# define _GL_ATTR_nonstring _GL_GNUC_PREREQ (8, 0)
114# define _GL_ATTR_nothrow _GL_GNUC_PREREQ (3, 3)
115# define _GL_ATTR_packed _GL_GNUC_PREREQ (2, 7)
116# define _GL_ATTR_pure _GL_GNUC_PREREQ (2, 96)
117# define _GL_ATTR_returns_nonnull _GL_GNUC_PREREQ (4, 9)
118# define _GL_ATTR_sentinel _GL_GNUC_PREREQ (4, 0)
119# define _GL_ATTR_unused _GL_GNUC_PREREQ (2, 7)
120# define _GL_ATTR_warn_unused_result _GL_GNUC_PREREQ (3, 4)
100# endif 121# endif
101# define _GL_ATTR_noinline _GL_GNUC_PREREQ (3, 1)
102# define _GL_ATTR_nonnull _GL_GNUC_PREREQ (3, 3)
103# define _GL_ATTR_nonstring _GL_GNUC_PREREQ (8, 0)
104# define _GL_ATTR_nothrow _GL_GNUC_PREREQ (3, 3)
105# define _GL_ATTR_packed _GL_GNUC_PREREQ (2, 7)
106# define _GL_ATTR_pure _GL_GNUC_PREREQ (2, 96)
107# define _GL_ATTR_returns_nonnull _GL_GNUC_PREREQ (4, 9)
108# define _GL_ATTR_sentinel _GL_GNUC_PREREQ (4, 0)
109# define _GL_ATTR_unused _GL_GNUC_PREREQ (2, 7)
110# define _GL_ATTR_warn_unused_result _GL_GNUC_PREREQ (3, 4)
111#endif 122#endif
112 123
113/* Disable GCC -Wpedantic if using __has_c_attribute and this is not C23+. */ 124/* Use __has_c_attribute if available. However, do not use with
114#if (defined __has_c_attribute && _GL_GNUC_PREREQ (4, 6) \ 125 pre-C23 GCC, which can issue false positives if -Wpedantic. */
115 && (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) <= 201710) 126#if (defined __has_c_attribute \
116# pragma GCC diagnostic ignored "-Wpedantic" 127 && ! (_GL_GNUC_PREREQ (4, 6) \
128 && (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) <= 201710))
129# define _GL_HAVE___HAS_C_ATTRIBUTE 1
130#else
131# define _GL_HAVE___HAS_C_ATTRIBUTE 0
117#endif 132#endif
118 133
134/* Define if, in a function declaration, the attributes in bracket syntax
135 [[...]] must come before the attributes in __attribute__((...)) syntax.
136 If this is defined, it is best to avoid the bracket syntax, so that the
137 various _GL_ATTRIBUTE_* can be cumulated on the same declaration in any
138 order. */
139#ifdef __cplusplus
140# if defined __clang__
141# define _GL_BRACKET_BEFORE_ATTRIBUTE 1
142# endif
143#else
144# if defined __GNUC__ && !defined __clang__
145# define _GL_BRACKET_BEFORE_ATTRIBUTE 1
146# endif
147#endif
119]dnl There is no _GL_ATTRIBUTE_ALIGNED; use stdalign's alignas instead. 148]dnl There is no _GL_ATTRIBUTE_ALIGNED; use stdalign's alignas instead.
120[ 149[
121/* _GL_ATTRIBUTE_ALLOC_SIZE ((N)) declares that the Nth argument of the function 150/* _GL_ATTRIBUTE_ALLOC_SIZE ((N)) declares that the Nth argument of the function
@@ -223,9 +252,11 @@ AC_DEFUN([gl_COMMON_BODY], [
223 - typedef, 252 - typedef,
224 in C++ also: namespace, class, template specialization. */ 253 in C++ also: namespace, class, template specialization. */
225#ifndef _GL_ATTRIBUTE_DEPRECATED 254#ifndef _GL_ATTRIBUTE_DEPRECATED
226# ifdef __has_c_attribute 255# ifndef _GL_BRACKET_BEFORE_ATTRIBUTE
227# if __has_c_attribute (__deprecated__) 256# if _GL_HAVE___HAS_C_ATTRIBUTE
228# define _GL_ATTRIBUTE_DEPRECATED [[__deprecated__]] 257# if __has_c_attribute (__deprecated__)
258# define _GL_ATTRIBUTE_DEPRECATED [[__deprecated__]]
259# endif
229# endif 260# endif
230# endif 261# endif
231# if !defined _GL_ATTRIBUTE_DEPRECATED && _GL_HAS_ATTRIBUTE (deprecated) 262# if !defined _GL_ATTRIBUTE_DEPRECATED && _GL_HAS_ATTRIBUTE (deprecated)
@@ -271,7 +302,7 @@ AC_DEFUN([gl_COMMON_BODY], [
271/* Applies to: Empty statement (;), inside a 'switch' statement. */ 302/* Applies to: Empty statement (;), inside a 'switch' statement. */
272/* Always expands to something. */ 303/* Always expands to something. */
273#ifndef _GL_ATTRIBUTE_FALLTHROUGH 304#ifndef _GL_ATTRIBUTE_FALLTHROUGH
274# ifdef __has_c_attribute 305# if _GL_HAVE___HAS_C_ATTRIBUTE
275# if __has_c_attribute (__fallthrough__) 306# if __has_c_attribute (__fallthrough__)
276# define _GL_ATTRIBUTE_FALLTHROUGH [[__fallthrough__]] 307# define _GL_ATTRIBUTE_FALLTHROUGH [[__fallthrough__]]
277# endif 308# endif
@@ -351,11 +382,19 @@ AC_DEFUN([gl_COMMON_BODY], [
351 in C++ also: class. */ 382 in C++ also: class. */
352/* In C++ and C23, this is spelled [[__maybe_unused__]]. 383/* In C++ and C23, this is spelled [[__maybe_unused__]].
353 GCC's syntax is __attribute__ ((__unused__)). 384 GCC's syntax is __attribute__ ((__unused__)).
354 clang supports both syntaxes. */ 385 clang supports both syntaxes. Except that with clang ≥ 6, < 10, in C++ mode,
386 __has_c_attribute (__maybe_unused__) yields true but the use of
387 [[__maybe_unused__]] nevertheless produces a warning. */
355#ifndef _GL_ATTRIBUTE_MAYBE_UNUSED 388#ifndef _GL_ATTRIBUTE_MAYBE_UNUSED
356# ifdef __has_c_attribute 389# ifndef _GL_BRACKET_BEFORE_ATTRIBUTE
357# if __has_c_attribute (__maybe_unused__) 390# if defined __clang__ && defined __cplusplus
358# define _GL_ATTRIBUTE_MAYBE_UNUSED [[__maybe_unused__]] 391# if !defined __apple_build_version__ && __clang_major__ >= 10
392# define _GL_ATTRIBUTE_MAYBE_UNUSED [[__maybe_unused__]]
393# endif
394# elif _GL_HAVE___HAS_C_ATTRIBUTE
395# if __has_c_attribute (__maybe_unused__)
396# define _GL_ATTRIBUTE_MAYBE_UNUSED [[__maybe_unused__]]
397# endif
359# endif 398# endif
360# endif 399# endif
361# ifndef _GL_ATTRIBUTE_MAYBE_UNUSED 400# ifndef _GL_ATTRIBUTE_MAYBE_UNUSED
@@ -373,9 +412,20 @@ AC_DEFUN([gl_COMMON_BODY], [
373 the return value, unless the caller uses something like ignore_value. */ 412 the return value, unless the caller uses something like ignore_value. */
374/* Applies to: function, enumeration, class. */ 413/* Applies to: function, enumeration, class. */
375#ifndef _GL_ATTRIBUTE_NODISCARD 414#ifndef _GL_ATTRIBUTE_NODISCARD
376# ifdef __has_c_attribute 415# ifndef _GL_BRACKET_BEFORE_ATTRIBUTE
377# if __has_c_attribute (__nodiscard__) 416# if defined __clang__ && defined __cplusplus
378# define _GL_ATTRIBUTE_NODISCARD [[__nodiscard__]] 417 /* With clang up to 15.0.6 (at least), in C++ mode, [[__nodiscard__]] produces
418 a warning.
419 The 1000 below means a yet unknown threshold. When clang++ version X
420 starts supporting [[__nodiscard__]] without warning about it, you can
421 replace the 1000 with X. */
422# if __clang_major__ >= 1000
423# define _GL_ATTRIBUTE_NODISCARD [[__nodiscard__]]
424# endif
425# elif _GL_HAVE___HAS_C_ATTRIBUTE
426# if __has_c_attribute (__nodiscard__)
427# define _GL_ATTRIBUTE_NODISCARD [[__nodiscard__]]
428# endif
379# endif 429# endif
380# endif 430# endif
381# if !defined _GL_ATTRIBUTE_NODISCARD && _GL_HAS_ATTRIBUTE (warn_unused_result) 431# if !defined _GL_ATTRIBUTE_NODISCARD && _GL_HAS_ATTRIBUTE (warn_unused_result)
@@ -427,11 +477,25 @@ AC_DEFUN([gl_COMMON_BODY], [
427/* _GL_ATTRIBUTE_NOTHROW declares that the function does not throw exceptions. 477/* _GL_ATTRIBUTE_NOTHROW declares that the function does not throw exceptions.
428 */ 478 */
429/* Applies to: functions. */ 479/* Applies to: functions. */
480/* After a function's parameter list, this attribute must come first, before
481 other attributes. */
430#ifndef _GL_ATTRIBUTE_NOTHROW 482#ifndef _GL_ATTRIBUTE_NOTHROW
431# if _GL_HAS_ATTRIBUTE (nothrow) && !defined __cplusplus 483# if defined __cplusplus
432# define _GL_ATTRIBUTE_NOTHROW __attribute__ ((__nothrow__)) 484# if _GL_GNUC_PREREQ (2, 8) || __clang_major >= 4
485# if __cplusplus >= 201103L
486# define _GL_ATTRIBUTE_NOTHROW noexcept (true)
487# else
488# define _GL_ATTRIBUTE_NOTHROW throw ()
489# endif
490# else
491# define _GL_ATTRIBUTE_NOTHROW
492# endif
433# else 493# else
434# define _GL_ATTRIBUTE_NOTHROW 494# if _GL_HAS_ATTRIBUTE (nothrow)
495# define _GL_ATTRIBUTE_NOTHROW __attribute__ ((__nothrow__))
496# else
497# define _GL_ATTRIBUTE_NOTHROW
498# endif
435# endif 499# endif
436#endif 500#endif
437 501
@@ -441,8 +505,10 @@ AC_DEFUN([gl_COMMON_BODY], [
441 minimizing the memory required. */ 505 minimizing the memory required. */
442/* Applies to: struct members, struct, union, 506/* Applies to: struct members, struct, union,
443 in C++ also: class. */ 507 in C++ also: class. */
508/* Oracle Studio 12.6 miscompiles code with __attribute__ ((__packed__)) despite
509 __has_attribute OK. */
444#ifndef _GL_ATTRIBUTE_PACKED 510#ifndef _GL_ATTRIBUTE_PACKED
445# if _GL_HAS_ATTRIBUTE (packed) 511# if _GL_HAS_ATTRIBUTE (packed) && !defined __SUNPRO_C
446# define _GL_ATTRIBUTE_PACKED __attribute__ ((__packed__)) 512# define _GL_ATTRIBUTE_PACKED __attribute__ ((__packed__))
447# else 513# else
448# define _GL_ATTRIBUTE_PACKED 514# define _GL_ATTRIBUTE_PACKED
@@ -513,6 +579,18 @@ AC_DEFUN([gl_COMMON_BODY], [
513# endif 579# endif
514#endif 580#endif
515]) 581])
582 AH_VERBATIM([c_linkage],
583[/* In C++, there is the concept of "language linkage", that encompasses
584 name mangling and function calling conventions.
585 The following macros start and end a block of "C" linkage. */
586#ifdef __cplusplus
587# define _GL_BEGIN_C_LINKAGE extern "C" {
588# define _GL_END_C_LINKAGE }
589#else
590# define _GL_BEGIN_C_LINKAGE
591# define _GL_END_C_LINKAGE
592#endif
593])
516 AH_VERBATIM([async_safe], 594 AH_VERBATIM([async_safe],
517[/* The _GL_ASYNC_SAFE marker should be attached to functions that are 595[/* The _GL_ASYNC_SAFE marker should be attached to functions that are
518 signal handlers (for signals other than SIGABRT, SIGPIPE) or can be 596 signal handlers (for signals other than SIGABRT, SIGPIPE) or can be
@@ -568,7 +646,7 @@ AC_DEFUN([gl_COMMON_BODY], [
568 dnl gl_cross_guess_normal (to be used when 'yes' is good and 'no' is bad), 646 dnl gl_cross_guess_normal (to be used when 'yes' is good and 'no' is bad),
569 dnl gl_cross_guess_inverted (to be used when 'no' is good and 'yes' is bad). 647 dnl gl_cross_guess_inverted (to be used when 'no' is good and 'yes' is bad).
570 AC_ARG_ENABLE([cross-guesses], 648 AC_ARG_ENABLE([cross-guesses],
571 [AS_HELP_STRING([--enable-cross-guesses={conservative|risky}], 649 [AS_HELP_STRING([[--enable-cross-guesses={conservative|risky}]],
572 [specify policy for cross-compilation guesses])], 650 [specify policy for cross-compilation guesses])],
573 [if test "x$enableval" != xconservative && test "x$enableval" != xrisky; then 651 [if test "x$enableval" != xconservative && test "x$enableval" != xrisky; then
574 AC_MSG_WARN([invalid argument supplied to --enable-cross-guesses]) 652 AC_MSG_WARN([invalid argument supplied to --enable-cross-guesses])
@@ -1005,6 +1083,7 @@ AC_DEFUN([gl_CC_GNULIB_WARNINGS],
1005 dnl -Wno-pedantic >= 4.8 >= 3.9 1083 dnl -Wno-pedantic >= 4.8 >= 3.9
1006 dnl -Wno-sign-compare >= 3 >= 3.9 1084 dnl -Wno-sign-compare >= 3 >= 3.9
1007 dnl -Wno-sign-conversion >= 4.3 >= 3.9 1085 dnl -Wno-sign-conversion >= 4.3 >= 3.9
1086 dnl -Wno-tautological-out-of-range-compare - >= 3.9
1008 dnl -Wno-type-limits >= 4.3 >= 3.9 1087 dnl -Wno-type-limits >= 4.3 >= 3.9
1009 dnl -Wno-undef >= 3 >= 3.9 1088 dnl -Wno-undef >= 3 >= 3.9
1010 dnl -Wno-unsuffixed-float-constants >= 4.5 1089 dnl -Wno-unsuffixed-float-constants >= 4.5
@@ -1030,6 +1109,9 @@ AC_DEFUN([gl_CC_GNULIB_WARNINGS],
1030 #if __GNUC__ + (__GNUC_MINOR__ >= 8) > 4 || (__clang_major__ + (__clang_minor__ >= 9) > 3) 1109 #if __GNUC__ + (__GNUC_MINOR__ >= 8) > 4 || (__clang_major__ + (__clang_minor__ >= 9) > 3)
1031 -Wno-pedantic 1110 -Wno-pedantic
1032 #endif 1111 #endif
1112 #if 3 < __clang_major__ + (9 <= __clang_minor__)
1113 -Wno-tautological-constant-out-of-range-compare
1114 #endif
1033 #if __GNUC__ + (__GNUC_MINOR__ >= 3) > 4 || (__clang_major__ + (__clang_minor__ >= 9) > 3) 1115 #if __GNUC__ + (__GNUC_MINOR__ >= 3) > 4 || (__clang_major__ + (__clang_minor__ >= 9) > 3)
1034 -Wno-sign-conversion 1116 -Wno-sign-conversion
1035 -Wno-type-limits 1117 -Wno-type-limits
@@ -1080,6 +1162,238 @@ AC_DEFUN([gl_CONDITIONAL_HEADER],
1080 m4_popdef([gl_header_name]) 1162 m4_popdef([gl_header_name])
1081]) 1163])
1082 1164
1165dnl Preparations for gl_CHECK_FUNCS_MACOS.
1166AC_DEFUN([gl_PREPARE_CHECK_FUNCS_MACOS],
1167[
1168 AC_REQUIRE([AC_CANONICAL_HOST])
1169 AC_REQUIRE([gl_COMPILER_CLANG])
1170 AC_CACHE_CHECK([for compiler option needed when checking for future declarations],
1171 [gl_cv_compiler_check_future_option],
1172 [case "$host_os" in
1173 dnl This is only needed on macOS.
1174 darwin*)
1175 if test $gl_cv_compiler_clang = yes; then
1176 dnl Test whether the compiler supports the option
1177 dnl '-Werror=unguarded-availability-new'.
1178 saved_ac_compile="$ac_compile"
1179 ac_compile="$ac_compile -Werror=unguarded-availability-new"
1180 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],[[]])],
1181 [gl_cv_compiler_check_future_option='-Werror=unguarded-availability-new'],
1182 [gl_cv_compiler_check_future_option=none])
1183 ac_compile="$saved_ac_compile"
1184 else
1185 gl_cv_compiler_check_future_option=none
1186 fi
1187 ;;
1188 *) gl_cv_compiler_check_future_option=none ;;
1189 esac
1190 ])
1191])
1192
1193dnl Pieces of the expansion of
1194dnl gl_CHECK_FUNCS_ANDROID
1195dnl gl_CHECK_FUNCS_MACOS
1196dnl gl_CHECK_FUNCS_ANDROID_MACOS
1197
1198AC_DEFUN([gl_CHECK_FUNCS_DEFAULT_CASE],
1199[
1200 *)
1201 AC_CHECK_FUNC([$1])
1202 [gl_cv_onwards_func_][$1]=$[ac_cv_func_][$1]
1203 ;;
1204])
1205
1206AC_DEFUN([gl_CHECK_FUNCS_CASE_FOR_ANDROID],
1207[
1208 linux*-android*)
1209 AC_CHECK_DECL([$1], , , [$2])
1210 if test $[ac_cv_have_decl_][$1] = yes; then
1211 AC_CHECK_FUNC([[$1]])
1212 if test $[ac_cv_func_][$1] = yes; then
1213 [gl_cv_onwards_func_][$1]=yes
1214 else
1215 dnl The function is declared but does not exist. This should not
1216 dnl happen normally. But anyway, we know that a future version
1217 dnl of Android will have the function.
1218 [gl_cv_onwards_func_][$1]='future OS version'
1219 fi
1220 else
1221 [gl_cv_onwards_func_][$1]='future OS version'
1222 fi
1223 ;;
1224])
1225
1226AC_DEFUN([gl_CHECK_FUNCS_CASE_FOR_MACOS],
1227[
1228 darwin*)
1229 if test "x$gl_cv_compiler_check_future_option" != "xnone"; then
1230 dnl Use a compile test, not a link test.
1231 saved_ac_compile="$ac_compile"
1232 ac_compile="$ac_compile $gl_cv_compiler_check_future_option"
1233 saved_ac_compile_for_check_decl="$ac_compile_for_check_decl"
1234 ac_compile_for_check_decl="$ac_compile_for_check_decl $gl_cv_compiler_check_future_option"
1235 unset [ac_cv_have_decl_][$1]
1236 AC_CHECK_DECL([$1], , , [$2])
1237 ac_compile="$saved_ac_compile"
1238 ac_compile_for_check_decl="$saved_ac_compile_for_check_decl"
1239 [ac_cv_func_][$1]="$[ac_cv_have_decl_][$1]"
1240 if test $[ac_cv_func_][$1] = yes; then
1241 [gl_cv_onwards_func_][$1]=yes
1242 else
1243 unset [ac_cv_have_decl_][$1]
1244 AC_CHECK_DECL([$1], , , [$2])
1245 if test $[ac_cv_have_decl_][$1] = yes; then
1246 [gl_cv_onwards_func_][$1]='future OS version'
1247 else
1248 [gl_cv_onwards_func_][$1]=no
1249 fi
1250 fi
1251 else
1252 AC_CHECK_FUNC([$1])
1253 [gl_cv_onwards_func_][$1]=$[ac_cv_func_][$1]
1254 fi
1255 ;;
1256])
1257
1258AC_DEFUN([gl_CHECK_FUNCS_SET_RESULTS],
1259[
1260 case "$[gl_cv_onwards_func_][$1]" in
1261 future*) [ac_cv_func_][$1]=no ;;
1262 *) [ac_cv_func_][$1]=$[gl_cv_onwards_func_][$1] ;;
1263 esac
1264 if test $[ac_cv_func_][$1] = yes; then
1265 AC_DEFINE([HAVE_]m4_translit([[$1]],
1266 [abcdefghijklmnopqrstuvwxyz],
1267 [ABCDEFGHIJKLMNOPQRSTUVWXYZ]),
1268 [1], [Define to 1 if you have the `$1' function.])
1269 fi
1270])
1271
1272dnl gl_CHECK_FUNCS_ANDROID([func], [[#include <foo.h>]])
1273dnl is like AC_CHECK_FUNCS([func]), taking into account a portability problem
1274dnl on Android.
1275dnl
1276dnl When code is compiled on Android, it is in the context of a certain
1277dnl "Android API level", which indicates the minimum version of Android on
1278dnl which the app can be installed. In other words, you don't compile for a
1279dnl specific version of Android. You compile for all versions of Android,
1280dnl onwards from the given API level.
1281dnl Thus, the question "does the OS have the function func" has three possible
1282dnl answers:
1283dnl - yes, in all versions starting from the given API level,
1284dnl - no, in no version,
1285dnl - not in the given API level, but in a later version of Android.
1286dnl
1287dnl In detail, this works as follows:
1288dnl If func was added to Android API level, say, 28, then the libc.so has the
1289dnl symbol func always, whereas the header file <foo.h> declares func
1290dnl conditionally:
1291dnl #if __ANDROID_API__ >= 28
1292dnl ... func (...) __INTRODUCED_IN(28);
1293dnl #endif
1294dnl Thus, when compiling with "clang -target armv7a-unknown-linux-android28",
1295dnl the function func is declared and exists in libc.
1296dnl Whereas when compiling with "clang -target armv7a-unknown-linux-android27",
1297dnl the function func is not declared but exists in libc.
1298dnl
1299dnl This macro sets two variables:
1300dnl - gl_cv_onwards_func_<func> to yes / no / "future OS version"
1301dnl - ac_cv_func_<func> to yes / no / no
1302dnl The first variable allows to distinguish all three cases.
1303dnl The second variable is set, so that an invocation
1304dnl gl_CHECK_FUNCS_ANDROID([func], [[#include <foo.h>]])
1305dnl can be used as a drop-in replacement for
1306dnl AC_CHECK_FUNCS([func]).
1307AC_DEFUN([gl_CHECK_FUNCS_ANDROID],
1308[
1309 AC_REQUIRE([AC_CANONICAL_HOST])
1310 AC_CACHE_CHECK([for [$1]],
1311 [[gl_cv_onwards_func_][$1]],
1312 [gl_SILENT([
1313 case "$host_os" in
1314 gl_CHECK_FUNCS_CASE_FOR_ANDROID([$1], [$2])
1315 gl_CHECK_FUNCS_DEFAULT_CASE([$1])
1316 esac
1317 ])
1318 ])
1319 gl_CHECK_FUNCS_SET_RESULTS([$1])
1320])
1321
1322dnl gl_CHECK_FUNCS_MACOS([func], [[#include <foo.h>]])
1323dnl is like AC_CHECK_FUNCS([func]), taking into account a portability problem
1324dnl on macOS.
1325dnl
1326dnl When code is compiled on macOS, it is in the context of a certain minimum
1327dnl macOS version, that can be set through the option '-mmacosx-version-min='.
1328dnl In other words, you don't compile for a specific version of macOS. You
1329dnl compile for all versions of macOS, onwards from the given version.
1330dnl Thus, the question "does the OS have the function func" has three possible
1331dnl answers:
1332dnl - yes, in all versions starting from the given version,
1333dnl - no, in no version,
1334dnl - not in the given version, but in a later version of macOS.
1335dnl
1336dnl In detail, this works as follows:
1337dnl If func was added to, say, macOS version 13, then the libc has the
1338dnl symbol func always, whereas the header file <foo.h> declares func
1339dnl conditionally with a special availability attribute:
1340dnl ... func (...) __attribute__((availability(macos,introduced=13.0)));
1341dnl Thus, when compiling with "clang mmacosx-version-min=13", there is no
1342dnl warning about the use of func, and the resulting binary
1343dnl - runs fine on macOS 13,
1344dnl - aborts with a dyld "Symbol not found" message on macOS 12.
1345dnl Whereas, when compiling with "clang mmacosx-version-min=12", there is a
1346dnl warning: 'func' is only available on macOS 13.0 or newer
1347dnl [-Wunguarded-availability-new],
1348dnl and the resulting binary
1349dnl - runs fine on macOS 13,
1350dnl - crashes with a SIGSEGV (signal 11) on macOS 12.
1351dnl
1352dnl This macro sets two variables:
1353dnl - gl_cv_onwards_func_<func> to yes / no / "future OS version"
1354dnl - ac_cv_func_<func> to yes / no / no
1355dnl The first variable allows to distinguish all three cases.
1356dnl The second variable is set, so that an invocation
1357dnl gl_CHECK_FUNCS_MACOS([func], [[#include <foo.h>]])
1358dnl can be used as a drop-in replacement for
1359dnl AC_CHECK_FUNCS([func]).
1360AC_DEFUN([gl_CHECK_FUNCS_MACOS],
1361[
1362 AC_REQUIRE([AC_CANONICAL_HOST])
1363 AC_REQUIRE([gl_PREPARE_CHECK_FUNCS_MACOS])
1364 AC_CACHE_CHECK([for [$1]],
1365 [[gl_cv_onwards_func_][$1]],
1366 [gl_SILENT([
1367 case "$host_os" in
1368 gl_CHECK_FUNCS_CASE_FOR_MACOS([$1], [$2])
1369 gl_CHECK_FUNCS_DEFAULT_CASE([$1])
1370 esac
1371 ])
1372 ])
1373 gl_CHECK_FUNCS_SET_RESULTS([$1])
1374])
1375
1376dnl gl_CHECK_FUNCS_ANDROID_MACOS([func], [[#include <foo.h>]])
1377dnl is like AC_CHECK_FUNCS([func]), taking into account a portability problem
1378dnl on Android and on macOS.
1379dnl It is the combination of gl_CHECK_FUNCS_ANDROID and gl_CHECK_FUNCS_MACOS.
1380AC_DEFUN([gl_CHECK_FUNCS_ANDROID_MACOS],
1381[
1382 AC_REQUIRE([AC_CANONICAL_HOST])
1383 AC_REQUIRE([gl_PREPARE_CHECK_FUNCS_MACOS])
1384 AC_CACHE_CHECK([for [$1]],
1385 [[gl_cv_onwards_func_][$1]],
1386 [gl_SILENT([
1387 case "$host_os" in
1388 gl_CHECK_FUNCS_CASE_FOR_ANDROID([$1], [$2])
1389 gl_CHECK_FUNCS_CASE_FOR_MACOS([$1], [$2])
1390 gl_CHECK_FUNCS_DEFAULT_CASE([$1])
1391 esac
1392 ])
1393 ])
1394 gl_CHECK_FUNCS_SET_RESULTS([$1])
1395])
1396
1083dnl Expands to some code for use in .c programs that, on native Windows, defines 1397dnl Expands to some code for use in .c programs that, on native Windows, defines
1084dnl the Microsoft deprecated alias function names to the underscore-prefixed 1398dnl the Microsoft deprecated alias function names to the underscore-prefixed
1085dnl actual function names. With this macro, these function names are available 1399dnl actual function names. With this macro, these function names are available
diff --git a/gl/m4/gnulib-comp.m4 b/gl/m4/gnulib-comp.m4
index 4764622e..83a0f727 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-2023 Free Software Foundation, Inc. 2# Copyright (C) 2002-2024 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
@@ -43,6 +43,7 @@ AC_DEFUN([gl_EARLY],
43 AC_REQUIRE([gl_PROG_AR_RANLIB]) 43 AC_REQUIRE([gl_PROG_AR_RANLIB])
44 44
45 # Code from module absolute-header: 45 # Code from module absolute-header:
46 # Code from module alignasof:
46 # Code from module alloca-opt: 47 # Code from module alloca-opt:
47 # Code from module arpa_inet: 48 # Code from module arpa_inet:
48 # Code from module assert-h: 49 # Code from module assert-h:
@@ -67,6 +68,7 @@ AC_DEFUN([gl_EARLY],
67 # Code from module environ: 68 # Code from module environ:
68 # Code from module errno: 69 # Code from module errno:
69 # Code from module error: 70 # Code from module error:
71 # Code from module error-h:
70 # Code from module exitfail: 72 # Code from module exitfail:
71 # Code from module extensions: 73 # Code from module extensions:
72 # Code from module extern-inline: 74 # Code from module extern-inline:
@@ -112,6 +114,11 @@ AC_DEFUN([gl_EARLY],
112 # Code from module inet_ntop: 114 # Code from module inet_ntop:
113 # Code from module intprops: 115 # Code from module intprops:
114 # Code from module inttypes-incomplete: 116 # Code from module inttypes-incomplete:
117 # Code from module iswblank:
118 # Code from module iswctype:
119 # Code from module iswdigit:
120 # Code from module iswpunct:
121 # Code from module iswxdigit:
115 # Code from module langinfo: 122 # Code from module langinfo:
116 # Code from module largefile: 123 # Code from module largefile:
117 AC_REQUIRE([AC_SYS_LARGEFILE]) 124 AC_REQUIRE([AC_SYS_LARGEFILE])
@@ -128,6 +135,7 @@ AC_DEFUN([gl_EARLY],
128 # Code from module math: 135 # Code from module math:
129 # Code from module mbrtowc: 136 # Code from module mbrtowc:
130 # Code from module mbsinit: 137 # Code from module mbsinit:
138 # Code from module mbszero:
131 # Code from module mbtowc: 139 # Code from module mbtowc:
132 # Code from module memchr: 140 # Code from module memchr:
133 # Code from module minmax: 141 # Code from module minmax:
@@ -150,6 +158,7 @@ AC_DEFUN([gl_EARLY],
150 # Code from module servent: 158 # Code from module servent:
151 # Code from module setenv: 159 # Code from module setenv:
152 # Code from module setlocale-null: 160 # Code from module setlocale-null:
161 # Code from module setlocale-null-unlocked:
153 # Code from module size_max: 162 # Code from module size_max:
154 # Code from module snippet/_Noreturn: 163 # Code from module snippet/_Noreturn:
155 # Code from module snippet/arg-nonnull: 164 # Code from module snippet/arg-nonnull:
@@ -163,12 +172,12 @@ AC_DEFUN([gl_EARLY],
163 # Code from module stat: 172 # Code from module stat:
164 # Code from module stat-time: 173 # Code from module stat-time:
165 # Code from module std-gnu11: 174 # Code from module std-gnu11:
166 # Code from module stdalign:
167 # Code from module stdbool: 175 # Code from module stdbool:
168 # Code from module stdckdint: 176 # Code from module stdckdint:
169 # Code from module stddef: 177 # Code from module stddef:
170 # Code from module stdint: 178 # Code from module stdint:
171 # Code from module stdio: 179 # Code from module stdio:
180 gl_STDIO_H_EARLY
172 # Code from module stdlib: 181 # Code from module stdlib:
173 # Code from module strcase: 182 # Code from module strcase:
174 # Code from module strcasestr: 183 # Code from module strcasestr:
@@ -186,7 +195,7 @@ AC_DEFUN([gl_EARLY],
186 # Code from module sys_uio: 195 # Code from module sys_uio:
187 # Code from module threadlib: 196 # Code from module threadlib:
188 gl_THREADLIB_EARLY 197 gl_THREADLIB_EARLY
189 # Code from module time: 198 # Code from module time-h:
190 # Code from module time_r: 199 # Code from module time_r:
191 # Code from module timegm: 200 # Code from module timegm:
192 # Code from module unistd: 201 # Code from module unistd:
@@ -199,6 +208,7 @@ AC_DEFUN([gl_EARLY],
199 # Code from module vsnprintf: 208 # Code from module vsnprintf:
200 # Code from module wchar: 209 # Code from module wchar:
201 # Code from module wcrtomb: 210 # Code from module wcrtomb:
211 # Code from module wctype:
202 # Code from module wctype-h: 212 # Code from module wctype-h:
203 # Code from module windows-mutex: 213 # Code from module windows-mutex:
204 # Code from module windows-once: 214 # Code from module windows-once:
@@ -229,6 +239,7 @@ AC_DEFUN([gl_INIT],
229 gl_COMMON 239 gl_COMMON
230 gl_source_base='gl' 240 gl_source_base='gl'
231 gl_source_base_prefix= 241 gl_source_base_prefix=
242 gl_ALIGNASOF
232 gl_FUNC_ALLOCA 243 gl_FUNC_ALLOCA
233 gl_CONDITIONAL_HEADER([alloca.h]) 244 gl_CONDITIONAL_HEADER([alloca.h])
234 AC_PROG_MKDIR_P 245 AC_PROG_MKDIR_P
@@ -280,14 +291,17 @@ AC_DEFUN([gl_INIT],
280 gl_HEADER_ERRNO_H 291 gl_HEADER_ERRNO_H
281 gl_CONDITIONAL_HEADER([errno.h]) 292 gl_CONDITIONAL_HEADER([errno.h])
282 AC_PROG_MKDIR_P 293 AC_PROG_MKDIR_P
294 AC_REQUIRE([gl_ERROR_H])
283 gl_ERROR 295 gl_ERROR
284 gl_CONDITIONAL([GL_COND_OBJ_ERROR], [test "$ac_cv_lib_error_at_line" = no]) 296 gl_CONDITIONAL([GL_COND_OBJ_ERROR], [test $COMPILE_ERROR_C = 1])
285 AM_COND_IF([GL_COND_OBJ_ERROR], [ 297 AM_COND_IF([GL_COND_OBJ_ERROR], [
286 gl_PREREQ_ERROR 298 gl_PREREQ_ERROR
287 ]) 299 ])
288 m4_ifdef([AM_XGETTEXT_OPTION], 300 m4_ifdef([AM_XGETTEXT_OPTION],
289 [AM_][XGETTEXT_OPTION([--flag=error:3:c-format]) 301 [AM_][XGETTEXT_OPTION([--flag=error:3:c-format])
290 AM_][XGETTEXT_OPTION([--flag=error_at_line:5:c-format])]) 302 AM_][XGETTEXT_OPTION([--flag=error_at_line:5:c-format])])
303 gl_ERROR_H
304 AC_PROG_MKDIR_P
291 AC_REQUIRE([gl_EXTERN_INLINE]) 305 AC_REQUIRE([gl_EXTERN_INLINE])
292 gl_FUNC_FCNTL 306 gl_FUNC_FCNTL
293 gl_CONDITIONAL([GL_COND_OBJ_FCNTL], 307 gl_CONDITIONAL([GL_COND_OBJ_FCNTL],
@@ -350,7 +364,7 @@ AC_DEFUN([gl_INIT],
350 gl_CONDITIONAL([GL_COND_OBJ_FSTAT], [test $REPLACE_FSTAT = 1]) 364 gl_CONDITIONAL([GL_COND_OBJ_FSTAT], [test $REPLACE_FSTAT = 1])
351 AM_COND_IF([GL_COND_OBJ_FSTAT], [ 365 AM_COND_IF([GL_COND_OBJ_FSTAT], [
352 case "$host_os" in 366 case "$host_os" in
353 mingw*) 367 mingw* | windows*)
354 AC_LIBOBJ([stat-w32]) 368 AC_LIBOBJ([stat-w32])
355 ;; 369 ;;
356 esac 370 esac
@@ -406,7 +420,8 @@ AC_DEFUN([gl_INIT],
406 gl_STDIO_MODULE_INDICATOR([getline]) 420 gl_STDIO_MODULE_INDICATOR([getline])
407 AC_REQUIRE([AC_CANONICAL_HOST]) 421 AC_REQUIRE([AC_CANONICAL_HOST])
408 gl_GETLOADAVG 422 gl_GETLOADAVG
409 gl_CONDITIONAL([GL_COND_OBJ_GETLOADAVG], [test $HAVE_GETLOADAVG = 0]) 423 gl_CONDITIONAL([GL_COND_OBJ_GETLOADAVG],
424 [test $HAVE_GETLOADAVG = 0 || test $REPLACE_GETLOADAVG = 1])
410 AM_COND_IF([GL_COND_OBJ_GETLOADAVG], [ 425 AM_COND_IF([GL_COND_OBJ_GETLOADAVG], [
411 gl_PREREQ_GETLOADAVG 426 gl_PREREQ_GETLOADAVG
412 ]) 427 ])
@@ -427,11 +442,20 @@ AC_DEFUN([gl_INIT],
427 ]) 442 ])
428 gl_UNISTD_MODULE_INDICATOR([getopt-posix]) 443 gl_UNISTD_MODULE_INDICATOR([getopt-posix])
429 gl_FUNC_GETPROGNAME 444 gl_FUNC_GETPROGNAME
445 gl_CONDITIONAL([GL_COND_OBJ_GETPROGNAME],
446 [test $HAVE_GETPROGNAME = 0 || test $REPLACE_GETPROGNAME = 1])
447 AM_COND_IF([GL_COND_OBJ_GETPROGNAME], [
448 gl_PREREQ_GETPROGNAME
449 ])
450 gl_STDLIB_MODULE_INDICATOR([getprogname])
430 AC_SUBST([LIBINTL]) 451 AC_SUBST([LIBINTL])
431 AC_SUBST([LTLIBINTL]) 452 AC_SUBST([LTLIBINTL])
432 AC_PROG_MKDIR_P 453 AC_PROG_MKDIR_P
433 AC_REQUIRE([gl_FUNC_SETLOCALE_NULL]) 454 AC_REQUIRE([gl_FUNC_SETLOCALE_NULL])
434 LIB_HARD_LOCALE="$LIB_SETLOCALE_NULL" 455 HARD_LOCALE_LIB="$SETLOCALE_NULL_LIB"
456 AC_SUBST([HARD_LOCALE_LIB])
457 dnl For backward compatibility.
458 LIB_HARD_LOCALE="$HARD_LOCALE_LIB"
435 AC_SUBST([LIB_HARD_LOCALE]) 459 AC_SUBST([LIB_HARD_LOCALE])
436 gl_HOSTENT 460 gl_HOSTENT
437 gl_IDPRIV 461 gl_IDPRIV
@@ -445,6 +469,26 @@ AC_DEFUN([gl_INIT],
445 gl_INTTYPES_INCOMPLETE 469 gl_INTTYPES_INCOMPLETE
446 gl_INTTYPES_H_REQUIRE_DEFAULTS 470 gl_INTTYPES_H_REQUIRE_DEFAULTS
447 AC_PROG_MKDIR_P 471 AC_PROG_MKDIR_P
472 gl_FUNC_ISWBLANK
473 gl_CONDITIONAL([GL_COND_OBJ_ISWBLANK],
474 [! { test $HAVE_ISWCNTRL = 0 || test $REPLACE_ISWCNTRL = 1; } && { test $HAVE_ISWBLANK = 0 || test $REPLACE_ISWBLANK = 1; }])
475 gl_WCTYPE_MODULE_INDICATOR([iswblank])
476 gl_FUNC_ISWCTYPE
477 gl_CONDITIONAL([GL_COND_OBJ_ISWCTYPE],
478 [test $HAVE_WCTYPE_T = 0 || test $GNULIBHEADERS_OVERRIDE_WINT_T = 1 || test $REPLACE_WCTYPE = 1])
479 gl_WCTYPE_MODULE_INDICATOR([iswctype])
480 gl_FUNC_ISWDIGIT
481 gl_CONDITIONAL([GL_COND_OBJ_ISWDIGIT],
482 [! { test $HAVE_ISWCNTRL = 0 || test $REPLACE_ISWCNTRL = 1; } && test $REPLACE_ISWDIGIT = 1])
483 gl_WCTYPE_MODULE_INDICATOR([iswdigit])
484 gl_FUNC_ISWPUNCT
485 gl_CONDITIONAL([GL_COND_OBJ_ISWPUNCT],
486 [! { test $HAVE_ISWCNTRL = 0 || test $REPLACE_ISWCNTRL = 1; } && test $REPLACE_ISWPUNCT = 1])
487 gl_WCTYPE_MODULE_INDICATOR([iswpunct])
488 gl_FUNC_ISWXDIGIT
489 gl_CONDITIONAL([GL_COND_OBJ_ISWXDIGIT],
490 [! { test $HAVE_ISWCNTRL = 0 || test $REPLACE_ISWCNTRL = 1; } && test $REPLACE_ISWXDIGIT = 1])
491 gl_WCTYPE_MODULE_INDICATOR([iswxdigit])
448 gl_LANGINFO_H 492 gl_LANGINFO_H
449 gl_LANGINFO_H_REQUIRE_DEFAULTS 493 gl_LANGINFO_H_REQUIRE_DEFAULTS
450 AC_PROG_MKDIR_P 494 AC_PROG_MKDIR_P
@@ -504,6 +548,10 @@ AC_DEFUN([gl_INIT],
504 gl_PREREQ_MBSINIT 548 gl_PREREQ_MBSINIT
505 ]) 549 ])
506 gl_WCHAR_MODULE_INDICATOR([mbsinit]) 550 gl_WCHAR_MODULE_INDICATOR([mbsinit])
551 AC_REQUIRE([AC_TYPE_MBSTATE_T])
552 gl_MBSTATE_T_BROKEN
553 gl_MUSL_LIBC
554 gl_WCHAR_MODULE_INDICATOR([mbszero])
507 gl_FUNC_MBTOWC 555 gl_FUNC_MBTOWC
508 gl_CONDITIONAL([GL_COND_OBJ_MBTOWC], 556 gl_CONDITIONAL([GL_COND_OBJ_MBTOWC],
509 [test $HAVE_MBTOWC = 0 || test $REPLACE_MBTOWC = 1]) 557 [test $HAVE_MBTOWC = 0 || test $REPLACE_MBTOWC = 1])
@@ -611,7 +659,7 @@ AC_DEFUN([gl_INIT],
611 gl_CONDITIONAL([GL_COND_OBJ_STAT], [test $REPLACE_STAT = 1]) 659 gl_CONDITIONAL([GL_COND_OBJ_STAT], [test $REPLACE_STAT = 1])
612 AM_COND_IF([GL_COND_OBJ_STAT], [ 660 AM_COND_IF([GL_COND_OBJ_STAT], [
613 case "$host_os" in 661 case "$host_os" in
614 mingw*) 662 mingw* | windows*)
615 AC_LIBOBJ([stat-w32]) 663 AC_LIBOBJ([stat-w32])
616 ;; 664 ;;
617 esac 665 esac
@@ -620,9 +668,6 @@ AC_DEFUN([gl_INIT],
620 gl_SYS_STAT_MODULE_INDICATOR([stat]) 668 gl_SYS_STAT_MODULE_INDICATOR([stat])
621 gl_STAT_TIME 669 gl_STAT_TIME
622 gl_STAT_BIRTHTIME 670 gl_STAT_BIRTHTIME
623 gl_STDALIGN_H
624 gl_CONDITIONAL_HEADER([stdalign.h])
625 AC_PROG_MKDIR_P
626 gl_C_BOOL 671 gl_C_BOOL
627 AC_CHECK_HEADERS_ONCE([stdckdint.h]) 672 AC_CHECK_HEADERS_ONCE([stdckdint.h])
628 if test $ac_cv_header_stdckdint_h = yes; then 673 if test $ac_cv_header_stdckdint_h = yes; then
@@ -781,21 +826,24 @@ AC_DEFUN([gl_INIT],
781 gl_PREREQ_WCRTOMB 826 gl_PREREQ_WCRTOMB
782 ]) 827 ])
783 gl_WCHAR_MODULE_INDICATOR([wcrtomb]) 828 gl_WCHAR_MODULE_INDICATOR([wcrtomb])
829 gl_FUNC_WCTYPE
830 gl_CONDITIONAL([GL_COND_OBJ_WCTYPE], [test $HAVE_WCTYPE = 0 || test $REPLACE_WCTYPE = 1])
831 gl_WCTYPE_MODULE_INDICATOR([wctype])
784 gl_WCTYPE_H 832 gl_WCTYPE_H
785 gl_WCTYPE_H_REQUIRE_DEFAULTS 833 gl_WCTYPE_H_REQUIRE_DEFAULTS
786 AC_PROG_MKDIR_P 834 AC_PROG_MKDIR_P
787 AC_REQUIRE([AC_CANONICAL_HOST]) 835 AC_REQUIRE([AC_CANONICAL_HOST])
788 gl_CONDITIONAL([GL_COND_OBJ_WINDOWS_MUTEX], 836 gl_CONDITIONAL([GL_COND_OBJ_WINDOWS_MUTEX],
789 [case "$host_os" in mingw*) true;; *) false;; esac]) 837 [case "$host_os" in mingw* | windows*) true;; *) false;; esac])
790 AC_REQUIRE([AC_CANONICAL_HOST]) 838 AC_REQUIRE([AC_CANONICAL_HOST])
791 gl_CONDITIONAL([GL_COND_OBJ_WINDOWS_ONCE], 839 gl_CONDITIONAL([GL_COND_OBJ_WINDOWS_ONCE],
792 [case "$host_os" in mingw*) true;; *) false;; esac]) 840 [case "$host_os" in mingw* | windows*) true;; *) false;; esac])
793 AC_REQUIRE([AC_CANONICAL_HOST]) 841 AC_REQUIRE([AC_CANONICAL_HOST])
794 gl_CONDITIONAL([GL_COND_OBJ_WINDOWS_RECMUTEX], 842 gl_CONDITIONAL([GL_COND_OBJ_WINDOWS_RECMUTEX],
795 [case "$host_os" in mingw*) true;; *) false;; esac]) 843 [case "$host_os" in mingw* | windows*) true;; *) false;; esac])
796 AC_REQUIRE([AC_CANONICAL_HOST]) 844 AC_REQUIRE([AC_CANONICAL_HOST])
797 gl_CONDITIONAL([GL_COND_OBJ_WINDOWS_RWLOCK], 845 gl_CONDITIONAL([GL_COND_OBJ_WINDOWS_RWLOCK],
798 [case "$host_os" in mingw*) true;; *) false;; esac]) 846 [case "$host_os" in mingw* | windows*) true;; *) false;; esac])
799 gl_XALLOC 847 gl_XALLOC
800 gl_MODULE_INDICATOR([xalloc]) 848 gl_MODULE_INDICATOR([xalloc])
801 gl_MODULE_INDICATOR([xalloc-die]) 849 gl_MODULE_INDICATOR([xalloc-die])
@@ -1002,7 +1050,7 @@ AC_DEFUN([gl_FILE_LIST], [
1002 lib/dynarray.h 1050 lib/dynarray.h
1003 lib/errno.in.h 1051 lib/errno.in.h
1004 lib/error.c 1052 lib/error.c
1005 lib/error.h 1053 lib/error.in.h
1006 lib/exitfail.c 1054 lib/exitfail.c
1007 lib/exitfail.h 1055 lib/exitfail.h
1008 lib/fcntl.c 1056 lib/fcntl.c
@@ -1062,6 +1110,12 @@ AC_DEFUN([gl_FILE_LIST], [
1062 lib/intprops-internal.h 1110 lib/intprops-internal.h
1063 lib/intprops.h 1111 lib/intprops.h
1064 lib/inttypes.in.h 1112 lib/inttypes.in.h
1113 lib/iswblank.c
1114 lib/iswctype-impl.h
1115 lib/iswctype.c
1116 lib/iswdigit.c
1117 lib/iswpunct.c
1118 lib/iswxdigit.c
1065 lib/itold.c 1119 lib/itold.c
1066 lib/langinfo.in.h 1120 lib/langinfo.in.h
1067 lib/lc-charset-dispatch.c 1121 lib/lc-charset-dispatch.c
@@ -1089,6 +1143,7 @@ AC_DEFUN([gl_FILE_LIST], [
1089 lib/mbrtowc-impl.h 1143 lib/mbrtowc-impl.h
1090 lib/mbrtowc.c 1144 lib/mbrtowc.c
1091 lib/mbsinit.c 1145 lib/mbsinit.c
1146 lib/mbszero.c
1092 lib/mbtowc-impl.h 1147 lib/mbtowc-impl.h
1093 lib/mbtowc-lock.c 1148 lib/mbtowc-lock.c
1094 lib/mbtowc-lock.h 1149 lib/mbtowc-lock.h
@@ -1124,6 +1179,7 @@ AC_DEFUN([gl_FILE_LIST], [
1124 lib/regexec.c 1179 lib/regexec.c
1125 lib/setenv.c 1180 lib/setenv.c
1126 lib/setlocale-lock.c 1181 lib/setlocale-lock.c
1182 lib/setlocale_null-unlocked.c
1127 lib/setlocale_null.c 1183 lib/setlocale_null.c
1128 lib/setlocale_null.h 1184 lib/setlocale_null.h
1129 lib/sha256-stream.c 1185 lib/sha256-stream.c
@@ -1138,7 +1194,6 @@ AC_DEFUN([gl_FILE_LIST], [
1138 lib/stat-w32.c 1194 lib/stat-w32.c
1139 lib/stat-w32.h 1195 lib/stat-w32.h
1140 lib/stat.c 1196 lib/stat.c
1141 lib/stdalign.in.h
1142 lib/stdckdint.in.h 1197 lib/stdckdint.in.h
1143 lib/stddef.in.h 1198 lib/stddef.in.h
1144 lib/stdint.in.h 1199 lib/stdint.in.h
@@ -1183,6 +1238,8 @@ AC_DEFUN([gl_FILE_LIST], [
1183 lib/wchar.in.h 1238 lib/wchar.in.h
1184 lib/wcrtomb.c 1239 lib/wcrtomb.c
1185 lib/wctype-h.c 1240 lib/wctype-h.c
1241 lib/wctype-impl.h
1242 lib/wctype.c
1186 lib/wctype.in.h 1243 lib/wctype.in.h
1187 lib/windows-initguard.h 1244 lib/windows-initguard.h
1188 lib/windows-mutex.c 1245 lib/windows-mutex.c
@@ -1220,9 +1277,11 @@ AC_DEFUN([gl_FILE_LIST], [
1220 m4/environ.m4 1277 m4/environ.m4
1221 m4/errno_h.m4 1278 m4/errno_h.m4
1222 m4/error.m4 1279 m4/error.m4
1280 m4/error_h.m4
1223 m4/exponentd.m4 1281 m4/exponentd.m4
1224 m4/extensions.m4 1282 m4/extensions.m4
1225 m4/extern-inline.m4 1283 m4/extern-inline.m4
1284 m4/fclose.m4
1226 m4/fcntl-o.m4 1285 m4/fcntl-o.m4
1227 m4/fcntl.m4 1286 m4/fcntl.m4
1228 m4/fcntl_h.m4 1287 m4/fcntl_h.m4
@@ -1257,6 +1316,11 @@ AC_DEFUN([gl_FILE_LIST], [
1257 m4/intmax_t.m4 1316 m4/intmax_t.m4
1258 m4/inttypes.m4 1317 m4/inttypes.m4
1259 m4/inttypes_h.m4 1318 m4/inttypes_h.m4
1319 m4/iswblank.m4
1320 m4/iswctype.m4
1321 m4/iswdigit.m4
1322 m4/iswpunct.m4
1323 m4/iswxdigit.m4
1260 m4/langinfo_h.m4 1324 m4/langinfo_h.m4
1261 m4/largefile.m4 1325 m4/largefile.m4
1262 m4/limits-h.m4 1326 m4/limits-h.m4
@@ -1284,6 +1348,7 @@ AC_DEFUN([gl_FILE_LIST], [
1284 m4/msvc-inval.m4 1348 m4/msvc-inval.m4
1285 m4/msvc-nothrow.m4 1349 m4/msvc-nothrow.m4
1286 m4/multiarch.m4 1350 m4/multiarch.m4
1351 m4/musl.m4
1287 m4/netdb_h.m4 1352 m4/netdb_h.m4
1288 m4/netinet_in_h.m4 1353 m4/netinet_in_h.m4
1289 m4/nl_langinfo.m4 1354 m4/nl_langinfo.m4
@@ -1346,6 +1411,7 @@ AC_DEFUN([gl_FILE_LIST], [
1346 m4/wchar_h.m4 1411 m4/wchar_h.m4
1347 m4/wchar_t.m4 1412 m4/wchar_t.m4
1348 m4/wcrtomb.m4 1413 m4/wcrtomb.m4
1414 m4/wctype.m4
1349 m4/wctype_h.m4 1415 m4/wctype_h.m4
1350 m4/wint_t.m4 1416 m4/wint_t.m4
1351 m4/xalloc.m4 1417 m4/xalloc.m4
diff --git a/gl/m4/gnulib-tool.m4 b/gl/m4/gnulib-tool.m4
index a9dd569b..ef45f51f 100644
--- a/gl/m4/gnulib-tool.m4
+++ b/gl/m4/gnulib-tool.m4
@@ -1,5 +1,6 @@
1# gnulib-tool.m4 serial 4 1# gnulib-tool.m4
2dnl Copyright (C) 2004-2005, 2009-2023 Free Software Foundation, Inc. 2# serial 4
3dnl Copyright (C) 2004-2005, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/hostent.m4 b/gl/m4/hostent.m4
index 3b2cc2b2..36dc636e 100644
--- a/gl/m4/hostent.m4
+++ b/gl/m4/hostent.m4
@@ -1,5 +1,6 @@
1# hostent.m4 serial 4 1# hostent.m4
2dnl Copyright (C) 2008, 2010-2023 Free Software Foundation, Inc. 2# serial 5
3dnl Copyright (C) 2008, 2010-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -26,7 +27,7 @@ AC_DEFUN([gl_HOSTENT],
26 AC_CACHE_CHECK([for gethostbyname in winsock2.h and -lws2_32], 27 AC_CACHE_CHECK([for gethostbyname in winsock2.h and -lws2_32],
27 [gl_cv_w32_gethostbyname], 28 [gl_cv_w32_gethostbyname],
28 [gl_cv_w32_gethostbyname=no 29 [gl_cv_w32_gethostbyname=no
29 gl_save_LIBS="$LIBS" 30 gl_saved_LIBS="$LIBS"
30 LIBS="$LIBS -lws2_32" 31 LIBS="$LIBS -lws2_32"
31 AC_LINK_IFELSE( 32 AC_LINK_IFELSE(
32 [AC_LANG_PROGRAM( 33 [AC_LANG_PROGRAM(
@@ -38,7 +39,7 @@ AC_DEFUN([gl_HOSTENT],
38 ]], 39 ]],
39 [[gethostbyname(NULL);]])], 40 [[gethostbyname(NULL);]])],
40 [gl_cv_w32_gethostbyname=yes]) 41 [gl_cv_w32_gethostbyname=yes])
41 LIBS="$gl_save_LIBS" 42 LIBS="$gl_saved_LIBS"
42 ]) 43 ])
43 if test "$gl_cv_w32_gethostbyname" = "yes"; then 44 if test "$gl_cv_w32_gethostbyname" = "yes"; then
44 HOSTENT_LIB="-lws2_32" 45 HOSTENT_LIB="-lws2_32"
diff --git a/gl/m4/idpriv.m4 b/gl/m4/idpriv.m4
index fc3dd17d..53693527 100644
--- a/gl/m4/idpriv.m4
+++ b/gl/m4/idpriv.m4
@@ -1,5 +1,6 @@
1# idpriv.m4 serial 1 1# idpriv.m4
2dnl Copyright (C) 2009-2023 Free Software Foundation, Inc. 2# serial 1
3dnl Copyright (C) 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/include_next.m4 b/gl/m4/include_next.m4
index 9f19215e..03e85251 100644
--- a/gl/m4/include_next.m4
+++ b/gl/m4/include_next.m4
@@ -1,5 +1,6 @@
1# include_next.m4 serial 26 1# include_next.m4
2dnl Copyright (C) 2006-2023 Free Software Foundation, Inc. 2# serial 27
3dnl Copyright (C) 2006-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -74,17 +75,17 @@ EOF
74#endif 75#endif
75#define DEFINED_IN_CONFTESTD2 76#define DEFINED_IN_CONFTESTD2
76EOF 77EOF
77 gl_save_CPPFLAGS="$CPPFLAGS" 78 gl_saved_CPPFLAGS="$CPPFLAGS"
78 CPPFLAGS="$gl_save_CPPFLAGS -Iconftestd1b -Iconftestd2" 79 CPPFLAGS="$gl_saved_CPPFLAGS -Iconftestd1b -Iconftestd2"
79dnl We intentionally avoid using AC_LANG_SOURCE here. 80dnl We intentionally avoid using AC_LANG_SOURCE here.
80 AC_COMPILE_IFELSE([AC_LANG_DEFINES_PROVIDED[#include <conftest.h>]], 81 AC_COMPILE_IFELSE([AC_LANG_DEFINES_PROVIDED[#include <conftest.h>]],
81 [gl_cv_have_include_next=yes], 82 [gl_cv_have_include_next=yes],
82 [CPPFLAGS="$gl_save_CPPFLAGS -Iconftestd1a -Iconftestd2" 83 [CPPFLAGS="$gl_saved_CPPFLAGS -Iconftestd1a -Iconftestd2"
83 AC_COMPILE_IFELSE([AC_LANG_DEFINES_PROVIDED[#include <conftest.h>]], 84 AC_COMPILE_IFELSE([AC_LANG_DEFINES_PROVIDED[#include <conftest.h>]],
84 [gl_cv_have_include_next=buggy], 85 [gl_cv_have_include_next=buggy],
85 [gl_cv_have_include_next=no]) 86 [gl_cv_have_include_next=no])
86 ]) 87 ])
87 CPPFLAGS="$gl_save_CPPFLAGS" 88 CPPFLAGS="$gl_saved_CPPFLAGS"
88 rm -rf conftestd1a conftestd1b conftestd2 89 rm -rf conftestd1a conftestd1b conftestd2
89 ]) 90 ])
90 PRAGMA_SYSTEM_HEADER= 91 PRAGMA_SYSTEM_HEADER=
diff --git a/gl/m4/inet_ntop.m4 b/gl/m4/inet_ntop.m4
index 48822d69..168e17e0 100644
--- a/gl/m4/inet_ntop.m4
+++ b/gl/m4/inet_ntop.m4
@@ -1,5 +1,6 @@
1# inet_ntop.m4 serial 21 1# inet_ntop.m4
2dnl Copyright (C) 2005-2006, 2008-2023 Free Software Foundation, Inc. 2# serial 22
3dnl Copyright (C) 2005-2006, 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -36,14 +37,14 @@ AC_DEFUN([gl_FUNC_INET_NTOP],
36 HAVE_DECL_INET_NTOP=0 37 HAVE_DECL_INET_NTOP=0
37 fi 38 fi
38 else 39 else
39 gl_save_LIBS=$LIBS 40 gl_saved_LIBS=$LIBS
40 AC_SEARCH_LIBS([inet_ntop], [nsl resolv network], [], 41 AC_SEARCH_LIBS([inet_ntop], [nsl resolv network], [],
41 [AC_CHECK_FUNCS([inet_ntop]) 42 [AC_CHECK_FUNCS([inet_ntop])
42 if test $ac_cv_func_inet_ntop = no; then 43 if test $ac_cv_func_inet_ntop = no; then
43 HAVE_INET_NTOP=0 44 HAVE_INET_NTOP=0
44 fi 45 fi
45 ]) 46 ])
46 LIBS=$gl_save_LIBS 47 LIBS=$gl_saved_LIBS
47 48
48 if test "$ac_cv_search_inet_ntop" != "no" \ 49 if test "$ac_cv_search_inet_ntop" != "no" \
49 && test "$ac_cv_search_inet_ntop" != "none required"; then 50 && test "$ac_cv_search_inet_ntop" != "none required"; then
diff --git a/gl/m4/intmax_t.m4 b/gl/m4/intmax_t.m4
index ef32e1b9..72858ea8 100644
--- a/gl/m4/intmax_t.m4
+++ b/gl/m4/intmax_t.m4
@@ -1,5 +1,6 @@
1# intmax_t.m4 serial 9 1# intmax_t.m4
2dnl Copyright (C) 1997-2004, 2006-2007, 2009-2023 Free Software Foundation, 2# serial 9
3dnl Copyright (C) 1997-2004, 2006-2007, 2009-2024 Free Software Foundation,
3dnl Inc. 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,
diff --git a/gl/m4/inttypes.m4 b/gl/m4/inttypes.m4
index bf2eab2b..c43cd162 100644
--- a/gl/m4/inttypes.m4
+++ b/gl/m4/inttypes.m4
@@ -1,5 +1,6 @@
1# inttypes.m4 serial 36 1# inttypes.m4
2dnl Copyright (C) 2006-2023 Free Software Foundation, Inc. 2# serial 37
3dnl Copyright (C) 2006-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -170,6 +171,10 @@ AC_DEFUN([gl_INTTYPES_H_DEFAULTS],
170 HAVE_DECL_STRTOIMAX=1; AC_SUBST([HAVE_DECL_STRTOIMAX]) 171 HAVE_DECL_STRTOIMAX=1; AC_SUBST([HAVE_DECL_STRTOIMAX])
171 HAVE_DECL_STRTOUMAX=1; AC_SUBST([HAVE_DECL_STRTOUMAX]) 172 HAVE_DECL_STRTOUMAX=1; AC_SUBST([HAVE_DECL_STRTOUMAX])
172 HAVE_IMAXDIV_T=1; AC_SUBST([HAVE_IMAXDIV_T]) 173 HAVE_IMAXDIV_T=1; AC_SUBST([HAVE_IMAXDIV_T])
174 HAVE_IMAXABS=1; AC_SUBST([HAVE_IMAXABS])
175 HAVE_IMAXDIV=1; AC_SUBST([HAVE_IMAXDIV])
176 REPLACE_IMAXABS=0; AC_SUBST([REPLACE_IMAXABS])
177 REPLACE_IMAXDIV=0; AC_SUBST([REPLACE_IMAXDIV])
173 REPLACE_STRTOIMAX=0; AC_SUBST([REPLACE_STRTOIMAX]) 178 REPLACE_STRTOIMAX=0; AC_SUBST([REPLACE_STRTOIMAX])
174 REPLACE_STRTOUMAX=0; AC_SUBST([REPLACE_STRTOUMAX]) 179 REPLACE_STRTOUMAX=0; AC_SUBST([REPLACE_STRTOUMAX])
175 INT32_MAX_LT_INTMAX_MAX=1; AC_SUBST([INT32_MAX_LT_INTMAX_MAX]) 180 INT32_MAX_LT_INTMAX_MAX=1; AC_SUBST([INT32_MAX_LT_INTMAX_MAX])
diff --git a/gl/m4/inttypes_h.m4 b/gl/m4/inttypes_h.m4
index 68c60e9d..3b9da5b0 100644
--- a/gl/m4/inttypes_h.m4
+++ b/gl/m4/inttypes_h.m4
@@ -1,5 +1,6 @@
1# inttypes_h.m4 serial 10 1# inttypes_h.m4
2dnl Copyright (C) 1997-2004, 2006, 2008-2023 Free Software Foundation, Inc. 2# serial 10
3dnl Copyright (C) 1997-2004, 2006, 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/iswblank.m4 b/gl/m4/iswblank.m4
new file mode 100644
index 00000000..4dc12d9a
--- /dev/null
+++ b/gl/m4/iswblank.m4
@@ -0,0 +1,39 @@
1# iswblank.m4
2# serial 7
3dnl Copyright (C) 2011-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_FUNC_ISWBLANK],
9[
10 AC_REQUIRE([gl_WCTYPE_H_DEFAULTS])
11 AC_REQUIRE([gl_WCTYPE_H])
12 dnl Persuade glibc <wctype.h> to declare iswblank().
13 AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
14 gl_CHECK_FUNCS_ANDROID([iswblank], [[#include <wctype.h>]])
15 AC_CHECK_DECLS([iswblank], , , [[
16 #include <wchar.h>
17 #include <wctype.h>
18 ]])
19 if test $ac_cv_func_iswblank = no; then
20 HAVE_ISWBLANK=0
21 if test $ac_cv_have_decl_iswblank = yes \
22 || case "$gl_cv_onwards_func_iswblank" in \
23 future*) true ;; \
24 *) false ;; \
25 esac; then
26 REPLACE_ISWBLANK=1
27 fi
28 fi
29 if test $HAVE_ISWCNTRL = 0 || test $REPLACE_ISWCNTRL = 1; then
30 dnl Redefine all of iswcntrl, ..., towupper in <wctype.h>.
31 :
32 else
33 if test $HAVE_ISWBLANK = 0 || test $REPLACE_ISWBLANK = 1; then
34 dnl Redefine only iswblank.
35 :
36 fi
37 fi
38
39])
diff --git a/gl/m4/iswctype.m4 b/gl/m4/iswctype.m4
new file mode 100644
index 00000000..16031be4
--- /dev/null
+++ b/gl/m4/iswctype.m4
@@ -0,0 +1,14 @@
1# iswctype.m4
2# serial 3
3dnl Copyright (C) 2011-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_FUNC_ISWCTYPE],
9[
10 AC_REQUIRE([gl_WCTYPE_H_DEFAULTS])
11 AC_REQUIRE([gl_WCTYPE_H])
12 dnl Determine REPLACE_WCTYPE.
13 AC_REQUIRE([gl_FUNC_WCTYPE])
14])
diff --git a/gl/m4/iswdigit.m4 b/gl/m4/iswdigit.m4
new file mode 100644
index 00000000..999acd28
--- /dev/null
+++ b/gl/m4/iswdigit.m4
@@ -0,0 +1,121 @@
1# iswdigit.m4
2# serial 7
3dnl Copyright (C) 2020-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_FUNC_ISWDIGIT],
9[
10 AC_REQUIRE([gl_WCTYPE_H_DEFAULTS])
11 AC_REQUIRE([gl_WCTYPE_H])
12 AC_REQUIRE([gt_LOCALE_FR])
13 AC_REQUIRE([gt_LOCALE_JA])
14 AC_REQUIRE([gt_LOCALE_FR_UTF8])
15 AC_REQUIRE([gt_LOCALE_ZH_CN])
16 AC_REQUIRE([AC_CANONICAL_HOST])
17
18 if test $HAVE_ISWCNTRL = 0 || test $REPLACE_ISWCNTRL = 1; then
19 dnl <wctype.h> redefines iswdigit already.
20 REPLACE_ISWDIGIT="$REPLACE_ISWCNTRL"
21 else
22 AC_CACHE_CHECK([whether iswdigit is ISO C compliant],
23 [gl_cv_func_iswdigit_works],
24 [
25 dnl Initial guess, used when cross-compiling or when no suitable locale
26 dnl is present.
27changequote(,)dnl
28 case "$host_os" in
29 # Guess no on FreeBSD, NetBSD, Solaris, native Windows.
30 freebsd* | dragonfly* | netbsd* | solaris* | mingw* | windows*)
31 gl_cv_func_iswdigit_works="guessing no" ;;
32 # Guess yes otherwise.
33 *) gl_cv_func_iswdigit_works="guessing yes" ;;
34 esac
35changequote([,])dnl
36 if test $LOCALE_FR != none || test $LOCALE_JA != none || test $LOCALE_FR_UTF8 != none || test $LOCALE_ZH_CN != none; then
37 AC_RUN_IFELSE(
38 [AC_LANG_SOURCE([[
39#include <locale.h>
40#include <stdlib.h>
41#include <string.h>
42#include <wchar.h>
43#include <wctype.h>
44
45/* Returns the value of iswdigit for the multibyte character s[0..n-1]. */
46static int
47for_character (const char *s, size_t n)
48{
49 mbstate_t state;
50 wchar_t wc;
51 size_t ret;
52
53 memset (&state, '\0', sizeof (mbstate_t));
54 wc = (wchar_t) 0xBADFACE;
55 ret = mbrtowc (&wc, s, n, &state);
56 if (ret != n)
57 abort ();
58
59 return iswdigit (wc);
60}
61
62int
63main (int argc, char *argv[])
64{
65 int is;
66 int result = 0;
67
68 if (strcmp ("$LOCALE_FR", "none") != 0
69 && setlocale (LC_ALL, "$LOCALE_FR") != NULL)
70 {
71 /* This fails on mingw, MSVC 14. */
72 /* U+00B2 SUPERSCRIPT TWO */
73 is = for_character ("\262", 1);
74 if (!(is == 0))
75 result |= 1;
76 }
77 if (strcmp ("$LOCALE_JA", "none") != 0
78 && setlocale (LC_ALL, "$LOCALE_JA") != NULL)
79 {
80 /* This fails on NetBSD 10.0. */
81 /* U+FF11 FULLWIDTH DIGIT ONE */
82 is = for_character ("\243\261", 2);
83 if (!(is == 0))
84 result |= 2;
85 }
86 if (strcmp ("$LOCALE_FR_UTF8", "none") != 0
87 && setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL)
88 {
89 /* This fails on FreeBSD 13.0, NetBSD 10.0, MSVC 14. */
90 /* U+0663 ARABIC-INDIC DIGIT THREE */
91 is = for_character ("\331\243", 2);
92 if (!(is == 0))
93 result |= 4;
94 /* This fails on FreeBSD 13.0, NetBSD 10.0, MSVC 14. */
95 /* U+FF11 FULLWIDTH DIGIT ONE */
96 is = for_character ("\357\274\221", 3);
97 if (!(is == 0))
98 result |= 8;
99 }
100 if (strcmp ("$LOCALE_ZH_CN", "none") != 0
101 && setlocale (LC_ALL, "$LOCALE_ZH_CN") != NULL)
102 {
103 /* This fails on NetBSD 10.0, Solaris 10, Solaris 11.4. */
104 /* U+FF11 FULLWIDTH DIGIT ONE */
105 is = for_character ("\243\261", 2);
106 if (!(is == 0))
107 result |= 16;
108 }
109 return result;
110}]])],
111 [gl_cv_func_iswdigit_works=yes],
112 [gl_cv_func_iswdigit_works=no],
113 [:])
114 fi
115 ])
116 case "$gl_cv_func_iswdigit_works" in
117 *yes) ;;
118 *) REPLACE_ISWDIGIT=1 ;;
119 esac
120 fi
121])
diff --git a/gl/m4/iswpunct.m4 b/gl/m4/iswpunct.m4
new file mode 100644
index 00000000..1edf58aa
--- /dev/null
+++ b/gl/m4/iswpunct.m4
@@ -0,0 +1,49 @@
1# iswpunct.m4
2# serial 2
3dnl Copyright (C) 2023-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_FUNC_ISWPUNCT],
9[
10 AC_REQUIRE([gl_WCTYPE_H_DEFAULTS])
11 AC_REQUIRE([gl_WCTYPE_H])
12 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
13
14 if test $HAVE_ISWCNTRL = 0 || test $REPLACE_ISWCNTRL = 1; then
15 dnl <wctype.h> redefines iswpunct already.
16 REPLACE_ISWPUNCT="$REPLACE_ISWCNTRL"
17 else
18 AC_CACHE_CHECK([whether iswpunct is consistent with ispunct],
19 [gl_cv_func_iswpunct_works],
20 [AC_RUN_IFELSE(
21 [AC_LANG_SOURCE([[
22#include <ctype.h>
23#include <wchar.h>
24#include <wctype.h>
25int
26main (int argc, char *argv[])
27{
28 int result = 0;
29 /* This fails on Android 11. */
30 if ((! iswpunct ('\`')) != (! ispunct ('\`')))
31 result |= 1;
32 return result;
33}]])],
34 [gl_cv_func_iswpunct_works=yes],
35 [gl_cv_func_iswpunct_works=no],
36 [case "$host_os" in
37 # Guess no on Android.
38 android*) gl_cv_func_iswpunct_works="guessing no" ;;
39 # Guess yes otherwise.
40 *) gl_cv_func_iswpunct_works="guessing yes" ;;
41 esac
42 ])
43 ])
44 case "$gl_cv_func_iswpunct_works" in
45 *yes) ;;
46 *) REPLACE_ISWPUNCT=1 ;;
47 esac
48 fi
49])
diff --git a/gl/m4/iswxdigit.m4 b/gl/m4/iswxdigit.m4
new file mode 100644
index 00000000..6085bf6b
--- /dev/null
+++ b/gl/m4/iswxdigit.m4
@@ -0,0 +1,111 @@
1# iswxdigit.m4
2# serial 7
3dnl Copyright (C) 2020-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_FUNC_ISWXDIGIT],
9[
10 AC_REQUIRE([gl_WCTYPE_H_DEFAULTS])
11 AC_REQUIRE([gl_WCTYPE_H])
12 AC_REQUIRE([gt_LOCALE_JA])
13 AC_REQUIRE([gt_LOCALE_FR_UTF8])
14 AC_REQUIRE([gt_LOCALE_ZH_CN])
15 AC_REQUIRE([AC_CANONICAL_HOST])
16
17 if test $HAVE_ISWCNTRL = 0 || test $REPLACE_ISWCNTRL = 1; then
18 dnl <wctype.h> redefines iswxdigit already.
19 REPLACE_ISWXDIGIT="$REPLACE_ISWCNTRL"
20 else
21 AC_CACHE_CHECK([whether iswxdigit is ISO C compliant],
22 [gl_cv_func_iswxdigit_works],
23 [
24 dnl Initial guess, used when cross-compiling or when no suitable locale
25 dnl is present.
26changequote(,)dnl
27 case "$host_os" in
28 # Guess no on FreeBSD, NetBSD, Solaris, native Windows.
29 freebsd* | dragonfly* | netbsd* | solaris* | mingw* | windows*)
30 gl_cv_func_iswxdigit_works="guessing no" ;;
31 # Guess yes otherwise.
32 *) gl_cv_func_iswxdigit_works="guessing yes" ;;
33 esac
34changequote([,])dnl
35 if test $LOCALE_JA != none || test $LOCALE_FR_UTF8 != none || test $LOCALE_ZH_CN != none; then
36 AC_RUN_IFELSE(
37 [AC_LANG_SOURCE([[
38#include <locale.h>
39#include <stdlib.h>
40#include <string.h>
41#include <wchar.h>
42#include <wctype.h>
43
44/* Returns the value of iswxdigit for the multibyte character s[0..n-1]. */
45static int
46for_character (const char *s, size_t n)
47{
48 mbstate_t state;
49 wchar_t wc;
50 size_t ret;
51
52 memset (&state, '\0', sizeof (mbstate_t));
53 wc = (wchar_t) 0xBADFACE;
54 ret = mbrtowc (&wc, s, n, &state);
55 if (ret != n)
56 abort ();
57
58 return iswxdigit (wc);
59}
60
61int
62main (int argc, char *argv[])
63{
64 int is;
65 int result = 0;
66
67 if (strcmp ("$LOCALE_JA", "none") != 0
68 && setlocale (LC_ALL, "$LOCALE_JA") != NULL)
69 {
70 /* This fails on NetBSD 10.0. */
71 /* U+FF21 FULLWIDTH LATIN CAPITAL LETTER A */
72 is = for_character ("\243\301", 2);
73 if (!(is == 0))
74 result |= 1;
75 }
76 if (strcmp ("$LOCALE_FR_UTF8", "none") != 0
77 && setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL)
78 {
79 /* This fails on FreeBSD 13.0. */
80 /* U+0663 ARABIC-INDIC DIGIT THREE */
81 is = for_character ("\331\243", 2);
82 if (!(is == 0))
83 result |= 2;
84 /* This fails on NetBSD 10.0, MSVC 14. */
85 /* U+FF21 FULLWIDTH LATIN CAPITAL LETTER A */
86 is = for_character ("\357\274\241", 3);
87 if (!(is == 0))
88 result |= 4;
89 }
90 if (strcmp ("$LOCALE_ZH_CN", "none") != 0
91 && setlocale (LC_ALL, "$LOCALE_ZH_CN") != NULL)
92 {
93 /* This fails on Solaris 10, Solaris 11.4. */
94 /* U+FF11 FULLWIDTH DIGIT ONE */
95 is = for_character ("\243\261", 2);
96 if (!(is == 0))
97 result |= 8;
98 }
99 return result;
100}]])],
101 [gl_cv_func_iswxdigit_works=yes],
102 [gl_cv_func_iswxdigit_works=no],
103 [:])
104 fi
105 ])
106 case "$gl_cv_func_iswxdigit_works" in
107 *yes) ;;
108 *) REPLACE_ISWXDIGIT=1 ;;
109 esac
110 fi
111])
diff --git a/gl/m4/langinfo_h.m4 b/gl/m4/langinfo_h.m4
index b17a526a..5eee8a71 100644
--- a/gl/m4/langinfo_h.m4
+++ b/gl/m4/langinfo_h.m4
@@ -1,5 +1,6 @@
1# langinfo_h.m4 serial 12 1# langinfo_h.m4
2dnl Copyright (C) 2009-2023 Free Software Foundation, Inc. 2# serial 12
3dnl Copyright (C) 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/largefile.m4 b/gl/m4/largefile.m4
index 7fb81b86..2f824089 100644
--- a/gl/m4/largefile.m4
+++ b/gl/m4/largefile.m4
@@ -1,16 +1,18 @@
1# largefile.m4
2# serial 1
3dnl Copyright 1992-1996, 1998-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
1# Enable large files on systems where this is not the default. 8# Enable large files on systems where this is not the default.
2# Enable support for files on Linux file systems with 64-bit inode numbers. 9# Enable support for files on Linux file systems with 64-bit inode numbers.
3 10
4# Copyright 1992-1996, 1998-2023 Free Software Foundation, Inc.
5# This file is free software; the Free Software Foundation
6# gives unlimited permission to copy and/or distribute it,
7# with or without modifications, as long as this notice is preserved.
8
9# The following macro works around a problem in Autoconf's AC_FUNC_FSEEKO: 11# The following macro works around a problem in Autoconf's AC_FUNC_FSEEKO:
10# It does not set _LARGEFILE_SOURCE=1 on HP-UX/ia64 32-bit, although this 12# It does not set _LARGEFILE_SOURCE=1 on HP-UX/ia64 32-bit, although this
11# setting of _LARGEFILE_SOURCE is needed so that <stdio.h> declares fseeko 13# setting of _LARGEFILE_SOURCE is needed so that <stdio.h> declares fseeko
12# and ftello in C++ mode as well. 14# and ftello in C++ mode as well.
13# Fixed in Autoconf 2.72, which has AC_SYS_YEAR2038. 15# This problem occurs in Autoconf 2.71 and earlier, which lack AC_SYS_YEAR2038.
14AC_DEFUN([gl_SET_LARGEFILE_SOURCE], 16AC_DEFUN([gl_SET_LARGEFILE_SOURCE],
15 m4_ifndef([AC_SYS_YEAR2038], [[ 17 m4_ifndef([AC_SYS_YEAR2038], [[
16 AC_REQUIRE([AC_CANONICAL_HOST]) 18 AC_REQUIRE([AC_CANONICAL_HOST])
@@ -24,29 +26,20 @@ AC_DEFUN([gl_SET_LARGEFILE_SOURCE],
24 ]]) 26 ]])
25) 27)
26 28
27# Work around a problem in autoconf <= 2.69: 29dnl Remove AC_SYS_YEAR2038_RECOMMENDED if unpatched Autoconf 2.72 or earlier.
28# AC_SYS_LARGEFILE does not configure for large inodes on Mac OS X 10.5, 30dnl Autoconf 2.72 still uses -n32, which is not a C preprocessor option,
29# or configures them incorrectly in some cases. 31dnl and which was useful only on IRIX which is no longer supported.
30m4_version_prereq([2.70], [], [ 32dnl This should be fixed in Autoconf 2.73.
31 33m4_ifdef([AC_SYS_YEAR2038_RECOMMENDED],
32# _AC_SYS_LARGEFILE_TEST_INCLUDES 34 [m4_bmatch(m4_ifdef([_AC_SYS_LARGEFILE_OPTIONS],
33# ------------------------------- 35 [m4_defn([_AC_SYS_LARGEFILE_OPTIONS])],
34m4_define([_AC_SYS_LARGEFILE_TEST_INCLUDES], 36 ["-n32"]),
35[#include <sys/types.h> 37 ["-n32"],
36 /* Check that off_t can represent 2**63 - 1 correctly. 38 [m4_undefine([AC_SYS_YEAR2038_RECOMMENDED])])])
37 We can't simply define LARGE_OFF_T to be 9223372036854775807,
38 since some C++ compilers masquerading as C compilers
39 incorrectly reject 9223372036854775807. */
40#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
41 int off_t_is_large[[(LARGE_OFF_T % 2147483629 == 721
42 && LARGE_OFF_T % 2147483647 == 1)
43 ? 1 : -1]];[]dnl
44])
45])# m4_version_prereq 2.70
46 39
47# Support AC_SYS_YEAR2038, even if Autoconf 2.71 or earlier. 40m4_ifndef([AC_SYS_YEAR2038_RECOMMENDED], [
48# This code is taken from Autoconf master. 41# Fix up AC_SYS_YEAR2038_RECOMMENDED and related macros, even if
49m4_ifndef([AC_SYS_YEAR2038], [ 42# unpatched Autoconf 2.72 or earlier. This code is taken from Autoconf master.
50 43
51# _AC_SYS_YEAR2038_TEST_CODE 44# _AC_SYS_YEAR2038_TEST_CODE
52# -------------------------- 45# --------------------------
@@ -78,8 +71,8 @@ m4_define([_AC_SYS_YEAR2038_OPTIONS], m4_normalize(
78 dnl 32-bit MinGW (misconfiguration) 71 dnl 32-bit MinGW (misconfiguration)
79)) 72))
80 73
81# _AC_SYS_YEAR2038_PROBE([IF-NOT-DETECTED]) 74# _AC_SYS_YEAR2038_PROBE
82# ----------------------------------------- 75# ----------------------
83# Subroutine of AC_SYS_YEAR2038. Probe for time_t that can represent 76# Subroutine of AC_SYS_YEAR2038. Probe for time_t that can represent
84# time points more than 2**31 - 1 seconds after the epoch (dates after 77# time points more than 2**31 - 1 seconds after the epoch (dates after
85# 2038-01-18, see above) and set the cache variable ac_cv_sys_year2038_opts 78# 2038-01-18, see above) and set the cache variable ac_cv_sys_year2038_opts
@@ -92,13 +85,10 @@ m4_define([_AC_SYS_YEAR2038_OPTIONS], m4_normalize(
92# AC_TRY_RUN. Note also that some systems only support large time_t 85# AC_TRY_RUN. Note also that some systems only support large time_t
93# together with large off_t. 86# together with large off_t.
94# 87#
95# If support is not detected, the behavior depends on which of the
96# top-level AC_SYS_YEAR2038 macros was used (see below).
97#
98# If you change this macro you may also need to change 88# If you change this macro you may also need to change
99# _AC_SYS_YEAR2038_OPTIONS. 89# _AC_SYS_YEAR2038_OPTIONS.
100AC_DEFUN([_AC_SYS_YEAR2038_PROBE], 90AC_DEFUN([_AC_SYS_YEAR2038_PROBE],
101[AC_CACHE_CHECK([for $CC option to enable timestamps after Jan 2038], 91[AC_CACHE_CHECK([for $CPPFLAGS option for timestamps after 2038],
102 [ac_cv_sys_year2038_opts], 92 [ac_cv_sys_year2038_opts],
103 [ac_save_CPPFLAGS="$CPPFLAGS" 93 [ac_save_CPPFLAGS="$CPPFLAGS"
104 ac_opt_found=no 94 ac_opt_found=no
@@ -117,40 +107,20 @@ ac_have_year2038=yes
117AS_CASE([$ac_cv_sys_year2038_opts], 107AS_CASE([$ac_cv_sys_year2038_opts],
118 ["none needed"], [], 108 ["none needed"], [],
119 ["support not detected"], 109 ["support not detected"],
120 [ac_have_year2038=no 110 [ac_have_year2038=no],
121 AS_CASE([$enable_year2038],
122 [yes],
123 [# If we're not cross compiling and 'touch' works with a large
124 # timestamp, then we can presume the system supports wider time_t
125 # *somehow* and we just weren't able to detect it. One common
126 # case that we deliberately *don't* probe for is a system that
127 # supports both 32- and 64-bit ABIs but only the 64-bit ABI offers
128 # wide time_t. (It would be inappropriate for us to override an
129 # intentional use of -m32.) Error out, demanding use of
130 # --disable-year2038 if this is intentional.
131 AS_IF([test $cross_compiling = no],
132 [AS_IF([TZ=UTC0 touch -t 210602070628.15 conftest.time 2>/dev/null],
133 [AS_CASE([`TZ=UTC0 LC_ALL=C ls -l conftest.time 2>/dev/null`],
134 [*'Feb 7 2106'* | *'Feb 7 17:10'*],
135 [AC_MSG_FAILURE(m4_text_wrap(
136 [this system appears to support timestamps after January 2038,
137 but no mechanism for enabling wide 'time_t' was detected.
138 Did you mean to build a 64-bit binary? (e.g. 'CC="${CC} -m64"'.)
139 To proceed with 32-bit time_t, configure with '--disable-year2038'.],
140 [], [], [55]))])])])])],
141 111
142 ["-D_TIME_BITS=64"], 112 ["-D_TIME_BITS=64"],
143 [AC_DEFINE([_TIME_BITS], [64], 113 [AC_DEFINE([_TIME_BITS], [64],
144 [Number of bits in time_t, on hosts where this is settable.])], 114 [Number of bits in time_t, on hosts where this is settable.])],
145 115
146 ["-D__MINGW_USE_VC2005_COMPAT=1"], 116 ["-D__MINGW_USE_VC2005_COMPAT"],
147 [AC_DEFINE([__MINGW_USE_VC2005_COMPAT], [1], 117 [AC_DEFINE([__MINGW_USE_VC2005_COMPAT], [1],
148 [Define to 1 on platforms where this makes time_t a 64-bit type.])], 118 [Define to 1 on platforms where this makes time_t a 64-bit type.])],
149 119
150 ["-U_USE_32_BIT_TIME_T"*], 120 ["-U_USE_32_BIT_TIME_T"*],
151 [AC_MSG_FAILURE(m4_text_wrap( 121 [AC_MSG_FAILURE(m4_text_wrap(
152 [the 'time_t' type is currently forced to be 32-bit. 122 [the 'time_t' type is currently forced to be 32-bit.
153 It will stop working after January 2038. 123 It will stop working after mid-January 2038.
154 Remove _USE_32BIT_TIME_T from the compiler flags.], 124 Remove _USE_32BIT_TIME_T from the compiler flags.],
155 [], [], [55]))], 125 [], [], [55]))],
156 126
@@ -160,12 +130,11 @@ AS_CASE([$ac_cv_sys_year2038_opts],
160 130
161# _AC_SYS_YEAR2038_ENABLE 131# _AC_SYS_YEAR2038_ENABLE
162# ----------------------- 132# -----------------------
163# Subroutine of AC_SYS_YEAR2038 and _AC_SYS_YEAR2038_OPT_IN.
164# Depending on which of the YEAR2038 macros was used, add either an 133# Depending on which of the YEAR2038 macros was used, add either an
165# --enable-year2038, or a --disable-year2038, or no option at all to 134# --enable-year2038 or a --disable-year2038 to
166# the configure script. Note that this is expanded very late and 135# the configure script. This is expanded very late and
167# therefore there cannot be any code in the AC_ARG_ENABLE. The 136# therefore there cannot be any code in the AC_ARG_ENABLE. The
168# default value for enable_year2038 is emitted unconditionally 137# default value for 'enable_year2038' is emitted unconditionally
169# because the generated code always looks at this variable. 138# because the generated code always looks at this variable.
170m4_define([_AC_SYS_YEAR2038_ENABLE], 139m4_define([_AC_SYS_YEAR2038_ENABLE],
171[m4_divert_text([DEFAULTS], 140[m4_divert_text([DEFAULTS],
@@ -175,50 +144,70 @@ m4_define([_AC_SYS_YEAR2038_ENABLE],
175[AC_ARG_ENABLE([year2038], 144[AC_ARG_ENABLE([year2038],
176 m4_provide_if([AC_SYS_YEAR2038], 145 m4_provide_if([AC_SYS_YEAR2038],
177 [AS_HELP_STRING([--disable-year2038], 146 [AS_HELP_STRING([--disable-year2038],
178 [do not support timestamps after 2038])], 147 [don't support timestamps after 2038])],
179 [AS_HELP_STRING([--enable-year2038], 148 [AS_HELP_STRING([--enable-year2038],
180 [support timestamps after 2038])]))]) 149 [support timestamps after 2038])]))])
181 150
182# _AC_SYS_YEAR2038_OPT_IN
183# -----------------------
184# If the --enable-year2038 option is given to configure, attempt to
185# detect and activate support for large time_t on 32-bit systems.
186# This macro is automatically invoked by AC_SYS_LARGEFILE when large
187# *file* support is detected. It does not AC_REQUIRE AC_SYS_LARGEFILE
188# to avoid a dependency loop, and is therefore unsafe to expose as a
189# documented macro.
190AC_DEFUN([_AC_SYS_YEAR2038_OPT_IN],
191[m4_provide_if([_AC_SYS_YEAR2038_PROBE], [], [dnl
192 AS_IF([test "$enable_year2038" != no], [_AC_SYS_YEAR2038_PROBE])
193 AC_CONFIG_COMMANDS_PRE([_AC_SYS_YEAR2038_ENABLE])
194])])
195
196# AC_SYS_YEAR2038 151# AC_SYS_YEAR2038
197# --------------- 152# ---------------
198# Attempt to detect and activate support for large time_t. 153# Attempt to detect and activate support for large time_t.
199# On systems where time_t is not always 64 bits, this probe can be 154# On systems where time_t is not always 64 bits, this probe can be
200# skipped by passing the --disable-year2038 option to configure. 155# skipped by passing the --disable-year2038 option to configure.
201AC_DEFUN([AC_SYS_YEAR2038], 156AC_DEFUN([AC_SYS_YEAR2038],
202[AC_REQUIRE([AC_SYS_LARGEFILE])]dnl 157[AC_REQUIRE([AC_SYS_LARGEFILE])dnl
203[m4_provide_if([_AC_SYS_YEAR2038_PROBE], [], [dnl 158AS_IF([test "$enable_year2038,$ac_have_year2038,$cross_compiling" = yes,no,no],
204 AS_IF([test "$enable_year2038" != no], [_AC_SYS_YEAR2038_PROBE]) 159 [# If we're not cross compiling and 'touch' works with a large
205 AC_CONFIG_COMMANDS_PRE([_AC_SYS_YEAR2038_ENABLE]) 160 # timestamp, then we can presume the system supports wider time_t
206])]) 161 # *somehow* and we just weren't able to detect it. One common
162 # case that we deliberately *don't* probe for is a system that
163 # supports both 32- and 64-bit ABIs but only the 64-bit ABI offers
164 # wide time_t. (It would be inappropriate for us to override an
165 # intentional use of -m32.) Error out, demanding use of
166 # --disable-year2038 if this is intentional.
167 AS_IF([TZ=UTC0 touch -t 210602070628.15 conftest.time 2>/dev/null],
168 [AS_CASE([`TZ=UTC0 LC_ALL=C ls -l conftest.time 2>/dev/null`],
169 [*'Feb 7 2106'* | *'Feb 7 17:10'*],
170 [AC_MSG_FAILURE(m4_text_wrap(
171 [this system appears to support timestamps after mid-January 2038,
172 but no mechanism for enabling wide 'time_t' was detected.
173 Did you mean to build a 64-bit binary? (E.g., 'CC="${CC} -m64"'.)
174 To proceed with 32-bit time_t, configure with '--disable-year2038'.],
175 [], [], [55]))])])])])
176
177# AC_SYS_YEAR2038_RECOMMENDED
178# ---------------------------
179# Same as AC_SYS_YEAR2038, but recommend support for large time_t.
180# If we cannot find any way to make time_t capable of representing
181# values larger than 2**31 - 1, error out unless --disable-year2038 is given.
182AC_DEFUN([AC_SYS_YEAR2038_RECOMMENDED],
183[AC_REQUIRE([AC_SYS_YEAR2038])dnl
184AS_IF([test "$enable_year2038,$ac_have_year2038" = yes,no],
185 [AC_MSG_FAILURE(m4_text_wrap(
186 [could not enable timestamps after mid-January 2038.
187 This package recommends support for these later timestamps.
188 However, to proceed with signed 32-bit time_t even though it
189 will fail then, configure with '--disable-year2038'.],
190 [], [], [55]))])])
207 191
208# _AC_SYS_LARGEFILE_TEST_CODE 192# _AC_SYS_LARGEFILE_TEST_CODE
209# --------------------------- 193# ---------------------------
210# C code used to probe for large file support. 194# C code used to probe for large file support.
211m4_define([_AC_SYS_LARGEFILE_TEST_CODE], 195m4_define([_AC_SYS_LARGEFILE_TEST_CODE],
212[@%:@include <sys/types.h> 196[@%:@include <sys/types.h>
213 /* Check that off_t can represent 2**63 - 1 correctly. 197@%:@ifndef FTYPE
214 We can't simply define LARGE_OFF_T to be 9223372036854775807, 198@%:@ define FTYPE off_t
199@%:@endif
200 /* Check that FTYPE can represent 2**63 - 1 correctly.
201 We can't simply define LARGE_FTYPE to be 9223372036854775807,
215 since some C++ compilers masquerading as C compilers 202 since some C++ compilers masquerading as C compilers
216 incorrectly reject 9223372036854775807. */ 203 incorrectly reject 9223372036854775807. */
217@%:@define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) 204@%:@define LARGE_FTYPE (((FTYPE) 1 << 31 << 31) - 1 + ((FTYPE) 1 << 31 << 31))
218 int off_t_is_large[[(LARGE_OFF_T % 2147483629 == 721 205 int FTYPE_is_large[[(LARGE_FTYPE % 2147483629 == 721
219 && LARGE_OFF_T % 2147483647 == 1) 206 && LARGE_FTYPE % 2147483647 == 1)
220 ? 1 : -1]];[]dnl 207 ? 1 : -1]];[]dnl
221]) 208])
209# Defined by Autoconf 2.71 and circa 2022 Gnulib unwisely depended on it.
210m4_define([_AC_SYS_LARGEFILE_TEST_INCLUDES], [_AC_SYS_LARGEFILE_TEST_CODE])
222 211
223# _AC_SYS_LARGEFILE_OPTIONS 212# _AC_SYS_LARGEFILE_OPTIONS
224# ------------------------- 213# -------------------------
@@ -228,8 +217,7 @@ m4_define([_AC_SYS_LARGEFILE_TEST_CODE],
228m4_define([_AC_SYS_LARGEFILE_OPTIONS], m4_normalize( 217m4_define([_AC_SYS_LARGEFILE_OPTIONS], m4_normalize(
229 ["none needed"] dnl Most current systems 218 ["none needed"] dnl Most current systems
230 ["-D_FILE_OFFSET_BITS=64"] dnl X/Open LFS spec 219 ["-D_FILE_OFFSET_BITS=64"] dnl X/Open LFS spec
231 ["-D_LARGE_FILES=1"] dnl AIX (which versions?) 220 ["-D_LARGE_FILES=1"] dnl 32-bit AIX 4.2.1+, 32-bit z/OS
232 ["-n32"] dnl Irix 6.2 w/ SGI compiler
233)) 221))
234 222
235# _AC_SYS_LARGEFILE_PROBE 223# _AC_SYS_LARGEFILE_PROBE
@@ -246,24 +234,43 @@ m4_define([_AC_SYS_LARGEFILE_OPTIONS], m4_normalize(
246# If you change this macro you may also need to change 234# If you change this macro you may also need to change
247# _AC_SYS_LARGEFILE_OPTIONS. 235# _AC_SYS_LARGEFILE_OPTIONS.
248AC_DEFUN([_AC_SYS_LARGEFILE_PROBE], 236AC_DEFUN([_AC_SYS_LARGEFILE_PROBE],
249[AC_CACHE_CHECK([for $CC option to enable large file support], 237[AC_CACHE_CHECK([for $CPPFLAGS option for large files],
250 [ac_cv_sys_largefile_opts], 238 [ac_cv_sys_largefile_opts],
251 [ac_save_CC="$CC" 239 [ac_save_CPPFLAGS=$CPPFLAGS
252 ac_opt_found=no 240 ac_opt_found=no
253 for ac_opt in _AC_SYS_LARGEFILE_OPTIONS; do 241 for ac_opt in _AC_SYS_LARGEFILE_OPTIONS; do
254 AS_IF([test x"$ac_opt" != x"none needed"], 242 AS_IF([test x"$ac_opt" != x"none needed"],
255 [CC="$ac_save_CC $ac_opt"]) 243 [CPPFLAGS="$ac_save_CPPFLAGS $ac_opt"])
256 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([_AC_SYS_LARGEFILE_TEST_CODE])], 244 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([_AC_SYS_LARGEFILE_TEST_CODE])],
257 [ac_cv_sys_largefile_opts="$ac_opt" 245 [AS_IF([test x"$ac_opt" = x"none needed"],
246 [# GNU/Linux s390x and alpha need _FILE_OFFSET_BITS=64 for wide ino_t.
247 CPPFLAGS="$CPPFLAGS -DFTYPE=ino_t"
248 AC_COMPILE_IFELSE([], [],
249 [CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=64"
250 AC_COMPILE_IFELSE([], [ac_opt='-D_FILE_OFFSET_BITS=64'])])])
251 ac_cv_sys_largefile_opts=$ac_opt
258 ac_opt_found=yes]) 252 ac_opt_found=yes])
259 test $ac_opt_found = no || break 253 test $ac_opt_found = no || break
260 done 254 done
261 CC="$ac_save_CC" 255 CPPFLAGS=$ac_save_CPPFLAGS
256 dnl Gnulib implements large file support for native Windows, based on the
257 dnl variables WINDOWS_64_BIT_OFF_T, WINDOWS_64_BIT_ST_SIZE.
258 m4_ifdef([gl_LARGEFILE], [
259 AC_REQUIRE([AC_CANONICAL_HOST])
260 if test $ac_opt_found != yes; then
261 AS_CASE([$host_os],
262 [mingw* | windows*],
263 [ac_cv_sys_largefile_opts="supported through gnulib"
264 ac_opt_found=yes]
265 )
266 fi
267 ])
262 test $ac_opt_found = yes || ac_cv_sys_largefile_opts="support not detected"]) 268 test $ac_opt_found = yes || ac_cv_sys_largefile_opts="support not detected"])
263 269
264ac_have_largefile=yes 270ac_have_largefile=yes
265AS_CASE([$ac_cv_sys_largefile_opts], 271AS_CASE([$ac_cv_sys_largefile_opts],
266 ["none needed"], [], 272 ["none needed"], [],
273 ["supported through gnulib"], [],
267 ["support not detected"], 274 ["support not detected"],
268 [ac_have_largefile=no], 275 [ac_have_largefile=no],
269 276
@@ -275,27 +282,12 @@ AS_CASE([$ac_cv_sys_largefile_opts],
275 [AC_DEFINE([_LARGE_FILES], [1], 282 [AC_DEFINE([_LARGE_FILES], [1],
276 [Define to 1 on platforms where this makes off_t a 64-bit type.])], 283 [Define to 1 on platforms where this makes off_t a 64-bit type.])],
277 284
278 ["-n32"],
279 [CC="$CC -n32"],
280
281 [AC_MSG_ERROR( 285 [AC_MSG_ERROR(
282 [internal error: bad value for \$ac_cv_sys_largefile_opts])]) 286 [internal error: bad value for \$ac_cv_sys_largefile_opts])])
283 287
284_AC_SYS_YEAR2038_OPT_IN 288AS_IF([test "$enable_year2038" != no],
285]) 289 [_AC_SYS_YEAR2038_PROBE])
286 290AC_CONFIG_COMMANDS_PRE([_AC_SYS_YEAR2038_ENABLE])])
287# _AC_SYS_LARGEFILE_ENABLE
288# ------------------------
289# Subroutine of AC_SYS_LARGEFILE. Note that this
290# is expanded very late and therefore there cannot be any code in the
291# AC_ARG_ENABLE. The default value for enable_largefile is emitted
292# unconditionally because the generated shell code always looks at
293# this variable.
294m4_define([_AC_SYS_LARGEFILE_ENABLE],
295[m4_divert_text([DEFAULTS],
296 enable_largefile=yes)]dnl
297[AC_ARG_ENABLE([largefile],
298 [AS_HELP_STRING([--disable-largefile], [omit support for large files])])])
299 291
300# AC_SYS_LARGEFILE 292# AC_SYS_LARGEFILE
301# ---------------- 293# ----------------
@@ -306,14 +298,13 @@ m4_define([_AC_SYS_LARGEFILE_ENABLE],
306# Additionally, on Linux file systems with 64-bit inodes a file that happens 298# Additionally, on Linux file systems with 64-bit inodes a file that happens
307# to have a 64-bit inode number cannot be accessed by 32-bit applications on 299# to have a 64-bit inode number cannot be accessed by 32-bit applications on
308# Linux x86/x86_64. This can occur with file systems such as XFS and NFS. 300# Linux x86/x86_64. This can occur with file systems such as XFS and NFS.
309# This macro allows configuration to continue if the system doesn't support
310# large files.
311AC_DEFUN([AC_SYS_LARGEFILE], 301AC_DEFUN([AC_SYS_LARGEFILE],
312[m4_provide_if([_AC_SYS_LARGEFILE_PROBE], [], [dnl 302[AC_ARG_ENABLE([largefile],
313 AS_IF([test "$enable_largefile" != no], [_AC_SYS_LARGEFILE_PROBE]) 303 [AS_HELP_STRING([--disable-largefile],
314 AC_CONFIG_COMMANDS_PRE([_AC_SYS_LARGEFILE_ENABLE]) 304 [omit support for large files])])dnl
315])]) 305AS_IF([test "$enable_largefile,$enable_year2038" != no,no],
316])# m4_ifndef AC_SYS_YEAR2038 306 [_AC_SYS_LARGEFILE_PROBE])])
307])# m4_ifndef AC_SYS_YEAR2038_RECOMMENDED
317 308
318# Enable large files on systems where this is implemented by Gnulib, not by the 309# Enable large files on systems where this is implemented by Gnulib, not by the
319# system headers. 310# system headers.
@@ -323,7 +314,7 @@ AC_DEFUN([gl_LARGEFILE],
323[ 314[
324 AC_REQUIRE([AC_CANONICAL_HOST]) 315 AC_REQUIRE([AC_CANONICAL_HOST])
325 case "$host_os" in 316 case "$host_os" in
326 mingw*) 317 mingw* | windows*)
327 dnl Native Windows. 318 dnl Native Windows.
328 dnl mingw64 defines off_t to a 64-bit type already, if 319 dnl mingw64 defines off_t to a 64-bit type already, if
329 dnl _FILE_OFFSET_BITS=64, which is ensured by AC_SYS_LARGEFILE. 320 dnl _FILE_OFFSET_BITS=64, which is ensured by AC_SYS_LARGEFILE.
diff --git a/gl/m4/limits-h.m4 b/gl/m4/limits-h.m4
index 5088fa16..1b619e1e 100644
--- a/gl/m4/limits-h.m4
+++ b/gl/m4/limits-h.m4
@@ -1,10 +1,12 @@
1dnl Check whether limits.h has needed features. 1# limits-h.m4
2 2# serial 1
3dnl Copyright 2016-2023 Free Software Foundation, Inc. 3dnl Copyright 2016-2024 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 7
8dnl Check whether limits.h has needed features.
9
8dnl From Paul Eggert. 10dnl From Paul Eggert.
9 11
10AC_DEFUN_ONCE([gl_LIMITS_H], 12AC_DEFUN_ONCE([gl_LIMITS_H],
@@ -23,14 +25,27 @@ AC_DEFUN_ONCE([gl_LIMITS_H],
23 int wb = WORD_BIT; 25 int wb = WORD_BIT;
24 int ullw = ULLONG_WIDTH; 26 int ullw = ULLONG_WIDTH;
25 int bw = BOOL_WIDTH; 27 int bw = BOOL_WIDTH;
28 int bm = BOOL_MAX;
29 int mblm = MB_LEN_MAX;
26 ]])], 30 ]])],
27 [gl_cv_header_limits_width=yes], 31 [gl_cv_header_limits_width=yes],
28 [gl_cv_header_limits_width=no])]) 32 [gl_cv_header_limits_width=no])])
29 if test "$gl_cv_header_limits_width" = yes; then 33 GL_GENERATE_LIMITS_H=true
30 GL_GENERATE_LIMITS_H=false 34 AS_IF([test "$gl_cv_header_limits_width" = yes],
31 else 35 [AC_CACHE_CHECK([whether limits.h has SSIZE_MAX],
32 GL_GENERATE_LIMITS_H=true 36 [gl_cv_header_limits_ssize_max],
33 fi 37 [AC_COMPILE_IFELSE(
38 [AC_LANG_SOURCE(
39 [[#include <limits.h>
40 #ifndef SSIZE_MAX
41 #error "SSIZE_MAX is not defined"
42 #endif
43 ]])],
44 [gl_cv_header_limits_ssize_max=yes],
45 [gl_cv_header_limits_ssize_max=no])])
46 if test "$gl_cv_header_limits_ssize_max" = yes; then
47 GL_GENERATE_LIMITS_H=false
48 fi])
34]) 49])
35 50
36dnl Unconditionally enables the replacement of <limits.h>. 51dnl Unconditionally enables the replacement of <limits.h>.
diff --git a/gl/m4/localcharset.m4 b/gl/m4/localcharset.m4
index 15b6b2a5..807a5eed 100644
--- a/gl/m4/localcharset.m4
+++ b/gl/m4/localcharset.m4
@@ -1,5 +1,6 @@
1# localcharset.m4 serial 8 1# localcharset.m4
2dnl Copyright (C) 2002, 2004, 2006, 2009-2023 Free Software Foundation, Inc. 2# serial 8
3dnl Copyright (C) 2002, 2004, 2006, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/locale-fr.m4 b/gl/m4/locale-fr.m4
index 8c41fadf..f8d7c543 100644
--- a/gl/m4/locale-fr.m4
+++ b/gl/m4/locale-fr.m4
@@ -1,5 +1,6 @@
1# locale-fr.m4 serial 20 1# locale-fr.m4
2dnl Copyright (C) 2003, 2005-2023 Free Software Foundation, Inc. 2# serial 23
3dnl Copyright (C) 2003, 2005-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -7,7 +8,7 @@ dnl with or without modifications, as long as this notice is preserved.
7dnl From Bruno Haible. 8dnl From Bruno Haible.
8 9
9dnl Determine the name of a french locale with traditional encoding. 10dnl Determine the name of a french locale with traditional encoding.
10AC_DEFUN([gt_LOCALE_FR], 11AC_DEFUN_ONCE([gt_LOCALE_FR],
11[ 12[
12 AC_REQUIRE([AC_CANONICAL_HOST]) 13 AC_REQUIRE([AC_CANONICAL_HOST])
13 AC_REQUIRE([AM_LANGINFO_CODESET]) 14 AC_REQUIRE([AM_LANGINFO_CODESET])
@@ -86,7 +87,7 @@ int main () {
86 # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252", 87 # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252",
87 # "ja" as "Japanese" or "Japanese_Japan.932", 88 # "ja" as "Japanese" or "Japanese_Japan.932",
88 # and similar. 89 # and similar.
89 mingw*) 90 mingw* | windows*)
90 # Test for the native Windows locale name. 91 # Test for the native Windows locale name.
91 if (LC_ALL=French_France.1252 LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then 92 if (LC_ALL=French_France.1252 LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then
92 gt_cv_locale_fr=French_France.1252 93 gt_cv_locale_fr=French_France.1252
@@ -116,7 +117,7 @@ int main () {
116 if (LC_ALL=fr_FR.iso88591 LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then 117 if (LC_ALL=fr_FR.iso88591 LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then
117 gt_cv_locale_fr=fr_FR.iso88591 118 gt_cv_locale_fr=fr_FR.iso88591
118 else 119 else
119 # Test for the Solaris 7 locale name. 120 # Test for the Solaris 10 locale name.
120 if (LC_ALL=fr LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then 121 if (LC_ALL=fr LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then
121 gt_cv_locale_fr=fr 122 gt_cv_locale_fr=fr
122 else 123 else
@@ -133,15 +134,31 @@ int main () {
133 rm -fr conftest* 134 rm -fr conftest*
134 ]) 135 ])
135 LOCALE_FR=$gt_cv_locale_fr 136 LOCALE_FR=$gt_cv_locale_fr
137 case $LOCALE_FR in #(
138 '' | *[[[:space:]\"\$\'*@<:@]]*)
139 dnl This locale name might cause trouble with sh or make.
140 AC_MSG_WARN([invalid locale "$LOCALE_FR"; assuming "none"])
141 LOCALE_FR=none;;
142 esac
136 AC_SUBST([LOCALE_FR]) 143 AC_SUBST([LOCALE_FR])
137]) 144])
138 145
139dnl Determine the name of a french locale with UTF-8 encoding. 146dnl Determine the name of a french locale with UTF-8 encoding.
140AC_DEFUN([gt_LOCALE_FR_UTF8], 147AC_DEFUN_ONCE([gt_LOCALE_FR_UTF8],
141[ 148[
149 AC_REQUIRE([AC_CANONICAL_HOST])
142 AC_REQUIRE([AM_LANGINFO_CODESET]) 150 AC_REQUIRE([AM_LANGINFO_CODESET])
143 AC_CACHE_CHECK([for a french Unicode locale], [gt_cv_locale_fr_utf8], [ 151 AC_CACHE_CHECK([for a french Unicode locale], [gt_cv_locale_fr_utf8], [
144 AC_LANG_CONFTEST([AC_LANG_SOURCE([[ 152 case "$host_os" in
153 *-musl* | midipix*)
154 dnl On musl libc, all kinds of ll_CC.UTF-8 locales exist, even without
155 dnl any locale file on disk. But they are effectively equivalent to the
156 dnl C.UTF-8 locale, except for locale categories (such as LC_MESSSAGES)
157 dnl for which localizations (.mo files) have been installed.
158 gt_cv_locale_fr_utf8=fr_FR.UTF-8
159 ;;
160 *)
161 AC_LANG_CONFTEST([AC_LANG_SOURCE([[
145#include <locale.h> 162#include <locale.h>
146#include <time.h> 163#include <time.h>
147#if HAVE_LANGINFO_CODESET 164#if HAVE_LANGINFO_CODESET
@@ -203,51 +220,82 @@ int main () {
203#endif 220#endif
204 return 0; 221 return 0;
205} 222}
206 ]])]) 223 ]])])
207 if AC_TRY_EVAL([ac_link]) && test -s conftest$ac_exeext; then 224 if AC_TRY_EVAL([ac_link]) && test -s conftest$ac_exeext; then
208 case "$host_os" in 225 case "$host_os" in
209 # Handle native Windows specially, because there setlocale() interprets 226 # Handle native Windows specially, because there setlocale() interprets
210 # "ar" as "Arabic" or "Arabic_Saudi Arabia.1256", 227 # "ar" as "Arabic" or "Arabic_Saudi Arabia.1256",
211 # "fr" or "fra" as "French" or "French_France.1252", 228 # "fr" or "fra" as "French" or "French_France.1252",
212 # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252", 229 # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252",
213 # "ja" as "Japanese" or "Japanese_Japan.932", 230 # "ja" as "Japanese" or "Japanese_Japan.932",
214 # and similar. 231 # and similar.
215 mingw*) 232 mingw* | windows*)
216 # Test for the hypothetical native Windows locale name. 233 # Test for the hypothetical native Windows locale name.
217 if (LC_ALL=French_France.65001 LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then 234 if (LC_ALL=French_France.65001 LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then
218 gt_cv_locale_fr_utf8=French_France.65001 235 gt_cv_locale_fr_utf8=French_France.65001
219 else
220 # None found.
221 gt_cv_locale_fr_utf8=none
222 fi
223 ;;
224 *)
225 # Setting LC_ALL is not enough. Need to set LC_TIME to empty, because
226 # otherwise on Mac OS X 10.3.5 the LC_TIME=C from the beginning of the
227 # configure script would override the LC_ALL setting. Likewise for
228 # LC_CTYPE, which is also set at the beginning of the configure script.
229 # Test for the usual locale name.
230 if (LC_ALL=fr_FR LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then
231 gt_cv_locale_fr_utf8=fr_FR
232 else
233 # Test for the locale name with explicit encoding suffix.
234 if (LC_ALL=fr_FR.UTF-8 LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then
235 gt_cv_locale_fr_utf8=fr_FR.UTF-8
236 else
237 # Test for the Solaris 7 locale name.
238 if (LC_ALL=fr.UTF-8 LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then
239 gt_cv_locale_fr_utf8=fr.UTF-8
240 else 236 else
241 # None found. 237 # None found.
242 gt_cv_locale_fr_utf8=none 238 gt_cv_locale_fr_utf8=none
243 fi 239 fi
244 fi 240 ;;
245 fi 241 *)
246 ;; 242 # Setting LC_ALL is not enough. Need to set LC_TIME to empty, because
247 esac 243 # otherwise on Mac OS X 10.3.5 the LC_TIME=C from the beginning of the
248 fi 244 # configure script would override the LC_ALL setting. Likewise for
249 rm -fr conftest* 245 # LC_CTYPE, which is also set at the beginning of the configure script.
246 # Test for the usual locale name.
247 if (LC_ALL=fr_FR LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then
248 gt_cv_locale_fr_utf8=fr_FR
249 else
250 # Test for the locale name with explicit encoding suffix.
251 if (LC_ALL=fr_FR.UTF-8 LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then
252 gt_cv_locale_fr_utf8=fr_FR.UTF-8
253 else
254 # Test for the Solaris 10 locale name.
255 if (LC_ALL=fr.UTF-8 LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then
256 gt_cv_locale_fr_utf8=fr.UTF-8
257 else
258 # None found.
259 gt_cv_locale_fr_utf8=none
260 fi
261 fi
262 fi
263 ;;
264 esac
265 fi
266 rm -fr conftest*
267 ;;
268 esac
250 ]) 269 ])
251 LOCALE_FR_UTF8=$gt_cv_locale_fr_utf8 270 LOCALE_FR_UTF8=$gt_cv_locale_fr_utf8
271 case $LOCALE_FR_UTF8 in #(
272 '' | *[[[:space:]\"\$\'*@<:@]]*)
273 dnl This locale name might cause trouble with sh or make.
274 AC_MSG_WARN([invalid locale "$LOCALE_FR_UTF8"; assuming "none"])
275 LOCALE_FR_UTF8=none;;
276 esac
252 AC_SUBST([LOCALE_FR_UTF8]) 277 AC_SUBST([LOCALE_FR_UTF8])
278
279 dnl Users of $LOCALE_FR_UTF8 need to know which of the locale categories they
280 dnl can rely on.
281 case "$host_os" in
282 *-musl* | midipix*)
283 dnl On musl libc, locale categories other than LC_CTYPE and LC_MESSAGES
284 dnl are effectively unimplemented.
285 LC_COLLATE_IMPLEMENTED=false
286 LC_NUMERIC_IMPLEMENTED=false
287 LC_TIME_IMPLEMENTED=false
288 LC_MONETARY_IMPLEMENTED=false
289 ;;
290 *)
291 LC_COLLATE_IMPLEMENTED=true
292 LC_NUMERIC_IMPLEMENTED=true
293 LC_TIME_IMPLEMENTED=true
294 LC_MONETARY_IMPLEMENTED=true
295 ;;
296 esac
297 AC_SUBST([LC_COLLATE_IMPLEMENTED])
298 AC_SUBST([LC_NUMERIC_IMPLEMENTED])
299 AC_SUBST([LC_TIME_IMPLEMENTED])
300 AC_SUBST([LC_MONETARY_IMPLEMENTED])
253]) 301])
diff --git a/gl/m4/locale-ja.m4 b/gl/m4/locale-ja.m4
index 25901730..8423bcb9 100644
--- a/gl/m4/locale-ja.m4
+++ b/gl/m4/locale-ja.m4
@@ -1,5 +1,6 @@
1# locale-ja.m4 serial 15 1# locale-ja.m4
2dnl Copyright (C) 2003, 2005-2023 Free Software Foundation, Inc. 2# serial 18
3dnl Copyright (C) 2003, 2005-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -7,7 +8,7 @@ dnl with or without modifications, as long as this notice is preserved.
7dnl From Bruno Haible. 8dnl From Bruno Haible.
8 9
9dnl Determine the name of a japanese locale with EUC-JP encoding. 10dnl Determine the name of a japanese locale with EUC-JP encoding.
10AC_DEFUN([gt_LOCALE_JA], 11AC_DEFUN_ONCE([gt_LOCALE_JA],
11[ 12[
12 AC_REQUIRE([AC_CANONICAL_HOST]) 13 AC_REQUIRE([AC_CANONICAL_HOST])
13 AC_REQUIRE([AM_LANGINFO_CODESET]) 14 AC_REQUIRE([AM_LANGINFO_CODESET])
@@ -90,7 +91,7 @@ int main ()
90 # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252", 91 # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252",
91 # "ja" as "Japanese" or "Japanese_Japan.932", 92 # "ja" as "Japanese" or "Japanese_Japan.932",
92 # and similar. 93 # and similar.
93 mingw*) 94 mingw* | windows*)
94 # Note that on native Windows, the Japanese locale is 95 # Note that on native Windows, the Japanese locale is
95 # Japanese_Japan.932, and CP932 is very different from EUC-JP, so we 96 # Japanese_Japan.932, and CP932 is very different from EUC-JP, so we
96 # cannot use it here. 97 # cannot use it here.
@@ -117,7 +118,7 @@ int main ()
117 if (LC_ALL=ja_JP.EUC LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then 118 if (LC_ALL=ja_JP.EUC LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then
118 gt_cv_locale_ja=ja_JP.EUC 119 gt_cv_locale_ja=ja_JP.EUC
119 else 120 else
120 # Test for the Solaris 7 locale name. 121 # Test for the Solaris 10 locale name.
121 if (LC_ALL=ja LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then 122 if (LC_ALL=ja LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then
122 gt_cv_locale_ja=ja 123 gt_cv_locale_ja=ja
123 else 124 else
@@ -139,5 +140,11 @@ int main ()
139 rm -fr conftest* 140 rm -fr conftest*
140 ]) 141 ])
141 LOCALE_JA=$gt_cv_locale_ja 142 LOCALE_JA=$gt_cv_locale_ja
143 case $LOCALE_JA in #(
144 '' | *[[[:space:]\"\$\'*@<:@]]*)
145 dnl This locale name might cause trouble with sh or make.
146 AC_MSG_WARN([invalid locale "$LOCALE_JA"; assuming "none"])
147 LOCALE_JA=none;;
148 esac
142 AC_SUBST([LOCALE_JA]) 149 AC_SUBST([LOCALE_JA])
143]) 150])
diff --git a/gl/m4/locale-zh.m4 b/gl/m4/locale-zh.m4
index b9f9eef7..7f1a10be 100644
--- a/gl/m4/locale-zh.m4
+++ b/gl/m4/locale-zh.m4
@@ -1,5 +1,6 @@
1# locale-zh.m4 serial 15 1# locale-zh.m4
2dnl Copyright (C) 2003, 2005-2023 Free Software Foundation, Inc. 2# serial 18
3dnl Copyright (C) 2003, 2005-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -7,7 +8,7 @@ dnl with or without modifications, as long as this notice is preserved.
7dnl From Bruno Haible. 8dnl From Bruno Haible.
8 9
9dnl Determine the name of a chinese locale with GB18030 encoding. 10dnl Determine the name of a chinese locale with GB18030 encoding.
10AC_DEFUN([gt_LOCALE_ZH_CN], 11AC_DEFUN_ONCE([gt_LOCALE_ZH_CN],
11[ 12[
12 AC_REQUIRE([AC_CANONICAL_HOST]) 13 AC_REQUIRE([AC_CANONICAL_HOST])
13 AC_REQUIRE([AM_LANGINFO_CODESET]) 14 AC_REQUIRE([AM_LANGINFO_CODESET])
@@ -91,7 +92,7 @@ int main ()
91 # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252", 92 # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252",
92 # "ja" as "Japanese" or "Japanese_Japan.932", 93 # "ja" as "Japanese" or "Japanese_Japan.932",
93 # and similar. 94 # and similar.
94 mingw*) 95 mingw* | windows*)
95 # Test for the hypothetical native Windows locale name. 96 # Test for the hypothetical native Windows locale name.
96 if (LC_ALL=Chinese_China.54936 LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then 97 if (LC_ALL=Chinese_China.54936 LC_TIME= LC_CTYPE= ./conftest; exit) 2>/dev/null; then
97 gt_cv_locale_zh_CN=Chinese_China.54936 98 gt_cv_locale_zh_CN=Chinese_China.54936
@@ -133,5 +134,11 @@ int main ()
133 rm -fr conftest* 134 rm -fr conftest*
134 ]) 135 ])
135 LOCALE_ZH_CN=$gt_cv_locale_zh_CN 136 LOCALE_ZH_CN=$gt_cv_locale_zh_CN
137 case $LOCALE_ZH_CN in #(
138 '' | *[[[:space:]\"\$\'*@<:@]]*)
139 dnl This locale name might cause trouble with sh or make.
140 AC_MSG_WARN([invalid locale "$LOCALE_ZH_CN"; assuming "none"])
141 LOCALE_ZH_CN=none;;
142 esac
136 AC_SUBST([LOCALE_ZH_CN]) 143 AC_SUBST([LOCALE_ZH_CN])
137]) 144])
diff --git a/gl/m4/locale_h.m4 b/gl/m4/locale_h.m4
index a33a0a46..cd1c81ec 100644
--- a/gl/m4/locale_h.m4
+++ b/gl/m4/locale_h.m4
@@ -1,5 +1,6 @@
1# locale_h.m4 serial 28 1# locale_h.m4
2dnl Copyright (C) 2007, 2009-2023 Free Software Foundation, Inc. 2# serial 31
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -59,7 +60,9 @@ AC_DEFUN_ONCE([gl_LOCALE_H],
59 dnl On native Windows with MSVC, merely define these member names as macros. 60 dnl On native Windows with MSVC, merely define these member names as macros.
60 dnl This avoids trouble in C++ mode. 61 dnl This avoids trouble in C++ mode.
61 case "$host_os" in 62 case "$host_os" in
62 mingw*) 63 windows*-msvc*)
64 ;;
65 mingw* | windows*)
63 AC_EGREP_CPP([Special], [ 66 AC_EGREP_CPP([Special], [
64#ifdef _MSC_VER 67#ifdef _MSC_VER
65 Special 68 Special
@@ -152,7 +155,7 @@ AC_DEFUN([gl_LOCALE_H_REQUIRE_DEFAULTS],
152 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETLOCALE]) 155 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETLOCALE])
153 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETLOCALE_NULL]) 156 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETLOCALE_NULL])
154 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DUPLOCALE]) 157 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DUPLOCALE])
155 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOCALENAME]) 158 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOCALENAME_UNSAFE])
156 ]) 159 ])
157 m4_require(GL_MODULE_INDICATOR_PREFIX[_LOCALE_H_MODULE_INDICATOR_DEFAULTS]) 160 m4_require(GL_MODULE_INDICATOR_PREFIX[_LOCALE_H_MODULE_INDICATOR_DEFAULTS])
158 AC_REQUIRE([gl_LOCALE_H_DEFAULTS]) 161 AC_REQUIRE([gl_LOCALE_H_DEFAULTS])
diff --git a/gl/m4/localeconv.m4 b/gl/m4/localeconv.m4
index ae225fed..77d5684f 100644
--- a/gl/m4/localeconv.m4
+++ b/gl/m4/localeconv.m4
@@ -1,5 +1,6 @@
1# localeconv.m4 serial 1 1# localeconv.m4
2dnl Copyright (C) 2012-2023 Free Software Foundation, Inc. 2# serial 3
3dnl Copyright (C) 2012-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -8,10 +9,45 @@ AC_DEFUN([gl_FUNC_LOCALECONV],
8[ 9[
9 AC_REQUIRE([gl_LOCALE_H_DEFAULTS]) 10 AC_REQUIRE([gl_LOCALE_H_DEFAULTS])
10 AC_REQUIRE([gl_LOCALE_H]) 11 AC_REQUIRE([gl_LOCALE_H])
12 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
11 13
12 if test $REPLACE_STRUCT_LCONV = 1; then 14 if test $REPLACE_STRUCT_LCONV = 1; then
13 REPLACE_LOCALECONV=1 15 REPLACE_LOCALECONV=1
14 fi 16 fi
17 if test $REPLACE_LOCALECONV = 0; then
18 dnl Test whether fields of type 'char' are filled correctly.
19 dnl This test fails on mingw 5.0.3.
20 AC_CACHE_CHECK([whether localeconv works],
21 [gl_cv_func_localeconv_works],
22 [AC_RUN_IFELSE(
23 [AC_LANG_SOURCE([[
24 #include <locale.h>
25 #include <limits.h>
26 int main ()
27 {
28 struct lconv *l = localeconv ();
29 return l->frac_digits != CHAR_MAX && l->frac_digits < 0;
30 }
31 ]])],
32 [gl_cv_func_localeconv_works=yes],
33 [gl_cv_func_localeconv_works=no],
34 [case "$host_os" in
35 # Guess yes on glibc systems.
36 *-gnu* | gnu*) gl_cv_func_localeconv_works="guessing yes" ;;
37 # Guess yes on musl systems.
38 *-musl* | midipix*) gl_cv_func_localeconv_works="guessing yes" ;;
39 # Guess no on native Windows.
40 mingw* | windows*) gl_cv_func_localeconv_works="guessing no" ;;
41 # If we don't know, obey --enable-cross-guesses.
42 *) gl_cv_func_localeconv_works="$gl_cross_guess_normal" ;;
43 esac
44 ])
45 ])
46 case "$gl_cv_func_localeconv_works" in
47 *yes) ;;
48 *) REPLACE_LOCALECONV=1 ;;
49 esac
50 fi
15]) 51])
16 52
17# Prerequisites of lib/localeconv.c. 53# Prerequisites of lib/localeconv.c.
@@ -19,4 +55,6 @@ AC_DEFUN([gl_PREREQ_LOCALECONV],
19[ 55[
20 AC_CHECK_MEMBERS([struct lconv.decimal_point], [], [], 56 AC_CHECK_MEMBERS([struct lconv.decimal_point], [], [],
21 [[#include <locale.h>]]) 57 [[#include <locale.h>]])
58 AC_CHECK_MEMBERS([struct lconv.int_p_cs_precedes], [], [],
59 [[#include <locale.h>]])
22]) 60])
diff --git a/gl/m4/lock.m4 b/gl/m4/lock.m4
index 88cf5575..eb0fc6a1 100644
--- a/gl/m4/lock.m4
+++ b/gl/m4/lock.m4
@@ -1,5 +1,6 @@
1# lock.m4 serial 14 1# lock.m4
2dnl Copyright (C) 2005-2023 Free Software Foundation, Inc. 2# serial 14
3dnl Copyright (C) 2005-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/lseek.m4 b/gl/m4/lseek.m4
index fd4f1f27..0bc3d65e 100644
--- a/gl/m4/lseek.m4
+++ b/gl/m4/lseek.m4
@@ -1,5 +1,6 @@
1# lseek.m4 serial 12 1# lseek.m4
2dnl Copyright (C) 2007, 2009-2023 Free Software Foundation, Inc. 2# serial 15
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -13,13 +14,15 @@ AC_DEFUN([gl_FUNC_LSEEK],
13 AC_CHECK_HEADERS_ONCE([unistd.h]) 14 AC_CHECK_HEADERS_ONCE([unistd.h])
14 AC_CACHE_CHECK([whether lseek detects pipes], [gl_cv_func_lseek_pipe], 15 AC_CACHE_CHECK([whether lseek detects pipes], [gl_cv_func_lseek_pipe],
15 [case "$host_os" in 16 [case "$host_os" in
16 mingw*) 17 mingw* | windows*)
17 dnl Native Windows. 18 dnl Native Windows.
18 dnl The result of lseek (fd, (off_t)0, SEEK_CUR) or 19 dnl The result of lseek (fd, (off_t)0, SEEK_CUR) or
19 dnl SetFilePointer(handle, 0, NULL, FILE_CURRENT) 20 dnl SetFilePointer(handle, 0, NULL, FILE_CURRENT)
20 dnl for a pipe depends on the environment: In a Cygwin 1.5 21 dnl for a pipe depends on the environment:
21 dnl environment it succeeds (wrong); in a Cygwin 1.7 environment 22 dnl In a Cygwin 1.5 environment it succeeds (wrong);
22 dnl it fails with a wrong errno value. 23 dnl in a Cygwin 1.7 environment it fails with a wrong errno value;
24 dnl in a Cygwin 2.9.0 environment it fails correctly;
25 dnl in a Cygwin 3.4.6 environment it succeeds again (wrong).
23 gl_cv_func_lseek_pipe=no 26 gl_cv_func_lseek_pipe=no
24 ;; 27 ;;
25 *) 28 *)
@@ -70,9 +73,29 @@ AC_DEFUN([gl_FUNC_LSEEK],
70 REPLACE_LSEEK=1 73 REPLACE_LSEEK=1
71 fi 74 fi
72 75
73 dnl macOS SEEK_DATA is incompatible with other platforms. 76 AS_IF([test $REPLACE_LSEEK = 0],
74 case $host_os in 77 [AC_CACHE_CHECK([whether SEEK_DATA works but is incompatible with GNU],
75 darwin*) 78 [gl_cv_func_lseek_works_but_incompatible],
76 REPLACE_LSEEK=1;; 79 [AC_PREPROC_IFELSE(
77 esac 80 [AC_LANG_SOURCE(
81 dnl Use macOS "9999" to stand for a future fixed macOS version.
82 dnl See ../lib/unistd.in.h and <https://bugs.gnu.org/61386>.
83 [[#include <unistd.h>
84 #if defined __APPLE__ && defined __MACH__ && defined SEEK_DATA
85 # ifdef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
86 # include <AvailabilityMacros.h>
87 # endif
88 # if 99990000 <= MAC_OS_X_VERSION_MIN_REQUIRED
89 # define LSEEK_WORKS_BUT_IS_INCOMPATIBLE_WITH_GNU
90 # endif
91 #endif
92 #ifndef LSEEK_WORKS_BUT_IS_INCOMPATIBLE_WITH_GNU
93 #error "No need to work around the bug"
94 #endif
95 ]])],
96 [gl_cv_func_lseek_works_but_incompatible=yes],
97 [gl_cv_func_lseek_works_but_incompatible=no])])
98 if test "$gl_cv_func_lseek_works_but_incompatible" = yes; then
99 REPLACE_LSEEK=1
100 fi])
78]) 101])
diff --git a/gl/m4/malloc.m4 b/gl/m4/malloc.m4
index 55402924..41a46937 100644
--- a/gl/m4/malloc.m4
+++ b/gl/m4/malloc.m4
@@ -1,5 +1,6 @@
1# malloc.m4 serial 28 1# malloc.m4
2dnl Copyright (C) 2007, 2009-2023 Free Software Foundation, Inc. 2# serial 31
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -16,7 +17,8 @@ AC_DEFUN([_AC_FUNC_MALLOC_IF],
16 [[#include <stdlib.h> 17 [[#include <stdlib.h>
17 ]], 18 ]],
18 [[void *p = malloc (0); 19 [[void *p = malloc (0);
19 int result = !p; 20 void * volatile vp = p;
21 int result = !vp;
20 free (p); 22 free (p);
21 return result;]]) 23 return result;]])
22 ], 24 ],
@@ -25,8 +27,8 @@ AC_DEFUN([_AC_FUNC_MALLOC_IF],
25 [case "$host_os" in 27 [case "$host_os" in
26 # Guess yes on platforms where we know the result. 28 # Guess yes on platforms where we know the result.
27 *-gnu* | freebsd* | netbsd* | openbsd* | bitrig* \ 29 *-gnu* | freebsd* | netbsd* | openbsd* | bitrig* \
28 | gnu* | *-musl* | midnightbsd* \ 30 | gnu* | *-musl* | midipix* | midnightbsd* \
29 | hpux* | solaris* | cygwin* | mingw* | msys* ) 31 | hpux* | solaris* | cygwin* | mingw* | windows* | msys* )
30 ac_cv_func_malloc_0_nonnull="guessing yes" ;; 32 ac_cv_func_malloc_0_nonnull="guessing yes" ;;
31 # If we don't know, obey --enable-cross-guesses. 33 # If we don't know, obey --enable-cross-guesses.
32 *) ac_cv_func_malloc_0_nonnull="$gl_cross_guess_normal" ;; 34 *) ac_cv_func_malloc_0_nonnull="$gl_cross_guess_normal" ;;
@@ -128,7 +130,7 @@ AC_DEFUN([gl_CHECK_MALLOC_POSIX],
128 dnl except on those platforms where we have seen 'test-malloc-gnu', 130 dnl except on those platforms where we have seen 'test-malloc-gnu',
129 dnl 'test-realloc-gnu', 'test-calloc-gnu' fail. 131 dnl 'test-realloc-gnu', 'test-calloc-gnu' fail.
130 case "$host_os" in 132 case "$host_os" in
131 mingw*) 133 mingw* | windows*)
132 gl_cv_func_malloc_posix=no ;; 134 gl_cv_func_malloc_posix=no ;;
133 irix* | solaris*) 135 irix* | solaris*)
134 dnl On IRIX 6.5, the three functions return NULL with errno unset 136 dnl On IRIX 6.5, the three functions return NULL with errno unset
diff --git a/gl/m4/malloca.m4 b/gl/m4/malloca.m4
index 1d777ebe..9e09d22c 100644
--- a/gl/m4/malloca.m4
+++ b/gl/m4/malloca.m4
@@ -1,5 +1,6 @@
1# malloca.m4 serial 2 1# malloca.m4
2dnl Copyright (C) 2003-2004, 2006-2007, 2009-2023 Free Software Foundation, 2# serial 2
3dnl Copyright (C) 2003-2004, 2006-2007, 2009-2024 Free Software Foundation,
3dnl Inc. 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,
diff --git a/gl/m4/math_h.m4 b/gl/m4/math_h.m4
index d2e90ff1..4b26c9e9 100644
--- a/gl/m4/math_h.m4
+++ b/gl/m4/math_h.m4
@@ -1,5 +1,6 @@
1# math_h.m4 serial 125 1# math_h.m4
2dnl Copyright (C) 2007-2023 Free Software Foundation, Inc. 2# serial 138
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -42,15 +43,21 @@ AC_DEFUN_ONCE([gl_MATH_H],
42 cbrt cbrtf cbrtl ceilf ceill copysign copysignf copysignl cosf cosl coshf 43 cbrt cbrtf cbrtl ceilf ceill copysign copysignf copysignl cosf cosl coshf
43 expf expl exp2 exp2f exp2l expm1 expm1f expm1l 44 expf expl exp2 exp2f exp2l expm1 expm1f expm1l
44 fabsf fabsl floorf floorl fma fmaf fmal 45 fabsf fabsl floorf floorl fma fmaf fmal
45 fmod fmodf fmodl frexpf frexpl hypotf hypotl 46 fmod fmodf fmodl frexpf frexpl
47 getpayload getpayloadf getpayloadl
48 hypotf hypotl
46 ilogb ilogbf ilogbl 49 ilogb ilogbf ilogbl
47 ldexpf ldexpl 50 ldexpf ldexpl
48 log logf logl log10 log10f log10l log1p log1pf log1pl log2 log2f log2l 51 log logf logl log10 log10f log10l log1p log1pf log1pl log2 log2f log2l
49 logb logbf logbl 52 logb logbf logbl
50 modf modff modfl powf 53 modf modff modfl powf
51 remainder remainderf remainderl 54 remainder remainderf remainderl
52 rint rintf rintl round roundf roundl sinf sinl sinhf sqrtf sqrtl 55 rint rintf rintl round roundf roundl
53 tanf tanl tanhf trunc truncf truncl]) 56 setpayload setpayloadf setpayloadl
57 setpayloadsig setpayloadsigf setpayloadsigl
58 sinf sinl sinhf sqrtf sqrtl
59 tanf tanl tanhf totalorder totalorderf totalorderl totalordermag
60 totalordermagf totalordermagl trunc truncf truncl])
54]) 61])
55 62
56# gl_MATH_MODULE_INDICATOR([modulename]) 63# gl_MATH_MODULE_INDICATOR([modulename])
@@ -113,6 +120,9 @@ AC_DEFUN([gl_MATH_H_REQUIRE_DEFAULTS],
113 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREXPF]) 120 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREXPF])
114 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREXP]) 121 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREXP])
115 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREXPL]) 122 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREXPL])
123 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETPAYLOAD])
124 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETPAYLOADF])
125 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETPAYLOADL])
116 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_HYPOT]) 126 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_HYPOT])
117 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_HYPOTF]) 127 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_HYPOTF])
118 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_HYPOTL]) 128 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_HYPOTL])
@@ -125,6 +135,7 @@ AC_DEFUN([gl_MATH_H_REQUIRE_DEFAULTS],
125 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ISNANF]) 135 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ISNANF])
126 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ISNAND]) 136 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ISNAND])
127 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ISNANL]) 137 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ISNANL])
138 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LDEXP])
128 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LDEXPF]) 139 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LDEXPF])
129 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LDEXPL]) 140 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LDEXPL])
130 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOG]) 141 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOG])
@@ -155,6 +166,12 @@ AC_DEFUN([gl_MATH_H_REQUIRE_DEFAULTS],
155 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ROUND]) 166 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ROUND])
156 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ROUNDF]) 167 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ROUNDF])
157 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ROUNDL]) 168 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ROUNDL])
169 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOAD])
170 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOADF])
171 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOADL])
172 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOADSIG])
173 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOADSIGF])
174 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETPAYLOADSIGL])
158 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SIGNBIT]) 175 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SIGNBIT])
159 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SINF]) 176 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SINF])
160 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SINL]) 177 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SINL])
@@ -164,6 +181,12 @@ AC_DEFUN([gl_MATH_H_REQUIRE_DEFAULTS],
164 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TANF]) 181 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TANF])
165 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TANL]) 182 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TANL])
166 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TANHF]) 183 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TANHF])
184 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TOTALORDER])
185 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TOTALORDERF])
186 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TOTALORDERL])
187 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TOTALORDERMAG])
188 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TOTALORDERMAGF])
189 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TOTALORDERMAGL])
167 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TRUNC]) 190 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TRUNC])
168 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TRUNCF]) 191 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TRUNCF])
169 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TRUNCL]) 192 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TRUNCL])
@@ -209,6 +232,9 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
209 HAVE_FMODF=1; AC_SUBST([HAVE_FMODF]) 232 HAVE_FMODF=1; AC_SUBST([HAVE_FMODF])
210 HAVE_FMODL=1; AC_SUBST([HAVE_FMODL]) 233 HAVE_FMODL=1; AC_SUBST([HAVE_FMODL])
211 HAVE_FREXPF=1; AC_SUBST([HAVE_FREXPF]) 234 HAVE_FREXPF=1; AC_SUBST([HAVE_FREXPF])
235 HAVE_GETPAYLOAD=1; AC_SUBST([HAVE_GETPAYLOAD])
236 HAVE_GETPAYLOADF=1; AC_SUBST([HAVE_GETPAYLOADF])
237 HAVE_GETPAYLOADL=1; AC_SUBST([HAVE_GETPAYLOADL])
212 HAVE_HYPOTF=1; AC_SUBST([HAVE_HYPOTF]) 238 HAVE_HYPOTF=1; AC_SUBST([HAVE_HYPOTF])
213 HAVE_HYPOTL=1; AC_SUBST([HAVE_HYPOTL]) 239 HAVE_HYPOTL=1; AC_SUBST([HAVE_HYPOTL])
214 HAVE_ILOGB=1; AC_SUBST([HAVE_ILOGB]) 240 HAVE_ILOGB=1; AC_SUBST([HAVE_ILOGB])
@@ -234,6 +260,12 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
234 HAVE_REMAINDERF=1; AC_SUBST([HAVE_REMAINDERF]) 260 HAVE_REMAINDERF=1; AC_SUBST([HAVE_REMAINDERF])
235 HAVE_RINT=1; AC_SUBST([HAVE_RINT]) 261 HAVE_RINT=1; AC_SUBST([HAVE_RINT])
236 HAVE_RINTL=1; AC_SUBST([HAVE_RINTL]) 262 HAVE_RINTL=1; AC_SUBST([HAVE_RINTL])
263 HAVE_SETPAYLOAD=1; AC_SUBST([HAVE_SETPAYLOAD])
264 HAVE_SETPAYLOADF=1; AC_SUBST([HAVE_SETPAYLOADF])
265 HAVE_SETPAYLOADL=1; AC_SUBST([HAVE_SETPAYLOADL])
266 HAVE_SETPAYLOADSIG=1; AC_SUBST([HAVE_SETPAYLOADSIG])
267 HAVE_SETPAYLOADSIGF=1; AC_SUBST([HAVE_SETPAYLOADSIGF])
268 HAVE_SETPAYLOADSIGL=1; AC_SUBST([HAVE_SETPAYLOADSIGL])
237 HAVE_SINF=1; AC_SUBST([HAVE_SINF]) 269 HAVE_SINF=1; AC_SUBST([HAVE_SINF])
238 HAVE_SINL=1; AC_SUBST([HAVE_SINL]) 270 HAVE_SINL=1; AC_SUBST([HAVE_SINL])
239 HAVE_SINHF=1; AC_SUBST([HAVE_SINHF]) 271 HAVE_SINHF=1; AC_SUBST([HAVE_SINHF])
@@ -242,6 +274,12 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
242 HAVE_TANF=1; AC_SUBST([HAVE_TANF]) 274 HAVE_TANF=1; AC_SUBST([HAVE_TANF])
243 HAVE_TANL=1; AC_SUBST([HAVE_TANL]) 275 HAVE_TANL=1; AC_SUBST([HAVE_TANL])
244 HAVE_TANHF=1; AC_SUBST([HAVE_TANHF]) 276 HAVE_TANHF=1; AC_SUBST([HAVE_TANHF])
277 HAVE_TOTALORDER=1; AC_SUBST([HAVE_TOTALORDER])
278 HAVE_TOTALORDERF=1; AC_SUBST([HAVE_TOTALORDERF])
279 HAVE_TOTALORDERL=1; AC_SUBST([HAVE_TOTALORDERL])
280 HAVE_TOTALORDERMAG=1; AC_SUBST([HAVE_TOTALORDERMAG])
281 HAVE_TOTALORDERMAGF=1; AC_SUBST([HAVE_TOTALORDERMAGF])
282 HAVE_TOTALORDERMAGL=1; AC_SUBST([HAVE_TOTALORDERMAGL])
245 HAVE_DECL_ACOSL=1; AC_SUBST([HAVE_DECL_ACOSL]) 283 HAVE_DECL_ACOSL=1; AC_SUBST([HAVE_DECL_ACOSL])
246 HAVE_DECL_ASINL=1; AC_SUBST([HAVE_DECL_ASINL]) 284 HAVE_DECL_ASINL=1; AC_SUBST([HAVE_DECL_ASINL])
247 HAVE_DECL_ATANL=1; AC_SUBST([HAVE_DECL_ATANL]) 285 HAVE_DECL_ATANL=1; AC_SUBST([HAVE_DECL_ATANL])
@@ -309,6 +347,9 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
309 REPLACE_FREXPF=0; AC_SUBST([REPLACE_FREXPF]) 347 REPLACE_FREXPF=0; AC_SUBST([REPLACE_FREXPF])
310 REPLACE_FREXP=0; AC_SUBST([REPLACE_FREXP]) 348 REPLACE_FREXP=0; AC_SUBST([REPLACE_FREXP])
311 REPLACE_FREXPL=0; AC_SUBST([REPLACE_FREXPL]) 349 REPLACE_FREXPL=0; AC_SUBST([REPLACE_FREXPL])
350 REPLACE_GETPAYLOAD=0; AC_SUBST([REPLACE_GETPAYLOAD])
351 REPLACE_GETPAYLOADF=0; AC_SUBST([REPLACE_GETPAYLOADF])
352 REPLACE_GETPAYLOADL=0; AC_SUBST([REPLACE_GETPAYLOADL])
312 REPLACE_HUGE_VAL=0; AC_SUBST([REPLACE_HUGE_VAL]) 353 REPLACE_HUGE_VAL=0; AC_SUBST([REPLACE_HUGE_VAL])
313 REPLACE_HYPOT=0; AC_SUBST([REPLACE_HYPOT]) 354 REPLACE_HYPOT=0; AC_SUBST([REPLACE_HYPOT])
314 REPLACE_HYPOTF=0; AC_SUBST([REPLACE_HYPOTF]) 355 REPLACE_HYPOTF=0; AC_SUBST([REPLACE_HYPOTF])
@@ -319,6 +360,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
319 REPLACE_ISFINITE=0; AC_SUBST([REPLACE_ISFINITE]) 360 REPLACE_ISFINITE=0; AC_SUBST([REPLACE_ISFINITE])
320 REPLACE_ISINF=0; AC_SUBST([REPLACE_ISINF]) 361 REPLACE_ISINF=0; AC_SUBST([REPLACE_ISINF])
321 REPLACE_ISNAN=0; AC_SUBST([REPLACE_ISNAN]) 362 REPLACE_ISNAN=0; AC_SUBST([REPLACE_ISNAN])
363 REPLACE_LDEXP=0; AC_SUBST([REPLACE_LDEXP])
322 REPLACE_LDEXPL=0; AC_SUBST([REPLACE_LDEXPL]) 364 REPLACE_LDEXPL=0; AC_SUBST([REPLACE_LDEXPL])
323 REPLACE_LOG=0; AC_SUBST([REPLACE_LOG]) 365 REPLACE_LOG=0; AC_SUBST([REPLACE_LOG])
324 REPLACE_LOGF=0; AC_SUBST([REPLACE_LOGF]) 366 REPLACE_LOGF=0; AC_SUBST([REPLACE_LOGF])
@@ -354,6 +396,12 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
354 REPLACE_SQRTL=0; AC_SUBST([REPLACE_SQRTL]) 396 REPLACE_SQRTL=0; AC_SUBST([REPLACE_SQRTL])
355 REPLACE_TANF=0; AC_SUBST([REPLACE_TANF]) 397 REPLACE_TANF=0; AC_SUBST([REPLACE_TANF])
356 REPLACE_TANHF=0; AC_SUBST([REPLACE_TANHF]) 398 REPLACE_TANHF=0; AC_SUBST([REPLACE_TANHF])
399 REPLACE_TOTALORDER=0; AC_SUBST([REPLACE_TOTALORDER])
400 REPLACE_TOTALORDERF=0; AC_SUBST([REPLACE_TOTALORDERF])
401 REPLACE_TOTALORDERL=0; AC_SUBST([REPLACE_TOTALORDERL])
402 REPLACE_TOTALORDERMAG=0; AC_SUBST([REPLACE_TOTALORDERMAG])
403 REPLACE_TOTALORDERMAGF=0; AC_SUBST([REPLACE_TOTALORDERMAGF])
404 REPLACE_TOTALORDERMAGL=0; AC_SUBST([REPLACE_TOTALORDERMAGL])
357 REPLACE_TRUNC=0; AC_SUBST([REPLACE_TRUNC]) 405 REPLACE_TRUNC=0; AC_SUBST([REPLACE_TRUNC])
358 REPLACE_TRUNCF=0; AC_SUBST([REPLACE_TRUNCF]) 406 REPLACE_TRUNCF=0; AC_SUBST([REPLACE_TRUNCF])
359 REPLACE_TRUNCL=0; AC_SUBST([REPLACE_TRUNCL]) 407 REPLACE_TRUNCL=0; AC_SUBST([REPLACE_TRUNCL])
@@ -364,7 +412,7 @@ AC_DEFUN([gl_MATH_H_DEFAULTS],
364# Sets variable HAVE_SAME_LONG_DOUBLE_AS_DOUBLE to 0 or 1, and defines 412# Sets variable HAVE_SAME_LONG_DOUBLE_AS_DOUBLE to 0 or 1, and defines
365# HAVE_SAME_LONG_DOUBLE_AS_DOUBLE accordingly. 413# HAVE_SAME_LONG_DOUBLE_AS_DOUBLE accordingly.
366# The currently known platforms where this is the case are: 414# The currently known platforms where this is the case are:
367# Linux/HPPA, Minix 3.1.8, AIX 5, AIX 6 and 7 with xlc, MSVC 9. 415# Linux/HPPA, NetBSD/sparc32, Minix 3.1.8, AIX 5, AIX 6 and 7 with xlc, MSVC 9.
368AC_DEFUN([gl_LONG_DOUBLE_VS_DOUBLE], 416AC_DEFUN([gl_LONG_DOUBLE_VS_DOUBLE],
369[ 417[
370 AC_CACHE_CHECK([whether long double and double are the same], 418 AC_CACHE_CHECK([whether long double and double are the same],
diff --git a/gl/m4/mbrtowc.m4 b/gl/m4/mbrtowc.m4
index bb393041..62c4fdb3 100644
--- a/gl/m4/mbrtowc.m4
+++ b/gl/m4/mbrtowc.m4
@@ -1,5 +1,6 @@
1# mbrtowc.m4 serial 38 -*- coding: utf-8 -*- 1# mbrtowc.m4
2dnl Copyright (C) 2001-2002, 2004-2005, 2008-2023 Free Software Foundation, 2# serial 44 -*- coding: utf-8 -*-
3dnl Copyright (C) 2001-2002, 2004-2005, 2008-2024 Free Software Foundation,
3dnl Inc. 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,
@@ -91,20 +92,25 @@ AC_DEFUN([gl_FUNC_MBRTOWC],
91 fi 92 fi
92 if test $REPLACE_MBSTATE_T = 1; then 93 if test $REPLACE_MBSTATE_T = 1; then
93 case "$host_os" in 94 case "$host_os" in
94 mingw*) LIB_MBRTOWC= ;; 95 mingw* | windows*)
96 MBRTOWC_LIB=
97 ;;
95 *) 98 *)
96 gl_WEAK_SYMBOLS 99 gl_WEAK_SYMBOLS
97 case "$gl_cv_have_weak" in 100 case "$gl_cv_have_weak" in
98 *yes) LIB_MBRTOWC= ;; 101 *yes) MBRTOWC_LIB= ;;
99 *) LIB_MBRTOWC="$LIBPTHREAD" ;; 102 *) MBRTOWC_LIB="$LIBPTHREAD" ;;
100 esac 103 esac
101 ;; 104 ;;
102 esac 105 esac
103 else 106 else
104 LIB_MBRTOWC= 107 MBRTOWC_LIB=
105 fi 108 fi
106 dnl LIB_MBRTOWC is expected to be '-pthread' or '-lpthread' on AIX 109 dnl MBRTOWC_LIB is expected to be '-pthread' or '-lpthread' on AIX
107 dnl with gcc or xlc, and empty otherwise. 110 dnl with gcc or xlc, and empty otherwise.
111 AC_SUBST([MBRTOWC_LIB])
112 dnl For backward compatibility.
113 LIB_MBRTOWC="$MBRTOWC_LIB"
108 AC_SUBST([LIB_MBRTOWC]) 114 AC_SUBST([LIB_MBRTOWC])
109]) 115])
110 116
@@ -114,7 +120,7 @@ dnl Result is REPLACE_MBSTATE_T.
114dnl When this is set to 1, we replace both mbsinit() and mbrtowc(), in order to 120dnl When this is set to 1, we replace both mbsinit() and mbrtowc(), in order to
115dnl avoid inconsistencies. 121dnl avoid inconsistencies.
116 122
117AC_DEFUN([gl_MBSTATE_T_BROKEN], 123AC_DEFUN_ONCE([gl_MBSTATE_T_BROKEN],
118[ 124[
119 AC_REQUIRE([gl_WCHAR_H_DEFAULTS]) 125 AC_REQUIRE([gl_WCHAR_H_DEFAULTS])
120 AC_REQUIRE([AC_CANONICAL_HOST]) 126 AC_REQUIRE([AC_CANONICAL_HOST])
@@ -126,7 +132,7 @@ AC_DEFUN([gl_MBSTATE_T_BROKEN],
126 dnl to override it, even if - like on MSVC - mbsinit() is only defined as 132 dnl to override it, even if - like on MSVC - mbsinit() is only defined as
127 dnl an inline function, not as a global function. 133 dnl an inline function, not as a global function.
128 if case "$host_os" in 134 if case "$host_os" in
129 mingw*) true ;; 135 mingw* | windows*) true ;;
130 *) test $ac_cv_func_mbsinit = yes ;; 136 *) test $ac_cv_func_mbsinit = yes ;;
131 esac \ 137 esac \
132 && test $ac_cv_func_mbrtowc = yes; then 138 && test $ac_cv_func_mbrtowc = yes; then
@@ -408,14 +414,16 @@ AC_DEFUN([gl_MBRTOWC_RETVAL],
408 dnl is present. 414 dnl is present.
409changequote(,)dnl 415changequote(,)dnl
410 case "$host_os" in 416 case "$host_os" in
411 # Guess no on HP-UX, Solaris, native Windows. 417 # Guess no on HP-UX, Solaris, native Windows.
412 hpux* | solaris* | mingw*) gl_cv_func_mbrtowc_retval="guessing no" ;; 418 hpux* | solaris* | mingw* | windows*)
413 # Guess yes otherwise. 419 gl_cv_func_mbrtowc_retval="guessing no" ;;
414 *) gl_cv_func_mbrtowc_retval="guessing yes" ;; 420 # Guess yes otherwise.
421 *)
422 gl_cv_func_mbrtowc_retval="guessing yes" ;;
415 esac 423 esac
416changequote([,])dnl 424changequote([,])dnl
417 if test $LOCALE_FR_UTF8 != none || test $LOCALE_JA != none \ 425 if test $LOCALE_FR_UTF8 != none || test $LOCALE_JA != none \
418 || { case "$host_os" in mingw*) true;; *) false;; esac; }; then 426 || { case "$host_os" in mingw* | windows*) true;; *) false;; esac; }; then
419 AC_RUN_IFELSE( 427 AC_RUN_IFELSE(
420 [AC_LANG_SOURCE([[ 428 [AC_LANG_SOURCE([[
421#include <locale.h> 429#include <locale.h>
@@ -426,7 +434,8 @@ int main ()
426 int result = 0; 434 int result = 0;
427 int found_some_locale = 0; 435 int found_some_locale = 0;
428 /* This fails on Solaris. */ 436 /* This fails on Solaris. */
429 if (setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL) 437 if (strcmp ("$LOCALE_FR_UTF8", "none") != 0
438 && setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL)
430 { 439 {
431 char input[] = "B\303\274\303\237er"; /* "Büßer" */ 440 char input[] = "B\303\274\303\237er"; /* "Büßer" */
432 mbstate_t state; 441 mbstate_t state;
@@ -442,7 +451,8 @@ int main ()
442 found_some_locale = 1; 451 found_some_locale = 1;
443 } 452 }
444 /* This fails on HP-UX 11.11. */ 453 /* This fails on HP-UX 11.11. */
445 if (setlocale (LC_ALL, "$LOCALE_JA") != NULL) 454 if (strcmp ("$LOCALE_JA", "none") != 0
455 && setlocale (LC_ALL, "$LOCALE_JA") != NULL)
446 { 456 {
447 char input[] = "B\217\253\344\217\251\316er"; /* "Büßer" */ 457 char input[] = "B\217\253\344\217\251\316er"; /* "Büßer" */
448 mbstate_t state; 458 mbstate_t state;
@@ -577,13 +587,13 @@ AC_DEFUN([gl_MBRTOWC_STORES_INCOMPLETE],
577 dnl is present. 587 dnl is present.
578changequote(,)dnl 588changequote(,)dnl
579 case "$host_os" in 589 case "$host_os" in
580 # Guess yes on native Windows. 590 # Guess yes on native Windows.
581 mingw*) gl_cv_func_mbrtowc_stores_incomplete="guessing yes" ;; 591 mingw* | windows*) gl_cv_func_mbrtowc_stores_incomplete="guessing yes" ;;
582 *) gl_cv_func_mbrtowc_stores_incomplete="guessing no" ;; 592 *) gl_cv_func_mbrtowc_stores_incomplete="guessing no" ;;
583 esac 593 esac
584changequote([,])dnl 594changequote([,])dnl
585 case "$host_os" in 595 case "$host_os" in
586 mingw*) 596 mingw* | windows*)
587 AC_RUN_IFELSE( 597 AC_RUN_IFELSE(
588 [AC_LANG_SOURCE([[ 598 [AC_LANG_SOURCE([[
589#include <locale.h> 599#include <locale.h>
@@ -677,31 +687,28 @@ AC_DEFUN([gl_MBRTOWC_EMPTY_INPUT],
677 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles 687 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
678 AC_CACHE_CHECK([whether mbrtowc works on empty input], 688 AC_CACHE_CHECK([whether mbrtowc works on empty input],
679 [gl_cv_func_mbrtowc_empty_input], 689 [gl_cv_func_mbrtowc_empty_input],
680 [ 690 [AC_RUN_IFELSE(
681 dnl Initial guess, used when cross-compiling or when no suitable locale 691 [AC_LANG_SOURCE([[
682 dnl is present. 692 #include <wchar.h>
683changequote(,)dnl 693 static wchar_t wc;
684 case "$host_os" in 694 static mbstate_t mbs;
685 # Guess no on AIX and glibc systems. 695 int
686 aix* | *-gnu* | gnu*) gl_cv_func_mbrtowc_empty_input="guessing no" ;; 696 main (void)
687 # Guess yes on native Windows. 697 {
688 mingw*) gl_cv_func_mbrtowc_empty_input="guessing yes" ;; 698 return mbrtowc (&wc, "", 0, &mbs) != (size_t) -2;
689 *) gl_cv_func_mbrtowc_empty_input="guessing yes" ;; 699 }]])],
690 esac 700 [gl_cv_func_mbrtowc_empty_input=yes],
691changequote([,])dnl 701 [gl_cv_func_mbrtowc_empty_input=no],
692 AC_RUN_IFELSE( 702 [case "$host_os" in
693 [AC_LANG_SOURCE([[ 703 # Guess no on AIX and glibc systems.
694 #include <wchar.h> 704 aix* | *-gnu* | gnu*) gl_cv_func_mbrtowc_empty_input="guessing no" ;;
695 static wchar_t wc; 705 # Guess no on Android.
696 static mbstate_t mbs; 706 linux*-android*) gl_cv_func_mbrtowc_empty_input="guessing no" ;;
697 int 707 # Guess no on native Windows.
698 main (void) 708 mingw* | windows*) gl_cv_func_mbrtowc_empty_input="guessing no" ;;
699 { 709 *) gl_cv_func_mbrtowc_empty_input="guessing yes" ;;
700 return mbrtowc (&wc, "", 0, &mbs) != (size_t) -2; 710 esac
701 }]])], 711 ])
702 [gl_cv_func_mbrtowc_empty_input=yes],
703 [gl_cv_func_mbrtowc_empty_input=no],
704 [:])
705 ]) 712 ])
706]) 713])
707 714
@@ -709,18 +716,17 @@ dnl Test whether mbrtowc reports encoding errors in the C locale.
709dnl Although POSIX was never intended to allow this, the GNU C Library 716dnl Although POSIX was never intended to allow this, the GNU C Library
710dnl and other implementations do it. See: 717dnl and other implementations do it. See:
711dnl https://sourceware.org/bugzilla/show_bug.cgi?id=19932 718dnl https://sourceware.org/bugzilla/show_bug.cgi?id=19932
719dnl POSIX has now clarified it:
720dnl <https://pubs.opengroup.org/onlinepubs/9699919799/functions/mbrtowc.html>
721dnl says: "In the POSIX locale an [EILSEQ] error cannot occur since all byte
722dnl values are valid characters."
712 723
713AC_DEFUN([gl_MBRTOWC_C_LOCALE], 724AC_DEFUN([gl_MBRTOWC_C_LOCALE],
714[ 725[
715 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles 726 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
716 AC_CACHE_CHECK([whether the C locale is free of encoding errors], 727 AC_CACHE_CHECK([whether the C locale is free of encoding errors],
717 [gl_cv_func_mbrtowc_C_locale_sans_EILSEQ], 728 [gl_cv_func_mbrtowc_C_locale_sans_EILSEQ],
718 [ 729 [AC_RUN_IFELSE(
719 dnl Initial guess, used when cross-compiling or when no suitable locale
720 dnl is present.
721 gl_cv_func_mbrtowc_C_locale_sans_EILSEQ="$gl_cross_guess_normal"
722
723 AC_RUN_IFELSE(
724 [AC_LANG_PROGRAM( 730 [AC_LANG_PROGRAM(
725 [[#include <limits.h> 731 [[#include <limits.h>
726 #include <locale.h> 732 #include <locale.h>
@@ -741,13 +747,14 @@ AC_DEFUN([gl_MBRTOWC_C_LOCALE],
741 } 747 }
742 return 0; 748 return 0;
743 ]])], 749 ]])],
744 [gl_cv_func_mbrtowc_C_locale_sans_EILSEQ=yes], 750 [gl_cv_func_mbrtowc_C_locale_sans_EILSEQ=yes],
745 [gl_cv_func_mbrtowc_C_locale_sans_EILSEQ=no], 751 [gl_cv_func_mbrtowc_C_locale_sans_EILSEQ=no],
746 [case "$host_os" in 752 [case "$host_os" in
747 # Guess yes on native Windows. 753 # Guess yes on native Windows.
748 mingw*) gl_cv_func_mbrtowc_C_locale_sans_EILSEQ="guessing yes" ;; 754 mingw* | windows*) gl_cv_func_mbrtowc_C_locale_sans_EILSEQ="guessing yes" ;;
749 esac 755 *) gl_cv_func_mbrtowc_C_locale_sans_EILSEQ="$gl_cross_guess_normal" ;;
750 ]) 756 esac
757 ])
751 ]) 758 ])
752]) 759])
753 760
diff --git a/gl/m4/mbsinit.m4 b/gl/m4/mbsinit.m4
index c388a8b9..10c86ba9 100644
--- a/gl/m4/mbsinit.m4
+++ b/gl/m4/mbsinit.m4
@@ -1,5 +1,6 @@
1# mbsinit.m4 serial 9 1# mbsinit.m4
2dnl Copyright (C) 2008, 2010-2023 Free Software Foundation, Inc. 2# serial 10
3dnl Copyright (C) 2008, 2010-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -32,7 +33,7 @@ AC_DEFUN([gl_FUNC_MBSINIT],
32 dnl states produced by mbrtowc() for an incomplete multibyte character 33 dnl states produced by mbrtowc() for an incomplete multibyte character
33 dnl in multibyte locales. 34 dnl in multibyte locales.
34 case "$host_os" in 35 case "$host_os" in
35 mingw*) REPLACE_MBSINIT=1 ;; 36 mingw* | windows*) REPLACE_MBSINIT=1 ;;
36 esac 37 esac
37 fi 38 fi
38 fi 39 fi
diff --git a/gl/m4/mbstate_t.m4 b/gl/m4/mbstate_t.m4
index dcd66b96..66d65cd7 100644
--- a/gl/m4/mbstate_t.m4
+++ b/gl/m4/mbstate_t.m4
@@ -1,5 +1,6 @@
1# mbstate_t.m4 serial 14 1# mbstate_t.m4
2dnl Copyright (C) 2000-2002, 2008-2023 Free Software Foundation, Inc. 2# serial 14
3dnl Copyright (C) 2000-2002, 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/mbtowc.m4 b/gl/m4/mbtowc.m4
index 7823be0e..603b0c1a 100644
--- a/gl/m4/mbtowc.m4
+++ b/gl/m4/mbtowc.m4
@@ -1,5 +1,6 @@
1# mbtowc.m4 serial 3 1# mbtowc.m4
2dnl Copyright (C) 2011-2023 Free Software Foundation, Inc. 2# serial 5
3dnl Copyright (C) 2011-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -8,9 +9,12 @@ AC_DEFUN([gl_FUNC_MBTOWC],
8[ 9[
9 AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) 10 AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
10 11
11 AC_CHECK_FUNCS([mbtowc]) 12 gl_CHECK_FUNCS_ANDROID([mbtowc], [[#include <stdlib.h>]])
12 if test $ac_cv_func_mbtowc = no; then 13 if test $ac_cv_func_mbtowc = no; then
13 HAVE_MBTOWC=0 14 HAVE_MBTOWC=0
15 case "$gl_cv_onwards_func_mbtowc" in
16 future*) REPLACE_MBTOWC=1 ;;
17 esac
14 else 18 else
15 if false; then 19 if false; then
16 REPLACE_MBTOWC=1 20 REPLACE_MBTOWC=1
diff --git a/gl/m4/memchr.m4 b/gl/m4/memchr.m4
index 4f1aed01..346a2882 100644
--- a/gl/m4/memchr.m4
+++ b/gl/m4/memchr.m4
@@ -1,5 +1,6 @@
1# memchr.m4 serial 18 1# memchr.m4
2dnl Copyright (C) 2002-2004, 2009-2023 Free Software Foundation, Inc. 2# serial 19
3dnl Copyright (C) 2002-2004, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -85,12 +86,12 @@ AC_DEFUN_ONCE([gl_FUNC_MEMCHR],
85 [gl_cv_func_memchr_works=yes], 86 [gl_cv_func_memchr_works=yes],
86 [gl_cv_func_memchr_works=no], 87 [gl_cv_func_memchr_works=no],
87 [case "$host_os" in 88 [case "$host_os" in
88 # Guess no on Android. 89 # Guess no on Android.
89 linux*-android*) gl_cv_func_memchr_works="guessing no" ;; 90 linux*-android*) gl_cv_func_memchr_works="guessing no" ;;
90 # Guess yes on native Windows. 91 # Guess yes on native Windows.
91 mingw*) gl_cv_func_memchr_works="guessing yes" ;; 92 mingw* | windows*) gl_cv_func_memchr_works="guessing yes" ;;
92 # If we don't know, obey --enable-cross-guesses. 93 # If we don't know, obey --enable-cross-guesses.
93 *) gl_cv_func_memchr_works="$gl_cross_guess_normal" ;; 94 *) gl_cv_func_memchr_works="$gl_cross_guess_normal" ;;
94 esac 95 esac
95 ]) 96 ])
96 ]) 97 ])
diff --git a/gl/m4/minmax.m4 b/gl/m4/minmax.m4
index fd09846f..bc7d0c34 100644
--- a/gl/m4/minmax.m4
+++ b/gl/m4/minmax.m4
@@ -1,5 +1,6 @@
1# minmax.m4 serial 4 1# minmax.m4
2dnl Copyright (C) 2005, 2009-2023 Free Software Foundation, Inc. 2# serial 4
3dnl Copyright (C) 2005, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/mktime.m4 b/gl/m4/mktime.m4
index e9d31f35..85c52454 100644
--- a/gl/m4/mktime.m4
+++ b/gl/m4/mktime.m4
@@ -1,6 +1,6 @@
1# serial 37 1# mktime.m4
2dnl Copyright (C) 2002-2003, 2005-2007, 2009-2023 Free Software Foundation, 2# serial 39
3dnl Inc. 3dnl Copyright (C) 2002-2003, 2005-2007, 2009-2024 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.
@@ -264,9 +264,9 @@ main ()
264 [gl_cv_func_working_mktime=yes], 264 [gl_cv_func_working_mktime=yes],
265 [gl_cv_func_working_mktime=no], 265 [gl_cv_func_working_mktime=no],
266 [case "$host_os" in 266 [case "$host_os" in
267 # Guess no on native Windows. 267 # Guess no on native Windows.
268 mingw*) gl_cv_func_working_mktime="guessing no" ;; 268 mingw* | windows*) gl_cv_func_working_mktime="guessing no" ;;
269 *) gl_cv_func_working_mktime="$gl_cross_guess_normal" ;; 269 *) gl_cv_func_working_mktime="$gl_cross_guess_normal" ;;
270 esac 270 esac
271 ]) 271 ])
272 fi 272 fi
@@ -280,7 +280,6 @@ AC_DEFUN([gl_FUNC_MKTIME],
280 AC_REQUIRE([AC_CANONICAL_HOST]) 280 AC_REQUIRE([AC_CANONICAL_HOST])
281 AC_REQUIRE([gl_FUNC_MKTIME_WORKS]) 281 AC_REQUIRE([gl_FUNC_MKTIME_WORKS])
282 282
283 REPLACE_MKTIME=0
284 if test "$gl_cv_func_working_mktime" != yes; then 283 if test "$gl_cv_func_working_mktime" != yes; then
285 REPLACE_MKTIME=1 284 REPLACE_MKTIME=1
286 AC_DEFINE([NEED_MKTIME_WORKING], [1], 285 AC_DEFINE([NEED_MKTIME_WORKING], [1],
@@ -288,7 +287,7 @@ AC_DEFUN([gl_FUNC_MKTIME],
288 with the algorithmic workarounds.]) 287 with the algorithmic workarounds.])
289 fi 288 fi
290 case "$host_os" in 289 case "$host_os" in
291 mingw*) 290 mingw* | windows*)
292 REPLACE_MKTIME=1 291 REPLACE_MKTIME=1
293 AC_DEFINE([NEED_MKTIME_WINDOWS], [1], 292 AC_DEFINE([NEED_MKTIME_WINDOWS], [1],
294 [Define if the compilation of mktime.c should define 'mktime' 293 [Define if the compilation of mktime.c should define 'mktime'
diff --git a/gl/m4/mmap-anon.m4 b/gl/m4/mmap-anon.m4
index d07d26e4..61ca0120 100644
--- a/gl/m4/mmap-anon.m4
+++ b/gl/m4/mmap-anon.m4
@@ -1,5 +1,6 @@
1# mmap-anon.m4 serial 12 1# mmap-anon.m4
2dnl Copyright (C) 2005, 2007, 2009-2023 Free Software Foundation, Inc. 2# serial 12
3dnl Copyright (C) 2005, 2007, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/mode_t.m4 b/gl/m4/mode_t.m4
index 82197c02..0d5c2808 100644
--- a/gl/m4/mode_t.m4
+++ b/gl/m4/mode_t.m4
@@ -1,5 +1,6 @@
1# mode_t.m4 serial 2 1# mode_t.m4
2dnl Copyright (C) 2009-2023 Free Software Foundation, Inc. 2# serial 2
3dnl Copyright (C) 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/mountlist.m4 b/gl/m4/mountlist.m4
index a9b4edb9..ff414e66 100644
--- a/gl/m4/mountlist.m4
+++ b/gl/m4/mountlist.m4
@@ -1,5 +1,6 @@
1# serial 15 1# mountlist.m4
2dnl Copyright (C) 2002-2006, 2009-2023 Free Software Foundation, Inc. 2# serial 17
3dnl Copyright (C) 2002-2006, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -106,7 +107,18 @@ $ac_includes_default
106 [Define if there is a function named getmntent for reading the list 107 [Define if there is a function named getmntent for reading the list
107 of mounted file systems, and that function takes a single argument. 108 of mounted file systems, and that function takes a single argument.
108 (4.3BSD, SunOS, HP-UX, Irix)]) 109 (4.3BSD, SunOS, HP-UX, Irix)])
109 AC_CHECK_FUNCS([setmntent endmntent hasmntopt]) 110 gl_CHECK_FUNCS_ANDROID([setmntent],
111 [[#include <stdio.h>
112 #include <mntent.h>
113 ]])
114 gl_CHECK_FUNCS_ANDROID([endmntent],
115 [[#include <stdio.h>
116 #include <mntent.h>
117 ]])
118 gl_CHECK_FUNCS_ANDROID([hasmntopt],
119 [[#include <stdio.h>
120 #include <mntent.h>
121 ]])
110 fi 122 fi
111 fi 123 fi
112 124
diff --git a/gl/m4/msvc-inval.m4 b/gl/m4/msvc-inval.m4
index 8d9d21b5..7919ff12 100644
--- a/gl/m4/msvc-inval.m4
+++ b/gl/m4/msvc-inval.m4
@@ -1,5 +1,6 @@
1# msvc-inval.m4 serial 1 1# msvc-inval.m4
2dnl Copyright (C) 2011-2023 Free Software Foundation, Inc. 2# serial 1
3dnl Copyright (C) 2011-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/msvc-nothrow.m4 b/gl/m4/msvc-nothrow.m4
index 0263e490..007c7620 100644
--- a/gl/m4/msvc-nothrow.m4
+++ b/gl/m4/msvc-nothrow.m4
@@ -1,5 +1,6 @@
1# msvc-nothrow.m4 serial 1 1# msvc-nothrow.m4
2dnl Copyright (C) 2011-2023 Free Software Foundation, Inc. 2# serial 1
3dnl Copyright (C) 2011-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/multiarch.m4 b/gl/m4/multiarch.m4
index 3ba5b0f7..3af29d39 100644
--- a/gl/m4/multiarch.m4
+++ b/gl/m4/multiarch.m4
@@ -1,5 +1,6 @@
1# multiarch.m4 serial 9 1# multiarch.m4
2dnl Copyright (C) 2008-2023 Free Software Foundation, Inc. 2# serial 9
3dnl Copyright (C) 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/musl.m4 b/gl/m4/musl.m4
new file mode 100644
index 00000000..0d4de892
--- /dev/null
+++ b/gl/m4/musl.m4
@@ -0,0 +1,21 @@
1# musl.m4
2# serial 4
3dnl Copyright (C) 2019-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
8# Test for musl libc, despite the musl libc authors don't like it
9# <https://wiki.musl-libc.org/faq.html>
10# <https://lists.gnu.org/archive/html/bug-gnulib/2018-02/msg00079.html>.
11# From Bruno Haible.
12
13AC_DEFUN_ONCE([gl_MUSL_LIBC],
14[
15 AC_REQUIRE([AC_CANONICAL_HOST])
16 case "$host_os" in
17 *-musl* | midipix*)
18 AC_DEFINE([MUSL_LIBC], [1], [Define to 1 on musl libc.])
19 ;;
20 esac
21])
diff --git a/gl/m4/netdb_h.m4 b/gl/m4/netdb_h.m4
index e6aa8925..d8c00217 100644
--- a/gl/m4/netdb_h.m4
+++ b/gl/m4/netdb_h.m4
@@ -1,5 +1,6 @@
1# netdb_h.m4 serial 15 1# netdb_h.m4
2dnl Copyright (C) 2008-2023 Free Software Foundation, Inc. 2# serial 15
3dnl Copyright (C) 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/netinet_in_h.m4 b/gl/m4/netinet_in_h.m4
index 71154191..926f7f95 100644
--- a/gl/m4/netinet_in_h.m4
+++ b/gl/m4/netinet_in_h.m4
@@ -1,5 +1,6 @@
1# netinet_in_h.m4 serial 6 1# netinet_in_h.m4
2dnl Copyright (C) 2006-2023 Free Software Foundation, Inc. 2# serial 6
3dnl Copyright (C) 2006-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/nl_langinfo.m4 b/gl/m4/nl_langinfo.m4
index 51e783ce..f38f11bb 100644
--- a/gl/m4/nl_langinfo.m4
+++ b/gl/m4/nl_langinfo.m4
@@ -1,5 +1,6 @@
1# nl_langinfo.m4 serial 8 1# nl_langinfo.m4
2dnl Copyright (C) 2009-2023 Free Software Foundation, Inc. 2# serial 11
3dnl Copyright (C) 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -8,7 +9,7 @@ AC_DEFUN([gl_FUNC_NL_LANGINFO],
8[ 9[
9 AC_REQUIRE([gl_LANGINFO_H_DEFAULTS]) 10 AC_REQUIRE([gl_LANGINFO_H_DEFAULTS])
10 AC_REQUIRE([gl_LANGINFO_H]) 11 AC_REQUIRE([gl_LANGINFO_H])
11 AC_CHECK_FUNCS_ONCE([nl_langinfo]) 12 gl_CHECK_FUNCS_ANDROID([nl_langinfo], [[#include <langinfo.h>]])
12 AC_REQUIRE([AC_CANONICAL_HOST]) 13 AC_REQUIRE([AC_CANONICAL_HOST])
13 AC_REQUIRE([gl_FUNC_SETLOCALE_NULL]) 14 AC_REQUIRE([gl_FUNC_SETLOCALE_NULL])
14 AC_REQUIRE([gl_PTHREADLIB]) 15 AC_REQUIRE([gl_PTHREADLIB])
@@ -60,9 +61,12 @@ AC_DEFUN([gl_FUNC_NL_LANGINFO],
60 fi 61 fi
61 else 62 else
62 HAVE_NL_LANGINFO=0 63 HAVE_NL_LANGINFO=0
64 case "$gl_cv_onwards_func_nl_langinfo" in
65 future*) REPLACE_NL_LANGINFO=1 ;;
66 esac
63 fi 67 fi
64 if test $HAVE_NL_LANGINFO = 0 || test $HAVE_LANGINFO_CODESET = 0; then 68 if test $HAVE_NL_LANGINFO = 0 || test $HAVE_LANGINFO_CODESET = 0; then
65 LIB_NL_LANGINFO="$LIB_SETLOCALE_NULL" 69 LIB_NL_LANGINFO="$SETLOCALE_NULL_LIB"
66 else 70 else
67 LIB_NL_LANGINFO= 71 LIB_NL_LANGINFO=
68 fi 72 fi
diff --git a/gl/m4/nocrash.m4 b/gl/m4/nocrash.m4
index 6a766387..cbe8fe82 100644
--- a/gl/m4/nocrash.m4
+++ b/gl/m4/nocrash.m4
@@ -1,5 +1,6 @@
1# nocrash.m4 serial 5 1# nocrash.m4
2dnl Copyright (C) 2005, 2009-2023 Free Software Foundation, Inc. 2# serial 5
3dnl Copyright (C) 2005, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/off_t.m4 b/gl/m4/off_t.m4
index 880f3472..db6035db 100644
--- a/gl/m4/off_t.m4
+++ b/gl/m4/off_t.m4
@@ -1,5 +1,6 @@
1# off_t.m4 serial 1 1# off_t.m4
2dnl Copyright (C) 2012-2023 Free Software Foundation, Inc. 2# serial 1
3dnl Copyright (C) 2012-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/open-cloexec.m4 b/gl/m4/open-cloexec.m4
index fd572fcd..6defdfb4 100644
--- a/gl/m4/open-cloexec.m4
+++ b/gl/m4/open-cloexec.m4
@@ -1,10 +1,12 @@
1# Test whether O_CLOEXEC is defined. 1# open-cloexec.m4
2 2# serial 1
3dnl Copyright 2017-2023 Free Software Foundation, Inc. 3dnl Copyright 2017-2024 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 7
8# Test whether O_CLOEXEC is defined.
9
8AC_DEFUN([gl_PREPROC_O_CLOEXEC], 10AC_DEFUN([gl_PREPROC_O_CLOEXEC],
9[ 11[
10 AC_CACHE_CHECK([for O_CLOEXEC], 12 AC_CACHE_CHECK([for O_CLOEXEC],
diff --git a/gl/m4/open-slash.m4 b/gl/m4/open-slash.m4
index 1f731f8a..03460e42 100644
--- a/gl/m4/open-slash.m4
+++ b/gl/m4/open-slash.m4
@@ -1,5 +1,6 @@
1# open-slash.m4 serial 2 1# open-slash.m4
2dnl Copyright (C) 2007-2023 Free Software Foundation, Inc. 2# serial 2
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/open.m4 b/gl/m4/open.m4
index 94fa2bb7..62a11a11 100644
--- a/gl/m4/open.m4
+++ b/gl/m4/open.m4
@@ -1,5 +1,6 @@
1# open.m4 serial 15 1# open.m4
2dnl Copyright (C) 2007-2023 Free Software Foundation, Inc. 2# serial 16
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -9,7 +10,7 @@ AC_DEFUN([gl_FUNC_OPEN],
9 AC_REQUIRE([AC_CANONICAL_HOST]) 10 AC_REQUIRE([AC_CANONICAL_HOST])
10 AC_REQUIRE([gl_PREPROC_O_CLOEXEC]) 11 AC_REQUIRE([gl_PREPROC_O_CLOEXEC])
11 case "$host_os" in 12 case "$host_os" in
12 mingw* | pw*) 13 mingw* | windows* | pw*)
13 REPLACE_OPEN=1 14 REPLACE_OPEN=1
14 ;; 15 ;;
15 *) 16 *)
diff --git a/gl/m4/pathmax.m4 b/gl/m4/pathmax.m4
index 6d47d2c0..4280837f 100644
--- a/gl/m4/pathmax.m4
+++ b/gl/m4/pathmax.m4
@@ -1,5 +1,6 @@
1# pathmax.m4 serial 11 1# pathmax.m4
2dnl Copyright (C) 2002-2003, 2005-2006, 2009-2023 Free Software Foundation, 2# serial 11
3dnl Copyright (C) 2002-2003, 2005-2006, 2009-2024 Free Software Foundation,
3dnl Inc. 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,
diff --git a/gl/m4/pid_t.m4 b/gl/m4/pid_t.m4
index 0fd7d0a1..8bedcc6b 100644
--- a/gl/m4/pid_t.m4
+++ b/gl/m4/pid_t.m4
@@ -1,5 +1,6 @@
1# pid_t.m4 serial 4 1# pid_t.m4
2dnl Copyright (C) 2020-2023 Free Software Foundation, Inc. 2# serial 4
3dnl Copyright (C) 2020-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/printf.m4 b/gl/m4/printf.m4
index 4e65abc6..0cb14d6f 100644
--- a/gl/m4/printf.m4
+++ b/gl/m4/printf.m4
@@ -1,5 +1,6 @@
1# printf.m4 serial 73 1# printf.m4
2dnl Copyright (C) 2003, 2007-2023 Free Software Foundation, Inc. 2# serial 91
3dnl Copyright (C) 2003, 2007-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -63,7 +64,7 @@ changequote(,)dnl
63 # Guess yes on glibc systems. 64 # Guess yes on glibc systems.
64 *-gnu* | gnu*) gl_cv_func_printf_sizes_c99="guessing yes";; 65 *-gnu* | gnu*) gl_cv_func_printf_sizes_c99="guessing yes";;
65 # Guess yes on musl systems. 66 # Guess yes on musl systems.
66 *-musl*) gl_cv_func_printf_sizes_c99="guessing yes";; 67 *-musl* | midipix*) gl_cv_func_printf_sizes_c99="guessing yes";;
67 # Guess yes on FreeBSD >= 5. 68 # Guess yes on FreeBSD >= 5.
68 freebsd[1-4].*) gl_cv_func_printf_sizes_c99="guessing no";; 69 freebsd[1-4].*) gl_cv_func_printf_sizes_c99="guessing no";;
69 freebsd* | kfreebsd*) gl_cv_func_printf_sizes_c99="guessing yes";; 70 freebsd* | kfreebsd*) gl_cv_func_printf_sizes_c99="guessing yes";;
@@ -86,7 +87,8 @@ changequote(,)dnl
86 linux*-android*) gl_cv_func_printf_sizes_c99="guessing yes";; 87 linux*-android*) gl_cv_func_printf_sizes_c99="guessing yes";;
87changequote([,])dnl 88changequote([,])dnl
88 # Guess yes on MSVC, no on mingw. 89 # Guess yes on MSVC, no on mingw.
89 mingw*) AC_EGREP_CPP([Known], [ 90 windows*-msvc*) gl_cv_func_printf_sizes_c99="guessing yes" ;;
91 mingw* | windows*) AC_EGREP_CPP([Known], [
90#ifdef _MSC_VER 92#ifdef _MSC_VER
91 Known 93 Known
92#endif 94#endif
@@ -101,6 +103,92 @@ changequote([,])dnl
101 ]) 103 ])
102]) 104])
103 105
106dnl Test whether the *printf family of functions supports the 'w8', 'w16',
107dnl 'w32', 'w64', 'wf8', 'wf16', 'wf32', 'wf64' size specifiers. (ISO C23)
108dnl Result is gl_cv_func_printf_sizes_c23.
109
110AC_DEFUN([gl_PRINTF_SIZES_C23],
111[
112 AC_REQUIRE([AC_PROG_CC])
113 AC_REQUIRE([gl_AC_HEADER_STDINT_H])
114 AC_REQUIRE([gl_AC_HEADER_INTTYPES_H])
115 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
116 AC_CACHE_CHECK([whether printf supports size specifiers as in C23],
117 [gl_cv_func_printf_sizes_c23],
118 [
119 AC_RUN_IFELSE(
120 [AC_LANG_SOURCE([[
121#include <stddef.h>
122#include <stdio.h>
123#include <string.h>
124#include <sys/types.h>
125#if HAVE_STDINT_H_WITH_UINTMAX
126# include <stdint.h>
127#endif
128#if HAVE_INTTYPES_H_WITH_UINTMAX
129# include <inttypes.h>
130#endif
131static char buf[100];
132int main ()
133{
134 int result = 0;
135 buf[0] = '\0';
136 if (sprintf (buf, "%w8u %d", (uint8_t) 123, 33, 44, 55) < 0
137 || strcmp (buf, "123 33") != 0)
138 result |= 1;
139 buf[0] = '\0';
140 if (sprintf (buf, "%wf8u %d", (uint_fast8_t) 123, 33, 44, 55) < 0
141 || strcmp (buf, "123 33") != 0)
142 result |= 1;
143 buf[0] = '\0';
144 if (sprintf (buf, "%w16u %d", (uint16_t) 12345, 33, 44, 55) < 0
145 || strcmp (buf, "12345 33") != 0)
146 result |= 2;
147 buf[0] = '\0';
148 if (sprintf (buf, "%wf16u %d", (uint_fast16_t) 12345, 33, 44, 55) < 0
149 || strcmp (buf, "12345 33") != 0)
150 result |= 2;
151 buf[0] = '\0';
152 if (sprintf (buf, "%w32u %d", (uint32_t) 12345671, 33, 44, 55) < 0
153 || strcmp (buf, "12345671 33") != 0)
154 result |= 4;
155 buf[0] = '\0';
156 if (sprintf (buf, "%wf32u %d", (uint_fast32_t) 12345671, 33, 44, 55) < 0
157 || strcmp (buf, "12345671 33") != 0)
158 result |= 4;
159#if HAVE_STDINT_H_WITH_UINTMAX || HAVE_INTTYPES_H_WITH_UINTMAX
160 buf[0] = '\0';
161 if (sprintf (buf, "%w64u %d", (uint64_t) 12345671, 33, 44, 55) < 0
162 || strcmp (buf, "12345671 33") != 0)
163 result |= 8;
164 buf[0] = '\0';
165 if (sprintf (buf, "%wf64u %d", (uint_fast64_t) 12345671, 33, 44, 55) < 0
166 || strcmp (buf, "12345671 33") != 0)
167 result |= 8;
168#else
169 result |= 8;
170#endif
171 return result;
172}]])],
173 [gl_cv_func_printf_sizes_c23=yes],
174 [gl_cv_func_printf_sizes_c23=no],
175 [
176 case "$host_os" in
177 # Guess no on glibc systems.
178 *-gnu* | gnu*) gl_cv_func_printf_sizes_c23="guessing no";;
179 # Guess no on musl systems.
180 *-musl* | midipix*) gl_cv_func_printf_sizes_c23="guessing no";;
181 # Guess no on Android.
182 linux*-android*) gl_cv_func_printf_sizes_c23="guessing no";;
183 # Guess no on native Windows.
184 mingw* | windows*) gl_cv_func_printf_sizes_c23="guessing no";;
185 # If we don't know, obey --enable-cross-guesses.
186 *) gl_cv_func_printf_sizes_c23="$gl_cross_guess_normal";;
187 esac
188 ])
189 ])
190])
191
104dnl Test whether the *printf family of functions supports 'long double' 192dnl Test whether the *printf family of functions supports 'long double'
105dnl arguments together with the 'L' size specifier. (ISO C99, POSIX:2001) 193dnl arguments together with the 'L' size specifier. (ISO C99, POSIX:2001)
106dnl Result is gl_cv_func_printf_long_double. 194dnl Result is gl_cv_func_printf_long_double.
@@ -137,20 +225,21 @@ int main ()
137 [gl_cv_func_printf_long_double=yes], 225 [gl_cv_func_printf_long_double=yes],
138 [gl_cv_func_printf_long_double=no], 226 [gl_cv_func_printf_long_double=no],
139 [case "$host_os" in 227 [case "$host_os" in
140 # Guess no on BeOS. 228 # Guess no on BeOS.
141 beos*) gl_cv_func_printf_long_double="guessing no";; 229 beos*) gl_cv_func_printf_long_double="guessing no";;
142 # Guess yes on Android. 230 # Guess yes on Android.
143 linux*-android*) gl_cv_func_printf_long_double="guessing yes";; 231 linux*-android*) gl_cv_func_printf_long_double="guessing yes";;
144 # Guess yes on MSVC, no on mingw. 232 # Guess yes on MSVC, no on mingw.
145 mingw*) AC_EGREP_CPP([Known], [ 233 windows*-msvc*) gl_cv_func_printf_long_double="guessing yes" ;;
234 mingw* | windows*) AC_EGREP_CPP([Known], [
146#ifdef _MSC_VER 235#ifdef _MSC_VER
147 Known 236 Known
148#endif 237#endif
149 ], 238 ],
150 [gl_cv_func_printf_long_double="guessing yes"], 239 [gl_cv_func_printf_long_double="guessing yes"],
151 [gl_cv_func_printf_long_double="guessing no"]) 240 [gl_cv_func_printf_long_double="guessing no"])
152 ;; 241 ;;
153 *) gl_cv_func_printf_long_double="guessing yes";; 242 *) gl_cv_func_printf_long_double="guessing yes";;
154 esac 243 esac
155 ]) 244 ])
156 ]) 245 ])
@@ -244,7 +333,7 @@ changequote(,)dnl
244 # Guess yes on glibc systems. 333 # Guess yes on glibc systems.
245 *-gnu* | gnu*) gl_cv_func_printf_infinite="guessing yes";; 334 *-gnu* | gnu*) gl_cv_func_printf_infinite="guessing yes";;
246 # Guess yes on musl systems. 335 # Guess yes on musl systems.
247 *-musl*) gl_cv_func_printf_infinite="guessing yes";; 336 *-musl* | midipix*) gl_cv_func_printf_infinite="guessing yes";;
248 # Guess yes on FreeBSD >= 6. 337 # Guess yes on FreeBSD >= 6.
249 freebsd[1-5].*) gl_cv_func_printf_infinite="guessing no";; 338 freebsd[1-5].*) gl_cv_func_printf_infinite="guessing no";;
250 freebsd* | kfreebsd*) gl_cv_func_printf_infinite="guessing yes";; 339 freebsd* | kfreebsd*) gl_cv_func_printf_infinite="guessing yes";;
@@ -268,7 +357,8 @@ changequote(,)dnl
268 linux*-android*) gl_cv_func_printf_infinite="guessing no";; 357 linux*-android*) gl_cv_func_printf_infinite="guessing no";;
269changequote([,])dnl 358changequote([,])dnl
270 # Guess yes on MSVC, no on mingw. 359 # Guess yes on MSVC, no on mingw.
271 mingw*) AC_EGREP_CPP([Known], [ 360 windows*-msvc*) gl_cv_func_printf_infinite="guessing yes" ;;
361 mingw* | windows*) AC_EGREP_CPP([Known], [
272#ifdef _MSC_VER 362#ifdef _MSC_VER
273 Known 363 Known
274#endif 364#endif
@@ -467,7 +557,7 @@ changequote(,)dnl
467 # Guess yes on glibc systems. 557 # Guess yes on glibc systems.
468 *-gnu* | gnu*) gl_cv_func_printf_infinite_long_double="guessing yes";; 558 *-gnu* | gnu*) gl_cv_func_printf_infinite_long_double="guessing yes";;
469 # Guess yes on musl systems. 559 # Guess yes on musl systems.
470 *-musl*) gl_cv_func_printf_infinite_long_double="guessing yes";; 560 *-musl* | midipix*) gl_cv_func_printf_infinite_long_double="guessing yes";;
471 # Guess yes on FreeBSD >= 6. 561 # Guess yes on FreeBSD >= 6.
472 freebsd[1-5].*) gl_cv_func_printf_infinite_long_double="guessing no";; 562 freebsd[1-5].*) gl_cv_func_printf_infinite_long_double="guessing no";;
473 freebsd* | kfreebsd*) gl_cv_func_printf_infinite_long_double="guessing yes";; 563 freebsd* | kfreebsd*) gl_cv_func_printf_infinite_long_double="guessing yes";;
@@ -482,7 +572,8 @@ changequote(,)dnl
482 linux*-android*) gl_cv_func_printf_infinite_long_double="guessing no";; 572 linux*-android*) gl_cv_func_printf_infinite_long_double="guessing no";;
483changequote([,])dnl 573changequote([,])dnl
484 # Guess yes on MSVC, no on mingw. 574 # Guess yes on MSVC, no on mingw.
485 mingw*) AC_EGREP_CPP([Known], [ 575 windows*-msvc*) gl_cv_func_printf_infinite_long_double="guessing yes" ;;
576 mingw* | windows*) AC_EGREP_CPP([Known], [
486#ifdef _MSC_VER 577#ifdef _MSC_VER
487 Known 578 Known
488#endif 579#endif
@@ -591,11 +682,11 @@ int main ()
591 [gl_cv_func_printf_directive_a="guessing no"]) 682 [gl_cv_func_printf_directive_a="guessing no"])
592 ;; 683 ;;
593 # Guess yes on musl systems. 684 # Guess yes on musl systems.
594 *-musl*) gl_cv_func_printf_directive_a="guessing yes";; 685 *-musl* | midipix*) gl_cv_func_printf_directive_a="guessing yes";;
595 # Guess no on Android. 686 # Guess no on Android.
596 linux*-android*) gl_cv_func_printf_directive_a="guessing no";; 687 linux*-android*) gl_cv_func_printf_directive_a="guessing no";;
597 # Guess no on native Windows. 688 # Guess no on native Windows.
598 mingw*) gl_cv_func_printf_directive_a="guessing no";; 689 mingw* | windows*) gl_cv_func_printf_directive_a="guessing no";;
599 # If we don't know, obey --enable-cross-guesses. 690 # If we don't know, obey --enable-cross-guesses.
600 *) gl_cv_func_printf_directive_a="$gl_cross_guess_normal";; 691 *) gl_cv_func_printf_directive_a="$gl_cross_guess_normal";;
601 esac 692 esac
@@ -603,6 +694,116 @@ int main ()
603 ]) 694 ])
604]) 695])
605 696
697dnl Test whether the *printf family of functions supports the 'b' conversion
698dnl specifier for binary output of integers.
699dnl (ISO C23)
700dnl Result is gl_cv_func_printf_directive_b.
701
702AC_DEFUN([gl_PRINTF_DIRECTIVE_B],
703[
704 AC_REQUIRE([AC_PROG_CC])
705 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
706 AC_CACHE_CHECK([whether printf supports the 'b' directive],
707 [gl_cv_func_printf_directive_b],
708 [
709 AC_RUN_IFELSE(
710 [AC_LANG_SOURCE([[
711#include <stdio.h>
712#include <string.h>
713static char buf[100];
714int main ()
715{
716 int result = 0;
717 if (sprintf (buf, "%b %d", 12345, 33, 44, 55) < 0
718 || strcmp (buf, "11000000111001 33") != 0)
719 result |= 1;
720 return result;
721}]])],
722 [gl_cv_func_printf_directive_b=yes],
723 [gl_cv_func_printf_directive_b=no],
724 [
725 case "$host_os" in
726 # Guess yes on glibc >= 2.35 systems.
727 *-gnu* | gnu*)
728 AC_EGREP_CPP([Lucky], [
729 #include <features.h>
730 #ifdef __GNU_LIBRARY__
731 #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 35) || (__GLIBC__ > 2)
732 Lucky user
733 #endif
734 #endif
735 ],
736 [gl_cv_func_printf_directive_uppercase_b="guessing yes"],
737 [gl_cv_func_printf_directive_uppercase_b="guessing no"])
738 ;;
739 # Guess no on musl systems.
740 *-musl* | midipix*) gl_cv_func_printf_directive_b="guessing no";;
741 # Guess no on Android.
742 linux*-android*) gl_cv_func_printf_directive_b="guessing no";;
743 # Guess no on native Windows.
744 mingw* | windows*) gl_cv_func_printf_directive_b="guessing no";;
745 # If we don't know, obey --enable-cross-guesses.
746 *) gl_cv_func_printf_directive_b="$gl_cross_guess_normal";;
747 esac
748 ])
749 ])
750])
751
752dnl Test whether the *printf family of functions supports the 'B' conversion
753dnl specifier for binary output of integers.
754dnl (GNU, encouraged by ISO C23 § 7.23.6.1)
755dnl Result is gl_cv_func_printf_directive_uppercase_b.
756
757AC_DEFUN([gl_PRINTF_DIRECTIVE_UPPERCASE_B],
758[
759 AC_REQUIRE([AC_PROG_CC])
760 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
761 AC_CACHE_CHECK([whether printf supports the 'B' directive],
762 [gl_cv_func_printf_directive_uppercase_b],
763 [
764 AC_RUN_IFELSE(
765 [AC_LANG_SOURCE([[
766#include <stdio.h>
767#include <string.h>
768static char buf[100];
769int main ()
770{
771 int result = 0;
772 if (sprintf (buf, "%#B %d", 12345, 33, 44, 55) < 0
773 || strcmp (buf, "0B11000000111001 33") != 0)
774 result |= 1;
775 return result;
776}]])],
777 [gl_cv_func_printf_directive_uppercase_b=yes],
778 [gl_cv_func_printf_directive_uppercase_b=no],
779 [
780 case "$host_os" in
781 # Guess yes on glibc >= 2.35 systems.
782 *-gnu* | gnu*)
783 AC_EGREP_CPP([Lucky], [
784 #include <features.h>
785 #ifdef __GNU_LIBRARY__
786 #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 35) || (__GLIBC__ > 2)
787 Lucky user
788 #endif
789 #endif
790 ],
791 [gl_cv_func_printf_directive_uppercase_b="guessing yes"],
792 [gl_cv_func_printf_directive_uppercase_b="guessing no"])
793 ;;
794 # Guess no on musl systems.
795 *-musl* | midipix*) gl_cv_func_printf_directive_uppercase_b="guessing no";;
796 # Guess no on Android.
797 linux*-android*) gl_cv_func_printf_directive_uppercase_b="guessing no";;
798 # Guess no on native Windows.
799 mingw* | windows*) gl_cv_func_printf_directive_uppercase_b="guessing no";;
800 # If we don't know, obey --enable-cross-guesses.
801 *) gl_cv_func_printf_directive_uppercase_b="$gl_cross_guess_normal";;
802 esac
803 ])
804 ])
805])
806
606dnl Test whether the *printf family of functions supports the %F format 807dnl Test whether the *printf family of functions supports the %F format
607dnl directive. (ISO C99, POSIX:2001) 808dnl directive. (ISO C99, POSIX:2001)
608dnl Result is gl_cv_func_printf_directive_f. 809dnl Result is gl_cv_func_printf_directive_f.
@@ -643,7 +844,7 @@ changequote(,)dnl
643 # Guess yes on glibc systems. 844 # Guess yes on glibc systems.
644 *-gnu* | gnu*) gl_cv_func_printf_directive_f="guessing yes";; 845 *-gnu* | gnu*) gl_cv_func_printf_directive_f="guessing yes";;
645 # Guess yes on musl systems. 846 # Guess yes on musl systems.
646 *-musl*) gl_cv_func_printf_directive_f="guessing yes";; 847 *-musl* | midipix*) gl_cv_func_printf_directive_f="guessing yes";;
647 # Guess yes on FreeBSD >= 6. 848 # Guess yes on FreeBSD >= 6.
648 freebsd[1-5].*) gl_cv_func_printf_directive_f="guessing no";; 849 freebsd[1-5].*) gl_cv_func_printf_directive_f="guessing no";;
649 freebsd* | kfreebsd*) gl_cv_func_printf_directive_f="guessing yes";; 850 freebsd* | kfreebsd*) gl_cv_func_printf_directive_f="guessing yes";;
@@ -661,7 +862,8 @@ changequote(,)dnl
661 linux*-android*) gl_cv_func_printf_directive_f="guessing no";; 862 linux*-android*) gl_cv_func_printf_directive_f="guessing no";;
662changequote([,])dnl 863changequote([,])dnl
663 # Guess yes on MSVC, no on mingw. 864 # Guess yes on MSVC, no on mingw.
664 mingw*) AC_EGREP_CPP([Known], [ 865 windows*-msvc*) gl_cv_func_printf_directive_f="guessing yes" ;;
866 mingw* | windows*) AC_EGREP_CPP([Known], [
665#ifdef _MSC_VER 867#ifdef _MSC_VER
666 Known 868 Known
667#endif 869#endif
@@ -689,6 +891,7 @@ AC_DEFUN([gl_PRINTF_DIRECTIVE_N],
689 [ 891 [
690 AC_RUN_IFELSE( 892 AC_RUN_IFELSE(
691 [AC_LANG_SOURCE([[ 893 [AC_LANG_SOURCE([[
894#include <signal.h>
692#include <stdio.h> 895#include <stdio.h>
693#include <stdlib.h> 896#include <stdlib.h>
694#include <string.h> 897#include <string.h>
@@ -706,6 +909,12 @@ invalid_parameter_handler (const wchar_t *expression,
706 exit (1); 909 exit (1);
707} 910}
708#endif 911#endif
912static void
913abort_handler (int sig)
914{
915 (void) sig;
916 _exit (1);
917}
709static char fmtstring[10]; 918static char fmtstring[10];
710static char buf[100]; 919static char buf[100];
711int main () 920int main ()
@@ -714,6 +923,7 @@ int main ()
714#ifdef _MSC_VER 923#ifdef _MSC_VER
715 _set_invalid_parameter_handler (invalid_parameter_handler); 924 _set_invalid_parameter_handler (invalid_parameter_handler);
716#endif 925#endif
926 signal (SIGABRT, abort_handler);
717 /* Copy the format string. Some systems (glibc with _FORTIFY_SOURCE=2) 927 /* Copy the format string. Some systems (glibc with _FORTIFY_SOURCE=2)
718 support %n in format strings in read-only memory but not in writable 928 support %n in format strings in read-only memory but not in writable
719 memory. */ 929 memory. */
@@ -727,21 +937,21 @@ int main ()
727 [gl_cv_func_printf_directive_n=yes], 937 [gl_cv_func_printf_directive_n=yes],
728 [gl_cv_func_printf_directive_n=no], 938 [gl_cv_func_printf_directive_n=no],
729 [case "$host_os" in 939 [case "$host_os" in
730 # Guess no on glibc when _FORTIFY_SOURCE >= 2. 940 # Guess no on glibc when _FORTIFY_SOURCE >= 2.
731 *-gnu* | gnu*) AC_COMPILE_IFELSE( 941 *-gnu* | gnu*) AC_COMPILE_IFELSE(
732 [AC_LANG_SOURCE( 942 [AC_LANG_SOURCE(
733 [[#if _FORTIFY_SOURCE >= 2 943 [[#if _FORTIFY_SOURCE >= 2
734 error fail 944 error fail
735 #endif 945 #endif
736 ]])], 946 ]])],
737 [gl_cv_func_printf_directive_n="guessing yes"], 947 [gl_cv_func_printf_directive_n="guessing yes"],
738 [gl_cv_func_printf_directive_n="guessing no"]) 948 [gl_cv_func_printf_directive_n="guessing no"])
739 ;; 949 ;;
740 # Guess no on Android. 950 # Guess no on Android.
741 linux*-android*) gl_cv_func_printf_directive_n="guessing no";; 951 linux*-android*) gl_cv_func_printf_directive_n="guessing no";;
742 # Guess no on native Windows. 952 # Guess no on native Windows.
743 mingw*) gl_cv_func_printf_directive_n="guessing no";; 953 mingw* | windows*) gl_cv_func_printf_directive_n="guessing no";;
744 *) gl_cv_func_printf_directive_n="guessing yes";; 954 *) gl_cv_func_printf_directive_n="guessing yes";;
745 esac 955 esac
746 ]) 956 ])
747 ]) 957 ])
@@ -811,18 +1021,64 @@ int main ()
811 [ 1021 [
812changequote(,)dnl 1022changequote(,)dnl
813 case "$host_os" in 1023 case "$host_os" in
814 # Guess yes on OpenBSD >= 6.0. 1024 # Guess yes on OpenBSD >= 6.0.
815 openbsd[1-5].*) gl_cv_func_printf_directive_ls="guessing no";; 1025 openbsd[1-5].*) gl_cv_func_printf_directive_ls="guessing no";;
816 openbsd*) gl_cv_func_printf_directive_ls="guessing yes";; 1026 openbsd*) gl_cv_func_printf_directive_ls="guessing yes";;
817 irix*) gl_cv_func_printf_directive_ls="guessing no";; 1027 irix*) gl_cv_func_printf_directive_ls="guessing no";;
818 solaris*) gl_cv_func_printf_directive_ls="guessing no";; 1028 solaris*) gl_cv_func_printf_directive_ls="guessing no";;
819 cygwin*) gl_cv_func_printf_directive_ls="guessing no";; 1029 cygwin*) gl_cv_func_printf_directive_ls="guessing no";;
820 beos* | haiku*) gl_cv_func_printf_directive_ls="guessing no";; 1030 beos* | haiku*) gl_cv_func_printf_directive_ls="guessing no";;
821 # Guess no on Android. 1031 # Guess no on Android.
822 linux*-android*) gl_cv_func_printf_directive_ls="guessing no";; 1032 linux*-android*) gl_cv_func_printf_directive_ls="guessing no";;
823 # Guess yes on native Windows. 1033 # Guess yes on native Windows.
824 mingw*) gl_cv_func_printf_directive_ls="guessing yes";; 1034 mingw* | windows*) gl_cv_func_printf_directive_ls="guessing yes";;
825 *) gl_cv_func_printf_directive_ls="guessing yes";; 1035 *) gl_cv_func_printf_directive_ls="guessing yes";;
1036 esac
1037changequote([,])dnl
1038 ])
1039 ])
1040])
1041
1042dnl Test whether the *printf family of functions supports the %lc format
1043dnl directive and in particular, when the argument is a null wide character,
1044dnl whether the functions produce a NUL byte, as specified in ISO C 23
1045dnl after the issue GB-141 was fixed.
1046dnl Result is gl_cv_func_printf_directive_lc.
1047
1048AC_DEFUN([gl_PRINTF_DIRECTIVE_LC],
1049[
1050 AC_REQUIRE([AC_PROG_CC])
1051 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
1052 AC_CACHE_CHECK([whether printf supports the 'lc' directive correctly],
1053 [gl_cv_func_printf_directive_lc],
1054 [
1055 AC_RUN_IFELSE(
1056 [AC_LANG_SOURCE([[
1057#include <stdio.h>
1058#include <wchar.h>
1059#include <string.h>
1060int main ()
1061{
1062 int result = 0;
1063 char buf[100];
1064 /* This test fails on musl libc 1.2.4. */
1065 {
1066 buf[0] = '\0';
1067 if (sprintf (buf, "%lc%lc%lc", (wint_t) 'a', (wint_t) 0, (wint_t) 'z') < 0
1068 || memcmp (buf, "a\0z", 4) != 0)
1069 result |= 1;
1070 }
1071 return result;
1072}]])],
1073 [gl_cv_func_printf_directive_lc=yes],
1074 [gl_cv_func_printf_directive_lc=no],
1075 [
1076changequote(,)dnl
1077 case "$host_os" in
1078 # Guess no on musl libc.
1079 *-musl* | midipix*) gl_cv_func_printf_directive_lc="guessing no";;
1080 # Guess yes otherwise.
1081 *) gl_cv_func_printf_directive_lc="guessing yes";;
826 esac 1082 esac
827changequote([,])dnl 1083changequote([,])dnl
828 ]) 1084 ])
@@ -833,7 +1089,7 @@ dnl Test whether the *printf family of functions supports POSIX/XSI format
833dnl strings with positions. (POSIX:2001) 1089dnl strings with positions. (POSIX:2001)
834dnl Result is gl_cv_func_printf_positions. 1090dnl Result is gl_cv_func_printf_positions.
835 1091
836AC_DEFUN([gl_PRINTF_POSITIONS], 1092AC_DEFUN_ONCE([gl_PRINTF_POSITIONS],
837[ 1093[
838 AC_REQUIRE([AC_PROG_CC]) 1094 AC_REQUIRE([AC_PROG_CC])
839 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles 1095 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
@@ -859,13 +1115,17 @@ int main ()
859changequote(,)dnl 1115changequote(,)dnl
860 case "$host_os" in 1116 case "$host_os" in
861 netbsd[1-3]* | netbsdelf[1-3]* | netbsdaout[1-3]* | netbsdcoff[1-3]*) 1117 netbsd[1-3]* | netbsdelf[1-3]* | netbsdaout[1-3]* | netbsdcoff[1-3]*)
862 gl_cv_func_printf_positions="guessing no";; 1118 gl_cv_func_printf_positions="guessing no";;
863 beos*) gl_cv_func_printf_positions="guessing no";; 1119 beos*)
864 # Guess yes on Android. 1120 gl_cv_func_printf_positions="guessing no";;
865 linux*-android*) gl_cv_func_printf_positions="guessing yes";; 1121 # Guess yes on Android.
866 # Guess no on native Windows. 1122 linux*-android*)
867 mingw* | pw*) gl_cv_func_printf_positions="guessing no";; 1123 gl_cv_func_printf_positions="guessing yes";;
868 *) gl_cv_func_printf_positions="guessing yes";; 1124 # Guess no on native Windows.
1125 mingw* | windows* | pw*)
1126 gl_cv_func_printf_positions="guessing no";;
1127 *)
1128 gl_cv_func_printf_positions="guessing yes";;
869 esac 1129 esac
870changequote([,])dnl 1130changequote([,])dnl
871 ]) 1131 ])
@@ -900,13 +1160,13 @@ int main ()
900 [ 1160 [
901changequote(,)dnl 1161changequote(,)dnl
902 case "$host_os" in 1162 case "$host_os" in
903 cygwin*) gl_cv_func_printf_flag_grouping="guessing no";; 1163 cygwin*) gl_cv_func_printf_flag_grouping="guessing no";;
904 netbsd*) gl_cv_func_printf_flag_grouping="guessing no";; 1164 netbsd*) gl_cv_func_printf_flag_grouping="guessing no";;
905 # Guess no on Android. 1165 # Guess no on Android.
906 linux*-android*) gl_cv_func_printf_flag_grouping="guessing no";; 1166 linux*-android*) gl_cv_func_printf_flag_grouping="guessing no";;
907 # Guess no on native Windows. 1167 # Guess no on native Windows.
908 mingw* | pw*) gl_cv_func_printf_flag_grouping="guessing no";; 1168 mingw* | windows* | pw*) gl_cv_func_printf_flag_grouping="guessing no";;
909 *) gl_cv_func_printf_flag_grouping="guessing yes";; 1169 *) gl_cv_func_printf_flag_grouping="guessing yes";;
910 esac 1170 esac
911changequote([,])dnl 1171changequote([,])dnl
912 ]) 1172 ])
@@ -943,16 +1203,16 @@ int main ()
943 [ 1203 [
944changequote(,)dnl 1204changequote(,)dnl
945 case "$host_os" in 1205 case "$host_os" in
946 # Guess yes on HP-UX 11. 1206 # Guess yes on HP-UX 11.
947 hpux11*) gl_cv_func_printf_flag_leftadjust="guessing yes";; 1207 hpux11*) gl_cv_func_printf_flag_leftadjust="guessing yes";;
948 # Guess no on HP-UX 10 and older. 1208 # Guess no on HP-UX 10 and older.
949 hpux*) gl_cv_func_printf_flag_leftadjust="guessing no";; 1209 hpux*) gl_cv_func_printf_flag_leftadjust="guessing no";;
950 # Guess yes on Android. 1210 # Guess yes on Android.
951 linux*-android*) gl_cv_func_printf_flag_leftadjust="guessing yes";; 1211 linux*-android*) gl_cv_func_printf_flag_leftadjust="guessing yes";;
952 # Guess yes on native Windows. 1212 # Guess yes on native Windows.
953 mingw*) gl_cv_func_printf_flag_leftadjust="guessing yes";; 1213 mingw* | windows*) gl_cv_func_printf_flag_leftadjust="guessing yes";;
954 # Guess yes otherwise. 1214 # Guess yes otherwise.
955 *) gl_cv_func_printf_flag_leftadjust="guessing yes";; 1215 *) gl_cv_func_printf_flag_leftadjust="guessing yes";;
956 esac 1216 esac
957changequote([,])dnl 1217changequote([,])dnl
958 ]) 1218 ])
@@ -990,18 +1250,62 @@ int main ()
990 [ 1250 [
991changequote(,)dnl 1251changequote(,)dnl
992 case "$host_os" in 1252 case "$host_os" in
993 # Guess yes on glibc systems. 1253 # Guess yes on glibc systems.
994 *-gnu* | gnu*) gl_cv_func_printf_flag_zero="guessing yes";; 1254 *-gnu* | gnu*) gl_cv_func_printf_flag_zero="guessing yes";;
995 # Guess yes on musl systems. 1255 # Guess yes on musl systems.
996 *-musl*) gl_cv_func_printf_flag_zero="guessing yes";; 1256 *-musl* | midipix*) gl_cv_func_printf_flag_zero="guessing yes";;
997 # Guess yes on BeOS. 1257 # Guess yes on BeOS.
998 beos*) gl_cv_func_printf_flag_zero="guessing yes";; 1258 beos*) gl_cv_func_printf_flag_zero="guessing yes";;
999 # Guess no on Android. 1259 # Guess no on Android.
1000 linux*-android*) gl_cv_func_printf_flag_zero="guessing no";; 1260 linux*-android*) gl_cv_func_printf_flag_zero="guessing no";;
1001 # Guess no on native Windows. 1261 # Guess no on native Windows.
1002 mingw*) gl_cv_func_printf_flag_zero="guessing no";; 1262 mingw* | windows*) gl_cv_func_printf_flag_zero="guessing no";;
1003 # If we don't know, obey --enable-cross-guesses. 1263 # If we don't know, obey --enable-cross-guesses.
1004 *) gl_cv_func_printf_flag_zero="$gl_cross_guess_normal";; 1264 *) gl_cv_func_printf_flag_zero="$gl_cross_guess_normal";;
1265 esac
1266changequote([,])dnl
1267 ])
1268 ])
1269])
1270
1271dnl Test whether the *printf family of functions supports the # flag with a
1272dnl zero precision and a zero value in the 'x' and 'X' directives correctly.
1273dnl ISO C and POSIX specify that for the 'd', 'i', 'b', 'o', 'u', 'x', 'X'
1274dnl directives: "The result of converting a zero value with a precision of
1275dnl zero is no characters." But on Mac OS X 10.5, for the 'x', 'X' directives,
1276dnl when a # flag is present, the output is "0" instead of "".
1277dnl Result is gl_cv_func_printf_flag_alt_precision_zero.
1278
1279AC_DEFUN([gl_PRINTF_FLAG_ALT_PRECISION_ZERO],
1280[
1281 AC_REQUIRE([AC_PROG_CC])
1282 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
1283 AC_CACHE_CHECK([whether printf supports the alternative flag with a zero precision],
1284 [gl_cv_func_printf_flag_alt_precision_zero],
1285 [
1286 AC_RUN_IFELSE(
1287 [AC_LANG_SOURCE([[
1288#include <stdio.h>
1289static char buf[10];
1290int main ()
1291{
1292 int result = 0;
1293 if (sprintf (buf, "%#.0x %d", 0, 33, 44) > 0 + 3)
1294 result |= 1;
1295 return result;
1296}]])],
1297 [gl_cv_func_printf_flag_alt_precision_zero=yes],
1298 [gl_cv_func_printf_flag_alt_precision_zero=no],
1299 [
1300changequote(,)dnl
1301 case "$host_os" in
1302 # Guess no only on macOS 10..12 systems.
1303 darwin[0-9] | darwin[0-9].* | \
1304 darwin1[0-9] | darwin1[0-9].* | \
1305 darwin2[0-1] | darwin2[0-1].*)
1306 gl_cv_func_printf_flag_alt_precision_zero="guessing no" ;;
1307 darwin*) gl_cv_func_printf_flag_alt_precision_zero="guessing yes" ;;
1308 *) gl_cv_func_printf_flag_alt_precision_zero="guessing yes" ;;
1005 esac 1309 esac
1006changequote([,])dnl 1310changequote([,])dnl
1007 ]) 1311 ])
@@ -1054,12 +1358,12 @@ int main ()
1054changequote(,)dnl 1358changequote(,)dnl
1055 case "$host_os" in 1359 case "$host_os" in
1056 # Guess no only on Solaris, native Windows, and BeOS systems. 1360 # Guess no only on Solaris, native Windows, and BeOS systems.
1057 solaris*) gl_cv_func_printf_precision="guessing no" ;; 1361 solaris*) gl_cv_func_printf_precision="guessing no" ;;
1058 mingw* | pw*) gl_cv_func_printf_precision="guessing no" ;; 1362 mingw* | windows* | pw*) gl_cv_func_printf_precision="guessing no" ;;
1059 beos*) gl_cv_func_printf_precision="guessing no" ;; 1363 beos*) gl_cv_func_printf_precision="guessing no" ;;
1060 # Guess yes on Android. 1364 # Guess yes on Android.
1061 linux*-android*) gl_cv_func_printf_precision="guessing yes" ;; 1365 linux*-android*) gl_cv_func_printf_precision="guessing yes" ;;
1062 *) gl_cv_func_printf_precision="guessing yes" ;; 1366 *) gl_cv_func_printf_precision="guessing yes" ;;
1063 esac 1367 esac
1064changequote([,])dnl 1368changequote([,])dnl
1065 ]) 1369 ])
@@ -1239,7 +1543,7 @@ changequote(,)dnl
1239 # Guess yes on glibc systems. 1543 # Guess yes on glibc systems.
1240 *-gnu* | gnu*) gl_cv_func_snprintf_truncation_c99="guessing yes";; 1544 *-gnu* | gnu*) gl_cv_func_snprintf_truncation_c99="guessing yes";;
1241 # Guess yes on musl systems. 1545 # Guess yes on musl systems.
1242 *-musl*) gl_cv_func_snprintf_truncation_c99="guessing yes";; 1546 *-musl* | midipix*) gl_cv_func_snprintf_truncation_c99="guessing yes";;
1243 # Guess yes on FreeBSD >= 5. 1547 # Guess yes on FreeBSD >= 5.
1244 freebsd[1-4].*) gl_cv_func_snprintf_truncation_c99="guessing no";; 1548 freebsd[1-4].*) gl_cv_func_snprintf_truncation_c99="guessing no";;
1245 freebsd* | kfreebsd*) gl_cv_func_snprintf_truncation_c99="guessing yes";; 1549 freebsd* | kfreebsd*) gl_cv_func_snprintf_truncation_c99="guessing yes";;
@@ -1275,7 +1579,7 @@ changequote(,)dnl
1275 # Guess yes on Android. 1579 # Guess yes on Android.
1276 linux*-android*) gl_cv_func_snprintf_truncation_c99="guessing yes";; 1580 linux*-android*) gl_cv_func_snprintf_truncation_c99="guessing yes";;
1277 # Guess no on native Windows. 1581 # Guess no on native Windows.
1278 mingw*) gl_cv_func_snprintf_truncation_c99="guessing no";; 1582 mingw* | windows*) gl_cv_func_snprintf_truncation_c99="guessing no";;
1279 # If we don't know, obey --enable-cross-guesses. 1583 # If we don't know, obey --enable-cross-guesses.
1280 *) gl_cv_func_snprintf_truncation_c99="$gl_cross_guess_normal";; 1584 *) gl_cv_func_snprintf_truncation_c99="$gl_cross_guess_normal";;
1281 esac 1585 esac
@@ -1344,7 +1648,7 @@ changequote(,)dnl
1344 # Guess yes on glibc systems. 1648 # Guess yes on glibc systems.
1345 *-gnu* | gnu*) gl_cv_func_snprintf_retval_c99="guessing yes";; 1649 *-gnu* | gnu*) gl_cv_func_snprintf_retval_c99="guessing yes";;
1346 # Guess yes on musl systems. 1650 # Guess yes on musl systems.
1347 *-musl*) gl_cv_func_snprintf_retval_c99="guessing yes";; 1651 *-musl* | midipix*) gl_cv_func_snprintf_retval_c99="guessing yes";;
1348 # Guess yes on FreeBSD >= 5. 1652 # Guess yes on FreeBSD >= 5.
1349 freebsd[1-4].*) gl_cv_func_snprintf_retval_c99="guessing no";; 1653 freebsd[1-4].*) gl_cv_func_snprintf_retval_c99="guessing no";;
1350 freebsd* | kfreebsd*) gl_cv_func_snprintf_retval_c99="guessing yes";; 1654 freebsd* | kfreebsd*) gl_cv_func_snprintf_retval_c99="guessing yes";;
@@ -1372,7 +1676,8 @@ changequote(,)dnl
1372 linux*-android*) gl_cv_func_snprintf_retval_c99="guessing yes";; 1676 linux*-android*) gl_cv_func_snprintf_retval_c99="guessing yes";;
1373changequote([,])dnl 1677changequote([,])dnl
1374 # Guess yes on MSVC, no on mingw. 1678 # Guess yes on MSVC, no on mingw.
1375 mingw*) AC_EGREP_CPP([Known], [ 1679 windows*-msvc*) gl_cv_func_snprintf_retval_c99="guessing yes" ;;
1680 mingw* | windows*) AC_EGREP_CPP([Known], [
1376#ifdef _MSC_VER 1681#ifdef _MSC_VER
1377 Known 1682 Known
1378#endif 1683#endif
@@ -1401,6 +1706,7 @@ AC_DEFUN([gl_SNPRINTF_DIRECTIVE_N],
1401 [ 1706 [
1402 AC_RUN_IFELSE( 1707 AC_RUN_IFELSE(
1403 [AC_LANG_SOURCE([[ 1708 [AC_LANG_SOURCE([[
1709#include <signal.h>
1404#include <stdio.h> 1710#include <stdio.h>
1405#include <string.h> 1711#include <string.h>
1406#if HAVE_SNPRINTF 1712#if HAVE_SNPRINTF
@@ -1417,11 +1723,18 @@ static int my_snprintf (char *buf, int size, const char *format, ...)
1417 return ret; 1723 return ret;
1418} 1724}
1419#endif 1725#endif
1726static void
1727abort_handler (int sig)
1728{
1729 (void) sig;
1730 _exit (1);
1731}
1420static char fmtstring[10]; 1732static char fmtstring[10];
1421static char buf[100]; 1733static char buf[100];
1422int main () 1734int main ()
1423{ 1735{
1424 int count = -1; 1736 int count = -1;
1737 signal (SIGABRT, abort_handler);
1425 /* Copy the format string. Some systems (glibc with _FORTIFY_SOURCE=2) 1738 /* Copy the format string. Some systems (glibc with _FORTIFY_SOURCE=2)
1426 support %n in format strings in read-only memory but not in writable 1739 support %n in format strings in read-only memory but not in writable
1427 memory. */ 1740 memory. */
@@ -1447,7 +1760,7 @@ int main ()
1447 ;; 1760 ;;
1448changequote(,)dnl 1761changequote(,)dnl
1449 # Guess yes on musl systems. 1762 # Guess yes on musl systems.
1450 *-musl*) gl_cv_func_snprintf_directive_n="guessing yes";; 1763 *-musl* | midipix*) gl_cv_func_snprintf_directive_n="guessing yes";;
1451 # Guess yes on FreeBSD >= 5. 1764 # Guess yes on FreeBSD >= 5.
1452 freebsd[1-4].*) gl_cv_func_snprintf_directive_n="guessing no";; 1765 freebsd[1-4].*) gl_cv_func_snprintf_directive_n="guessing no";;
1453 freebsd* | kfreebsd*) gl_cv_func_snprintf_directive_n="guessing yes";; 1766 freebsd* | kfreebsd*) gl_cv_func_snprintf_directive_n="guessing yes";;
@@ -1476,7 +1789,7 @@ changequote(,)dnl
1476 # Guess no on Android. 1789 # Guess no on Android.
1477 linux*-android*) gl_cv_func_snprintf_directive_n="guessing no";; 1790 linux*-android*) gl_cv_func_snprintf_directive_n="guessing no";;
1478 # Guess no on native Windows. 1791 # Guess no on native Windows.
1479 mingw*) gl_cv_func_snprintf_directive_n="guessing no";; 1792 mingw* | windows*) gl_cv_func_snprintf_directive_n="guessing no";;
1480 # If we don't know, obey --enable-cross-guesses. 1793 # If we don't know, obey --enable-cross-guesses.
1481 *) gl_cv_func_snprintf_directive_n="$gl_cross_guess_normal";; 1794 *) gl_cv_func_snprintf_directive_n="$gl_cross_guess_normal";;
1482changequote([,])dnl 1795changequote([,])dnl
@@ -1524,11 +1837,11 @@ int main()
1524 [gl_cv_func_snprintf_size1=yes], 1837 [gl_cv_func_snprintf_size1=yes],
1525 [gl_cv_func_snprintf_size1=no], 1838 [gl_cv_func_snprintf_size1=no],
1526 [case "$host_os" in 1839 [case "$host_os" in
1527 # Guess yes on Android. 1840 # Guess yes on Android.
1528 linux*-android*) gl_cv_func_snprintf_size1="guessing yes" ;; 1841 linux*-android*) gl_cv_func_snprintf_size1="guessing yes" ;;
1529 # Guess yes on native Windows. 1842 # Guess yes on native Windows.
1530 mingw*) gl_cv_func_snprintf_size1="guessing yes" ;; 1843 mingw* | windows*) gl_cv_func_snprintf_size1="guessing yes" ;;
1531 *) gl_cv_func_snprintf_size1="guessing yes" ;; 1844 *) gl_cv_func_snprintf_size1="guessing yes" ;;
1532 esac 1845 esac
1533 ]) 1846 ])
1534 ]) 1847 ])
@@ -1601,128 +1914,320 @@ int main()
1601 [ 1914 [
1602changequote(,)dnl 1915changequote(,)dnl
1603 case "$host_os" in 1916 case "$host_os" in
1604 # Guess yes on glibc systems. 1917 # Guess yes on glibc systems.
1605 *-gnu* | gnu*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";; 1918 *-gnu* | gnu*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";;
1606 # Guess yes on musl systems. 1919 # Guess yes on musl systems.
1607 *-musl*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";; 1920 *-musl* | midipix*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";;
1608 # Guess yes on FreeBSD >= 5. 1921 # Guess yes on FreeBSD >= 5.
1609 freebsd[1-4].*) gl_cv_func_vsnprintf_zerosize_c99="guessing no";; 1922 freebsd[1-4].*) gl_cv_func_vsnprintf_zerosize_c99="guessing no";;
1610 freebsd* | kfreebsd*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";; 1923 freebsd* | kfreebsd*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";;
1611 midnightbsd*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";; 1924 midnightbsd*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";;
1612 # Guess yes on Mac OS X >= 10.3. 1925 # Guess yes on Mac OS X >= 10.3.
1613 darwin[1-6].*) gl_cv_func_vsnprintf_zerosize_c99="guessing no";; 1926 darwin[1-6].*) gl_cv_func_vsnprintf_zerosize_c99="guessing no";;
1614 darwin*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";; 1927 darwin*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";;
1615 # Guess yes on Cygwin. 1928 # Guess yes on Cygwin.
1616 cygwin*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";; 1929 cygwin*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";;
1617 # Guess yes on Solaris >= 2.6. 1930 # Guess yes on Solaris >= 2.6.
1618 solaris2.[0-5] | solaris2.[0-5].*) 1931 solaris2.[0-5] | solaris2.[0-5].*)
1619 gl_cv_func_vsnprintf_zerosize_c99="guessing no";; 1932 gl_cv_func_vsnprintf_zerosize_c99="guessing no";;
1620 solaris*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";; 1933 solaris*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";;
1621 # Guess yes on AIX >= 4. 1934 # Guess yes on AIX >= 4.
1622 aix[1-3]*) gl_cv_func_vsnprintf_zerosize_c99="guessing no";; 1935 aix[1-3]*) gl_cv_func_vsnprintf_zerosize_c99="guessing no";;
1623 aix*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";; 1936 aix*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";;
1624 # Guess yes on IRIX >= 6.5. 1937 # Guess yes on IRIX >= 6.5.
1625 irix6.5) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";; 1938 irix6.5) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";;
1626 # Guess yes on NetBSD >= 3. 1939 # Guess yes on NetBSD >= 3.
1627 netbsd[1-2]* | netbsdelf[1-2]* | netbsdaout[1-2]* | netbsdcoff[1-2]*) 1940 netbsd[1-2]* | netbsdelf[1-2]* | netbsdaout[1-2]* | netbsdcoff[1-2]*)
1628 gl_cv_func_vsnprintf_zerosize_c99="guessing no";; 1941 gl_cv_func_vsnprintf_zerosize_c99="guessing no";;
1629 netbsd*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";; 1942 netbsd*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";;
1630 # Guess yes on BeOS. 1943 # Guess yes on BeOS.
1631 beos*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";; 1944 beos*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";;
1632 # Guess yes on Android. 1945 # Guess yes on Android.
1633 linux*-android*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";; 1946 linux*-android*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";;
1634 # Guess yes on native Windows. 1947 # Guess yes on native Windows.
1635 mingw* | pw*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";; 1948 mingw* | windows* | pw*) gl_cv_func_vsnprintf_zerosize_c99="guessing yes";;
1636 # If we don't know, obey --enable-cross-guesses. 1949 # If we don't know, obey --enable-cross-guesses.
1637 *) gl_cv_func_vsnprintf_zerosize_c99="$gl_cross_guess_normal";; 1950 *) gl_cv_func_vsnprintf_zerosize_c99="$gl_cross_guess_normal";;
1638 esac 1951 esac
1639changequote([,])dnl 1952changequote([,])dnl
1640 ]) 1953 ])
1641 ]) 1954 ])
1642]) 1955])
1643 1956
1957dnl Test whether the swprintf function works correctly when it produces output
1958dnl that contains null wide characters.
1959dnl Result is gl_cv_func_swprintf_works.
1960
1961AC_DEFUN([gl_SWPRINTF_WORKS],
1962[
1963 AC_REQUIRE([AC_PROG_CC])
1964 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
1965 AC_CHECK_FUNCS_ONCE([swprintf])
1966 AC_CACHE_CHECK([whether swprintf works],
1967 [gl_cv_func_swprintf_works],
1968 [
1969 AC_RUN_IFELSE(
1970 [AC_LANG_SOURCE([[
1971#ifndef __USE_MINGW_ANSI_STDIO
1972# define __USE_MINGW_ANSI_STDIO 1
1973#endif
1974#include <stdio.h>
1975#include <wchar.h>
1976int main()
1977{
1978 int result = 0;
1979 { /* This test fails on musl libc 1.2.3, FreeBSD, NetBSD, OpenBSD, macOS, AIX. */
1980 wchar_t buf[5] = { 0xBEEF, 0xBEEF, 0xBEEF, 0xBEEF, 0xBEEF };
1981 int ret = swprintf (buf, 4, L"%cz", '\0');
1982 /* Expected result:
1983 ret = 2, buf[0] = 0x0, buf[1] = 0x7a, buf[2] = 0x0, buf[3] = 0xbeef
1984 musl libc 1.2.3:
1985 ret = 2, buf[0] = 0x0, buf[1] = 0x0, buf[2] = 0x0, buf[3] = 0x0
1986 Reported at <https://www.openwall.com/lists/musl/2023/03/22/9>.
1987 FreeBSD 13.1, NetBSD 9.0, OpenBSD 7.2, macOS 12.5, AIX 7.2:
1988 ret = 2, buf[0] = 0x0, buf[1] = 0xbeef, buf[2] = 0xbeef, buf[3] = 0xbeef
1989 */
1990 if (ret < 0 || buf[1] != 'z')
1991 result |= 1;
1992 }
1993 { /* This test fails on mingw. */
1994 wchar_t buf[2];
1995 int ret = swprintf (buf, 2, L"%lc", (wint_t)0);
1996 /* Expected: ret = 1
1997 mingw: ret = 0
1998 */
1999 if (ret != 1)
2000 result |= 2;
2001 }
2002 return result;
2003}]])],
2004 [gl_cv_func_swprintf_works=yes],
2005 [gl_cv_func_swprintf_works=no],
2006 [case "$host_os" in
2007 # Guess yes on glibc systems.
2008 *-gnu* | gnu*) gl_cv_func_swprintf_works="guessing yes";;
2009 # Guess no on musl systems.
2010 *-musl* | midipix*) gl_cv_func_swprintf_works="guessing no";;
2011 # Guess no on FreeBSD, NetBSD, OpenBSD, macOS, AIX.
2012 freebsd* | midnightbsd* | netbsd* | openbsd* | darwin* | aix*)
2013 gl_cv_func_swprintf_works="guessing no";;
2014 # Guess no on native Windows.
2015 mingw* | windows* | pw*) gl_cv_func_swprintf_works="guessing no";;
2016 # If we don't know, obey --enable-cross-guesses.
2017 *) gl_cv_func_swprintf_works="$gl_cross_guess_normal";;
2018 esac
2019 ])
2020 ])
2021])
2022
2023dnl Test whether the *wprintf family of functions supports the 'a' and 'A'
2024dnl conversion specifier for hexadecimal output of 'long double' numbers.
2025dnl (ISO C99, POSIX:2001)
2026dnl Result is gl_cv_func_swprintf_directive_la.
2027
2028AC_DEFUN([gl_SWPRINTF_DIRECTIVE_LA],
2029[
2030 AC_REQUIRE([AC_PROG_CC])
2031 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
2032 AC_CACHE_CHECK([whether swprintf supports the 'La' and 'LA' directives],
2033 [gl_cv_func_swprintf_directive_la],
2034 [
2035 AC_RUN_IFELSE(
2036 [AC_LANG_SOURCE([[
2037#include <stdio.h>
2038#include <wchar.h>
2039static wchar_t buf[100];
2040int main ()
2041{
2042 int result = 0;
2043 /* This catches a glibc 2.15, Haiku 2022, NetBSD 10.0 bug. */
2044 if (swprintf (buf, sizeof (buf) / sizeof (wchar_t),
2045 L"%La %d", 3.1416015625L, 33, 44, 55) < 0
2046 || (wcscmp (buf, L"0x1.922p+1 33") != 0
2047 && wcscmp (buf, L"0x3.244p+0 33") != 0
2048 && wcscmp (buf, L"0x6.488p-1 33") != 0
2049 && wcscmp (buf, L"0xc.91p-2 33") != 0))
2050 result |= 1;
2051 return result;
2052}]])],
2053 [gl_cv_func_swprintf_directive_la=yes],
2054 [gl_cv_func_swprintf_directive_la=no],
2055 [case "$host_os" in
2056 # Guess yes on glibc >= 2.17 systems.
2057 *-gnu* | gnu*)
2058 AC_EGREP_CPP([Unlucky], [
2059 #include <features.h>
2060 #ifdef __GNU_LIBRARY__
2061 #if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 16) || (__GLIBC__ > 2)) && !defined __UCLIBC__
2062 Unlucky
2063 #endif
2064 #endif
2065 ],
2066 [gl_cv_func_swprintf_directive_la="guessing yes"],
2067 [gl_cv_func_swprintf_directive_la="guessing no"])
2068 ;;
2069 # Guess yes on musl systems.
2070 *-musl* | midipix*) gl_cv_func_swprintf_directive_la="guessing yes";;
2071 # Guess yes on Android.
2072 linux*-android*) gl_cv_func_swprintf_directive_la="guessing yes";;
2073 # Guess no on NetBSD.
2074 netbsd*) gl_cv_func_swprintf_directive_la="guessing no";;
2075 # Guess no on native Windows.
2076 mingw* | windows*) gl_cv_func_swprintf_directive_la="guessing no";;
2077 # If we don't know, obey --enable-cross-guesses.
2078 *) gl_cv_func_swprintf_directive_la="$gl_cross_guess_normal";;
2079 esac
2080 ])
2081 ])
2082])
2083
2084dnl Test whether the *wprintf family of functions supports the 'lc' conversion
2085dnl specifier for all wide characters.
2086dnl (ISO C11, POSIX:2001)
2087dnl Result is gl_cv_func_swprintf_directive_lc.
2088
2089AC_DEFUN([gl_SWPRINTF_DIRECTIVE_LC],
2090[
2091 AC_REQUIRE([AC_PROG_CC])
2092 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
2093 AC_CACHE_CHECK([whether swprintf supports the 'lc' directive],
2094 [gl_cv_func_swprintf_directive_lc],
2095 [
2096 AC_RUN_IFELSE(
2097 [AC_LANG_SOURCE([[
2098#include <stdio.h>
2099#include <wchar.h>
2100static wchar_t buf[100];
2101static wint_t L_invalid = (wchar_t) 0x76543210;
2102int main ()
2103{
2104 int result = 0;
2105 /* This catches a musl libc 1.2.4, Android bug.
2106 Reported at <https://www.openwall.com/lists/musl/2023/06/12/3>. */
2107 if (swprintf (buf, sizeof (buf) / sizeof (wchar_t),
2108 L"%lc %d", L_invalid, 33, 44, 55) < 0)
2109 result |= 1;
2110 return result;
2111}]])],
2112 [gl_cv_func_swprintf_directive_lc=yes],
2113 [gl_cv_func_swprintf_directive_lc=no],
2114 [case "$host_os" in
2115 # Guess yes on glibc systems.
2116 *-gnu* | gnu*) gl_cv_func_swprintf_directive_lc="guessing yes";;
2117 # Guess no on musl systems.
2118 *-musl* | midipix*) gl_cv_func_swprintf_directive_lc="guessing no";;
2119 # Guess no on Android.
2120 linux*-android*) gl_cv_func_swprintf_directive_lc="guessing no";;
2121 # Guess yes on native Windows.
2122 mingw* | windows*) gl_cv_func_swprintf_directive_lc="guessing yes";;
2123 # If we don't know, obey --enable-cross-guesses.
2124 *) gl_cv_func_swprintf_directive_lc="$gl_cross_guess_normal";;
2125 esac
2126 ])
2127 ])
2128])
2129
1644dnl The results of these tests on various platforms are: 2130dnl The results of these tests on various platforms are:
1645dnl 2131dnl
1646dnl 1 = gl_PRINTF_SIZES_C99 2132dnl 1 = gl_PRINTF_SIZES_C99
1647dnl 2 = gl_PRINTF_LONG_DOUBLE 2133dnl 2 = gl_PRINTF_SIZES_C23
1648dnl 3 = gl_PRINTF_INFINITE 2134dnl 3 = gl_PRINTF_LONG_DOUBLE
1649dnl 4 = gl_PRINTF_INFINITE_LONG_DOUBLE 2135dnl 4 = gl_PRINTF_INFINITE
1650dnl 5 = gl_PRINTF_DIRECTIVE_A 2136dnl 5 = gl_PRINTF_INFINITE_LONG_DOUBLE
1651dnl 6 = gl_PRINTF_DIRECTIVE_F 2137dnl 6 = gl_PRINTF_DIRECTIVE_A
1652dnl 7 = gl_PRINTF_DIRECTIVE_N 2138dnl 7 = gl_PRINTF_DIRECTIVE_B
1653dnl 8 = gl_PRINTF_DIRECTIVE_LS 2139dnl 8 = gl_PRINTF_DIRECTIVE_UPPERCASE_B
1654dnl 9 = gl_PRINTF_POSITIONS 2140dnl 9 = gl_PRINTF_DIRECTIVE_F
1655dnl 10 = gl_PRINTF_FLAG_GROUPING 2141dnl 10 = gl_PRINTF_DIRECTIVE_N
1656dnl 11 = gl_PRINTF_FLAG_LEFTADJUST 2142dnl 11 = gl_PRINTF_DIRECTIVE_LS
1657dnl 12 = gl_PRINTF_FLAG_ZERO 2143dnl 12 = gl_PRINTF_DIRECTIVE_LC
1658dnl 13 = gl_PRINTF_PRECISION 2144dnl 13 = gl_PRINTF_POSITIONS
1659dnl 14 = gl_PRINTF_ENOMEM 2145dnl 14 = gl_PRINTF_FLAG_GROUPING
1660dnl 15 = gl_SNPRINTF_PRESENCE 2146dnl 15 = gl_PRINTF_FLAG_LEFTADJUST
1661dnl 16 = gl_SNPRINTF_TRUNCATION_C99 2147dnl 16 = gl_PRINTF_FLAG_ZERO
1662dnl 17 = gl_SNPRINTF_RETVAL_C99 2148dnl 17 = gl_PRINTF_FLAG_ALT_PRECISION_ZERO
1663dnl 18 = gl_SNPRINTF_DIRECTIVE_N 2149dnl 18 = gl_PRINTF_PRECISION
1664dnl 19 = gl_SNPRINTF_SIZE1 2150dnl 19 = gl_PRINTF_ENOMEM
1665dnl 20 = gl_VSNPRINTF_ZEROSIZE_C99 2151dnl 20 = gl_SNPRINTF_PRESENCE
2152dnl 21 = gl_SNPRINTF_TRUNCATION_C99
2153dnl 22 = gl_SNPRINTF_RETVAL_C99
2154dnl 23 = gl_SNPRINTF_DIRECTIVE_N
2155dnl 24 = gl_SNPRINTF_SIZE1
2156dnl 25 = gl_VSNPRINTF_ZEROSIZE_C99
2157dnl 26 = gl_SWPRINTF_WORKS
2158dnl 27 = gl_SWPRINTF_DIRECTIVE_LA
2159dnl 28 = gl_SWPRINTF_DIRECTIVE_LC
1666dnl 2160dnl
1667dnl 1 = checking whether printf supports size specifiers as in C99... 2161dnl 1 = checking whether printf supports size specifiers as in C99...
1668dnl 2 = checking whether printf supports 'long double' arguments... 2162dnl 2 = checking whether printf supports size specifiers as in C23...
1669dnl 3 = checking whether printf supports infinite 'double' arguments... 2163dnl 3 = checking whether printf supports 'long double' arguments...
1670dnl 4 = checking whether printf supports infinite 'long double' arguments... 2164dnl 4 = checking whether printf supports infinite 'double' arguments...
1671dnl 5 = checking whether printf supports the 'a' and 'A' directives... 2165dnl 5 = checking whether printf supports infinite 'long double' arguments...
1672dnl 6 = checking whether printf supports the 'F' directive... 2166dnl 6 = checking whether printf supports the 'a' and 'A' directives...
1673dnl 7 = checking whether printf supports the 'n' directive... 2167dnl 7 = checking whether printf supports the 'b' directive...
1674dnl 8 = checking whether printf supports the 'ls' directive... 2168dnl 8 = checking whether printf supports the 'B' directive...
1675dnl 9 = checking whether printf supports POSIX/XSI format strings with positions... 2169dnl 9 = checking whether printf supports the 'F' directive...
1676dnl 10 = checking whether printf supports the grouping flag... 2170dnl 10 = checking whether printf supports the 'n' directive...
1677dnl 11 = checking whether printf supports the left-adjust flag correctly... 2171dnl 11 = checking whether printf supports the 'ls' directive...
1678dnl 12 = checking whether printf supports the zero flag correctly... 2172dnl 12 = checking whether printf supports the 'lc' directive correctly...
1679dnl 13 = checking whether printf supports large precisions... 2173dnl 13 = checking whether printf supports POSIX/XSI format strings with positions...
1680dnl 14 = checking whether printf survives out-of-memory conditions... 2174dnl 14 = checking whether printf supports the grouping flag...
1681dnl 15 = checking for snprintf... 2175dnl 15 = checking whether printf supports the left-adjust flag correctly...
1682dnl 16 = checking whether snprintf truncates the result as in C99... 2176dnl 16 = checking whether printf supports the zero flag correctly...
1683dnl 17 = checking whether snprintf returns a byte count as in C99... 2177dnl 17 = checking whether printf supports the alternative flag with a zero precision...
1684dnl 18 = checking whether snprintf fully supports the 'n' directive... 2178dnl 18 = checking whether printf supports large precisions...
1685dnl 19 = checking whether snprintf respects a size of 1... 2179dnl 19 = checking whether printf survives out-of-memory conditions...
1686dnl 20 = checking whether vsnprintf respects a zero size as in C99... 2180dnl 20 = checking for snprintf...
2181dnl 21 = checking whether snprintf truncates the result as in C99...
2182dnl 22 = checking whether snprintf returns a byte count as in C99...
2183dnl 23 = checking whether snprintf fully supports the 'n' directive...
2184dnl 24 = checking whether snprintf respects a size of 1...
2185dnl 25 = checking whether vsnprintf respects a zero size as in C99...
2186dnl 26 = checking whether swprintf works...
2187dnl 27 = checking whether swprintf supports the 'La' and 'LA' directives...
2188dnl 28 = checking whether swprintf supports the 'lc' directive...
1687dnl 2189dnl
1688dnl . = yes, # = no. 2190dnl . = yes, # = no.
1689dnl 2191dnl
1690dnl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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
1691dnl glibc 2.5 . . . . . . . . . . . . . . . . . . . . 2193dnl musl libc 1.2.3 . # . . . . # # . . . # . . . . ? . . . . . . . . # . #
1692dnl glibc 2.3.6 . . . . # . . . . . . . . . . . . . . . 2194dnl glibc 2.35 . # . . . . . . . . . . . . . . . . . . . . . . . . . .
1693dnl FreeBSD 13.0 . . . . # . . . . . . . . # . . . . . . 2195dnl glibc 2.5 . # . . . . # # . . . . . . . . . . . . . . . . . . # .
1694dnl FreeBSD 5.4, 6.1 . . . . # . . . . . . # . # . . . . . . 2196dnl glibc 2.3.6 . # . . . # # # . . . . . . . . . . . . . . . . . . # .
1695dnl Mac OS X 10.13.5 . . . # # . # . . . . . . . . . . # . . 2197dnl FreeBSD 14.0 . . . . . # . . . . . . . . . . . . # . . . . . . # . #
1696dnl Mac OS X 10.5.8 . . . # # . . . . . . # . . . . . . . . 2198dnl FreeBSD 13.0 . # . . . # # # . . . . . . . . . . # . . . . . . # . #
1697dnl Mac OS X 10.3.9 . . . . # . . . . . . # . # . . . . . . 2199dnl FreeBSD 5.4, 6.1 . # . . . # # # . . . . . . . # ? . # . . . . . . # ? ?
1698dnl OpenBSD 6.0, 6.7 . . . . # . . . . . . . . # . . . . . . 2200dnl Mac OS X 10.13.5 . # . . # # # # . # . . . . . . . . . . . . # . . # ? ?
1699dnl OpenBSD 3.9, 4.0 . . # # # # . # . # . # . # . . . . . . 2201dnl Mac OS X 10.5.8 . # . . # # # # . . . . . . . # # . . . . . . . . # ? ?
1700dnl Cygwin 1.7.0 (2009) . . . # . . . ? . . . . . ? . . . . . . 2202dnl Mac OS X 10.3.9 . # . . . # # # . . . . . . . # # . # . . . . . . # ? ?
1701dnl Cygwin 1.5.25 (2008) . . . # # . . # . . . . . # . . . . . . 2203dnl OpenBSD 6.0, 6.7 . # . . . # # # . . . . . . . . . . # . . . . . . # . #
1702dnl Cygwin 1.5.19 (2006) # . . # # # . # . # . # # # . . . . . . 2204dnl OpenBSD 3.9, 4.0 . # . # # # # # # . # . . # . # ? . # . . . . . . # ? ?
1703dnl Solaris 11.4 . . # # # . . # . . . # . . . . . . . . 2205dnl Cygwin 1.7.0 (2009) . # . . # . # # . . ? ? . . . . ? . ? . . . . . . ? ? ?
1704dnl Solaris 11.3 . . . . # . . # . . . . . . . . . . . . 2206dnl Cygwin 1.5.25 (2008) . # . . # # # # . . # ? . . . . ? . # . . . . . . ? ? ?
1705dnl Solaris 11.0 . . # # # . . # . . . # . . . . . . . . 2207dnl Cygwin 1.5.19 (2006) # # . . # # # # # . # ? . # . # ? # # . . . . . . ? ? ?
1706dnl Solaris 10 . . # # # . . # . . . # # . . . . . . . 2208dnl Solaris 11.4 . # . # # # # # . . # . . . . # . . . . . . . . . . # .
1707dnl Solaris 2.6 ... 9 # . # # # # . # . . . # # . . . # . . . 2209dnl Solaris 11.3 . # . . . # # # . . # . . . . . . . . . . . . . . . # .
1708dnl Solaris 2.5.1 # . # # # # . # . . . # . . # # # # # # 2210dnl Solaris 11.0 . # . # # # # # . . # . . . . # . . . . . . . . . ? ? ?
1709dnl AIX 7.1 . . # # # . . . . . . # # . . . . . . . 2211dnl Solaris 10 . # . # # # # # . . # . . . . # . # . . . . . . . . # .
1710dnl AIX 5.2 . . # # # . . . . . . # . . . . . . . . 2212dnl Solaris 2.6 ... 9 # # . # # # # # # . # . . . . # ? # . . . # . . . ? ? ?
1711dnl AIX 4.3.2, 5.1 # . # # # # . . . . . # . . . . # . . . 2213dnl Solaris 2.5.1 # # . # # # # # # . # . . . . # ? . . # # # # # # ? ? ?
1712dnl HP-UX 11.31 . . . . # . . . . . . # . . . . # # . . 2214dnl AIX 7.1 . # . # # # # # . . . . . . . # . # . . . . . . . # . .
1713dnl HP-UX 11.{00,11,23} # . . . # # . . . . . # . . . . # # . # 2215dnl AIX 5.2 . # . # # # # # . . . . . . . # ? . . . . . . . . # ? ?
1714dnl HP-UX 10.20 # . # . # # . ? . . # # . . . . # # ? # 2216dnl AIX 4.3.2, 5.1 # # . # # # # # # . . . . . . # ? . . . . # . . . # ? ?
1715dnl IRIX 6.5 # . # # # # . # . . . # . . . . # . . . 2217dnl HP-UX 11.31 . # . . . # # # . . . ? . . . # ? . . . . # # . . ? ? ?
1716dnl OSF/1 5.1 # . # # # # . . . . . # . . . . # . . # 2218dnl HP-UX 11.{00,11,23} # # . . . # # # # . . ? . . . # ? . . . . # # . # ? ? ?
1717dnl OSF/1 4.0d # . # # # # . . . . . # . . # # # # # # 2219dnl HP-UX 10.20 # # . # . # # # # . ? ? . . # # ? . . . . # # ? # ? ? ?
1718dnl NetBSD 9.0 . . . . # . . . . . . . . . . . . . . . 2220dnl IRIX 6.5 # # . # # # # # # . # . . . . # ? . . . . # . . . # ? ?
1719dnl NetBSD 5.0 . . . # # . . . . . . # . # . . . . . . 2221dnl OSF/1 5.1 # # . # # # # # # . . ? . . . # ? . . . . # . . # ? ? ?
1720dnl NetBSD 4.0 . ? ? ? ? ? . ? . ? ? ? ? ? . . . ? ? ? 2222dnl OSF/1 4.0d # # . # # # # # # . . ? . . . # ? . . # # # # # # ? ? ?
1721dnl NetBSD 3.0 . . . . # # . ? # # ? # . # . . . . . . 2223dnl NetBSD 9.0 . # . . . # # # . . . . . . . . . . . . . . . . . # . #
1722dnl Haiku . . . # # # . # . . . . . ? . . ? . . . 2224dnl NetBSD 5.0 . # . . # # # # . . . . . . . # ? . # . . . . . . # ? ?
1723dnl BeOS # # . # # # . ? # . ? . # ? . . ? . . . 2225dnl NetBSD 4.0 . # ? ? ? ? # # ? . ? . . ? ? ? ? ? ? . . . ? ? ? # ? ?
1724dnl Android 4.3 . . # # # # # # . # . # . # . . . # . . 2226dnl NetBSD 3.0 . # . . . # # # # . ? . # # ? # ? . # . . . . . . # ? ?
1725dnl old mingw / msvcrt # # # # # # . . # # . # # ? . # # # . . 2227dnl Haiku . # . . # # # # # . # ? . . . . ? . ? . . ? . . . . # .
1726dnl MSVC 9 # # # # # # # . # # . # # ? # # # # . . 2228dnl BeOS # # # . # # # # # . ? ? # . ? . ? # ? . . ? . . . ? ? ?
1727dnl mingw 2009-2011 . # . # . . . . # # . . . ? . . . . . . 2229dnl Android 4.3 . # . # # # # # # # # ? . # . # ? . # . . . # . . ? ? ?
1728dnl mingw-w64 2011 # # # # # # . . # # . # # ? . # # # . . 2230dnl old mingw / msvcrt # # # # # # # # # . . ? # # . # ? # ? . # # # . . # ? ?
2231dnl MSVC 9 # # # # # # # # # # . ? # # . # ? # ? # # # # . . # ? ?
2232dnl mingw 2009-2011 . # # . # . # # . . . ? # # . . ? . ? . . . . . . # ? ?
2233dnl mingw-w64 2011 # # # # # # # # # . . ? # # . # ? # ? . # # # . . # ? ?
diff --git a/gl/m4/pthread_rwlock_rdlock.m4 b/gl/m4/pthread_rwlock_rdlock.m4
index ae6a8853..b8b5b117 100644
--- a/gl/m4/pthread_rwlock_rdlock.m4
+++ b/gl/m4/pthread_rwlock_rdlock.m4
@@ -1,5 +1,6 @@
1# pthread_rwlock_rdlock.m4 serial 4 1# pthread_rwlock_rdlock.m4
2dnl Copyright (C) 2017-2023 Free Software Foundation, Inc. 2# serial 8
3dnl Copyright (C) 2017-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -34,11 +35,11 @@ dnl https://sourceware.org/bugzilla/show_bug.cgi?id=13701
34dnl https://bugzilla.redhat.com/show_bug.cgi?id=1410052 35dnl https://bugzilla.redhat.com/show_bug.cgi?id=1410052
35AC_DEFUN([gl_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER], 36AC_DEFUN([gl_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER],
36[ 37[
37 AC_REQUIRE([gl_THREADLIB_EARLY]) 38 AC_REQUIRE([gl_THREADLIB])
38 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles 39 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
39 AC_CACHE_CHECK([whether pthread_rwlock_rdlock prefers a writer to a reader], 40 AC_CACHE_CHECK([whether pthread_rwlock_rdlock prefers a writer to a reader],
40 [gl_cv_pthread_rwlock_rdlock_prefer_writer], 41 [gl_cv_pthread_rwlock_rdlock_prefer_writer],
41 [save_LIBS="$LIBS" 42 [saved_LIBS="$LIBS"
42 LIBS="$LIBS $LIBMULTITHREAD" 43 LIBS="$LIBS $LIBMULTITHREAD"
43 AC_RUN_IFELSE( 44 AC_RUN_IFELSE(
44 [AC_LANG_SOURCE([[ 45 [AC_LANG_SOURCE([[
@@ -156,25 +157,25 @@ main ()
156 [gl_cv_pthread_rwlock_rdlock_prefer_writer=yes], 157 [gl_cv_pthread_rwlock_rdlock_prefer_writer=yes],
157 [gl_cv_pthread_rwlock_rdlock_prefer_writer=no], 158 [gl_cv_pthread_rwlock_rdlock_prefer_writer=no],
158 [case "$host_os" in 159 [case "$host_os" in
159 # Guess no on glibc systems. 160 # Guess no on glibc systems.
160 *-gnu* | gnu*) gl_cv_pthread_rwlock_rdlock_prefer_writer="guessing no" ;; 161 *-gnu* | gnu*) gl_cv_pthread_rwlock_rdlock_prefer_writer="guessing no" ;;
161 # Guess no on musl systems. 162 # Guess no on musl systems.
162 *-musl*) gl_cv_pthread_rwlock_rdlock_prefer_writer="guessing no" ;; 163 *-musl* | midipix*) gl_cv_pthread_rwlock_rdlock_prefer_writer="guessing no" ;;
163 # Guess no on bionic systems. 164 # Guess no on bionic systems.
164 *-android*) gl_cv_pthread_rwlock_rdlock_prefer_writer="guessing no" ;; 165 *-android*) gl_cv_pthread_rwlock_rdlock_prefer_writer="guessing no" ;;
165 # Guess yes on native Windows with the mingw-w64 winpthreads library. 166 # Guess yes on native Windows with the mingw-w64 winpthreads library.
166 # Guess no on native Windows with the gnulib windows-rwlock module. 167 # Guess no on native Windows with the gnulib windows-rwlock module.
167 mingw*) if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then 168 mingw* | windows*) if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then
168 gl_cv_pthread_rwlock_rdlock_prefer_writer="guessing yes" 169 gl_cv_pthread_rwlock_rdlock_prefer_writer="guessing yes"
169 else 170 else
170 gl_cv_pthread_rwlock_rdlock_prefer_writer="guessing no" 171 gl_cv_pthread_rwlock_rdlock_prefer_writer="guessing no"
171 fi 172 fi
172 ;; 173 ;;
173 # If we don't know, obey --enable-cross-guesses. 174 # If we don't know, obey --enable-cross-guesses.
174 *) gl_cv_pthread_rwlock_rdlock_prefer_writer="$gl_cross_guess_normal" ;; 175 *) gl_cv_pthread_rwlock_rdlock_prefer_writer="$gl_cross_guess_normal" ;;
175 esac 176 esac
176 ]) 177 ])
177 LIBS="$save_LIBS" 178 LIBS="$saved_LIBS"
178 ]) 179 ])
179 case "$gl_cv_pthread_rwlock_rdlock_prefer_writer" in 180 case "$gl_cv_pthread_rwlock_rdlock_prefer_writer" in
180 *yes) 181 *yes)
diff --git a/gl/m4/realloc.m4 b/gl/m4/realloc.m4
index d22138fc..eb90d588 100644
--- a/gl/m4/realloc.m4
+++ b/gl/m4/realloc.m4
@@ -1,5 +1,6 @@
1# realloc.m4 serial 26 1# realloc.m4
2dnl Copyright (C) 2007, 2009-2023 Free Software Foundation, Inc. 2# serial 29
3dnl Copyright (C) 2007, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -16,7 +17,8 @@ AC_DEFUN([_AC_FUNC_REALLOC_IF],
16 [[#include <stdlib.h> 17 [[#include <stdlib.h>
17 ]], 18 ]],
18 [[void *p = realloc (0, 0); 19 [[void *p = realloc (0, 0);
19 int result = !p; 20 void * volatile vp = p;
21 int result = !vp;
20 free (p); 22 free (p);
21 return result;]]) 23 return result;]])
22 ], 24 ],
@@ -25,8 +27,8 @@ AC_DEFUN([_AC_FUNC_REALLOC_IF],
25 [case "$host_os" in 27 [case "$host_os" in
26 # Guess yes on platforms where we know the result. 28 # Guess yes on platforms where we know the result.
27 *-gnu* | freebsd* | netbsd* | openbsd* | bitrig* \ 29 *-gnu* | freebsd* | netbsd* | openbsd* | bitrig* \
28 | gnu* | *-musl* | midnightbsd* \ 30 | gnu* | *-musl* | midipix* | midnightbsd* \
29 | hpux* | solaris* | cygwin* | mingw* | msys* ) 31 | hpux* | solaris* | cygwin* | mingw* | windows* | msys* )
30 ac_cv_func_realloc_0_nonnull="guessing yes" ;; 32 ac_cv_func_realloc_0_nonnull="guessing yes" ;;
31 # If we don't know, obey --enable-cross-guesses. 33 # If we don't know, obey --enable-cross-guesses.
32 *) ac_cv_func_realloc_0_nonnull="$gl_cross_guess_normal" ;; 34 *) ac_cv_func_realloc_0_nonnull="$gl_cross_guess_normal" ;;
diff --git a/gl/m4/reallocarray.m4 b/gl/m4/reallocarray.m4
index 1607b7a9..958095e1 100644
--- a/gl/m4/reallocarray.m4
+++ b/gl/m4/reallocarray.m4
@@ -1,5 +1,6 @@
1# reallocarray.m4 serial 3 1# reallocarray.m4
2dnl Copyright (C) 2017-2023 Free Software Foundation, Inc. 2# serial 5
3dnl Copyright (C) 2017-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -11,9 +12,12 @@ AC_DEFUN([gl_FUNC_REALLOCARRAY],
11 12
12 AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) 13 AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
13 AC_REQUIRE([gl_CHECK_MALLOC_PTRDIFF]) 14 AC_REQUIRE([gl_CHECK_MALLOC_PTRDIFF])
14 AC_CHECK_FUNCS([reallocarray]) 15 gl_CHECK_FUNCS_ANDROID([reallocarray], [[#include <stdlib.h>]])
15 if test "$ac_cv_func_reallocarray" = no; then 16 if test "$ac_cv_func_reallocarray" = no; then
16 HAVE_REALLOCARRAY=0 17 HAVE_REALLOCARRAY=0
18 case "$gl_cv_onwards_func_reallocarray" in
19 future*) REPLACE_REALLOCARRAY=1 ;;
20 esac
17 elif test "$gl_cv_malloc_ptrdiff" = no; then 21 elif test "$gl_cv_malloc_ptrdiff" = no; then
18 REPLACE_REALLOCARRAY=1 22 REPLACE_REALLOCARRAY=1
19 fi 23 fi
diff --git a/gl/m4/regex.m4 b/gl/m4/regex.m4
index c89a1432..f0101fe6 100644
--- a/gl/m4/regex.m4
+++ b/gl/m4/regex.m4
@@ -1,10 +1,9 @@
1# serial 73 1# regex.m4
2 2# serial 75
3# Copyright (C) 1996-2001, 2003-2023 Free Software Foundation, Inc. 3dnl Copyright (C) 1996-2001, 2003-2024 Free Software Foundation, Inc.
4# 4dnl This file is free software; the Free Software Foundation
5# This file is free software; the Free Software Foundation 5dnl gives unlimited permission to copy and/or distribute it,
6# gives unlimited permission to copy and/or distribute it, 6dnl with or without modifications, as long as this notice is preserved.
7# with or without modifications, as long as this notice is preserved.
8 7
9dnl Initially derived from code in GNU grep. 8dnl Initially derived from code in GNU grep.
10dnl Mostly written by Jim Meyering. 9dnl Mostly written by Jim Meyering.
@@ -15,7 +14,7 @@ AC_DEFUN([gl_REGEX],
15[ 14[
16 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles 15 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
17 AC_ARG_WITH([included-regex], 16 AC_ARG_WITH([included-regex],
18 [AS_HELP_STRING([--without-included-regex], 17 [AS_HELP_STRING([[--without-included-regex]],
19 [don't compile regex; this is the default on systems 18 [don't compile regex; this is the default on systems
20 with recent-enough versions of the GNU C Library 19 with recent-enough versions of the GNU C Library
21 (use with caution on other systems).])]) 20 (use with caution on other systems).])])
@@ -327,10 +326,10 @@ AC_DEFUN([gl_REGEX],
327 [gl_cv_func_re_compile_pattern_working=yes], 326 [gl_cv_func_re_compile_pattern_working=yes],
328 [gl_cv_func_re_compile_pattern_working=no], 327 [gl_cv_func_re_compile_pattern_working=no],
329 [case "$host_os" in 328 [case "$host_os" in
330 # Guess no on native Windows. 329 # Guess no on native Windows.
331 mingw*) gl_cv_func_re_compile_pattern_working="guessing no" ;; 330 mingw* | windows*) gl_cv_func_re_compile_pattern_working="guessing no" ;;
332 # Otherwise obey --enable-cross-guesses. 331 # Otherwise obey --enable-cross-guesses.
333 *) gl_cv_func_re_compile_pattern_working="$gl_cross_guess_normal" ;; 332 *) gl_cv_func_re_compile_pattern_working="$gl_cross_guess_normal" ;;
334 esac 333 esac
335 ]) 334 ])
336 ]) 335 ])
diff --git a/gl/m4/servent.m4 b/gl/m4/servent.m4
index 0f35b8b8..422003b4 100644
--- a/gl/m4/servent.m4
+++ b/gl/m4/servent.m4
@@ -1,5 +1,6 @@
1# servent.m4 serial 4 1# servent.m4
2dnl Copyright (C) 2008, 2010-2023 Free Software Foundation, Inc. 2# serial 5
3dnl Copyright (C) 2008, 2010-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -28,7 +29,7 @@ AC_DEFUN([gl_SERVENT],
28 AC_CACHE_CHECK([for getservbyname in winsock2.h and -lws2_32], 29 AC_CACHE_CHECK([for getservbyname in winsock2.h and -lws2_32],
29 [gl_cv_w32_getservbyname], 30 [gl_cv_w32_getservbyname],
30 [gl_cv_w32_getservbyname=no 31 [gl_cv_w32_getservbyname=no
31 gl_save_LIBS="$LIBS" 32 gl_saved_LIBS="$LIBS"
32 LIBS="$LIBS -lws2_32" 33 LIBS="$LIBS -lws2_32"
33 AC_LINK_IFELSE( 34 AC_LINK_IFELSE(
34 [AC_LANG_PROGRAM( 35 [AC_LANG_PROGRAM(
@@ -40,7 +41,7 @@ AC_DEFUN([gl_SERVENT],
40 ]], 41 ]],
41 [[getservbyname(NULL,NULL);]])], 42 [[getservbyname(NULL,NULL);]])],
42 [gl_cv_w32_getservbyname=yes]) 43 [gl_cv_w32_getservbyname=yes])
43 LIBS="$gl_save_LIBS" 44 LIBS="$gl_saved_LIBS"
44 ]) 45 ])
45 if test "$gl_cv_w32_getservbyname" = "yes"; then 46 if test "$gl_cv_w32_getservbyname" = "yes"; then
46 SERVENT_LIB="-lws2_32" 47 SERVENT_LIB="-lws2_32"
diff --git a/gl/m4/setenv.m4 b/gl/m4/setenv.m4
index 16f9eb55..e7f00f39 100644
--- a/gl/m4/setenv.m4
+++ b/gl/m4/setenv.m4
@@ -1,5 +1,6 @@
1# setenv.m4 serial 30 1# setenv.m4
2dnl Copyright (C) 2001-2004, 2006-2023 Free Software Foundation, Inc. 2# serial 33
3dnl Copyright (C) 2001-2004, 2006-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -35,12 +36,12 @@ AC_DEFUN([gl_FUNC_SETENV],
35 ]])], 36 ]])],
36 [gl_cv_func_setenv_works=yes], [gl_cv_func_setenv_works=no], 37 [gl_cv_func_setenv_works=yes], [gl_cv_func_setenv_works=no],
37 [case "$host_os" in 38 [case "$host_os" in
38 # Guess yes on glibc systems. 39 # Guess yes on glibc systems.
39 *-gnu* | gnu*) gl_cv_func_setenv_works="guessing yes" ;; 40 *-gnu* | gnu*) gl_cv_func_setenv_works="guessing yes" ;;
40 # Guess yes on musl systems. 41 # Guess yes on musl systems.
41 *-musl*) gl_cv_func_setenv_works="guessing yes" ;; 42 *-musl* | midipix*) gl_cv_func_setenv_works="guessing yes" ;;
42 # If we don't know, obey --enable-cross-guesses. 43 # If we don't know, obey --enable-cross-guesses.
43 *) gl_cv_func_setenv_works="$gl_cross_guess_normal" ;; 44 *) gl_cv_func_setenv_works="$gl_cross_guess_normal" ;;
44 esac 45 esac
45 ])]) 46 ])])
46 case "$gl_cv_func_setenv_works" in 47 case "$gl_cv_func_setenv_works" in
@@ -151,11 +152,10 @@ int unsetenv (const char *name);
151# Prerequisites of lib/setenv.c. 152# Prerequisites of lib/setenv.c.
152AC_DEFUN([gl_PREREQ_SETENV], 153AC_DEFUN([gl_PREREQ_SETENV],
153[ 154[
154 AC_REQUIRE([AC_FUNC_ALLOCA])
155 AC_REQUIRE([gl_ENVIRON]) 155 AC_REQUIRE([gl_ENVIRON])
156 AC_CHECK_HEADERS_ONCE([unistd.h]) 156 AC_CHECK_HEADERS_ONCE([unistd.h])
157 AC_CHECK_HEADERS([search.h]) 157 AC_CHECK_HEADERS([search.h])
158 AC_CHECK_FUNCS([tsearch]) 158 gl_CHECK_FUNCS_ANDROID([tsearch], [[#include <search.h>]])
159]) 159])
160 160
161# Prerequisites of lib/unsetenv.c. 161# Prerequisites of lib/unsetenv.c.
diff --git a/gl/m4/setlocale_null.m4 b/gl/m4/setlocale_null.m4
index 032119d0..e5b7d28b 100644
--- a/gl/m4/setlocale_null.m4
+++ b/gl/m4/setlocale_null.m4
@@ -1,5 +1,6 @@
1# setlocale_null.m4 serial 5 1# setlocale_null.m4
2dnl Copyright (C) 2019-2023 Free Software Foundation, Inc. 2# serial 9
3dnl Copyright (C) 2019-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -13,11 +14,25 @@ AC_DEFUN([gl_FUNC_SETLOCALE_NULL],
13 AC_CACHE_CHECK([whether setlocale (LC_ALL, NULL) is multithread-safe], 14 AC_CACHE_CHECK([whether setlocale (LC_ALL, NULL) is multithread-safe],
14 [gl_cv_func_setlocale_null_all_mtsafe], 15 [gl_cv_func_setlocale_null_all_mtsafe],
15 [case "$host_os" in 16 [case "$host_os" in
16 # Guess no on musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin. 17 # Guess no on musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku.
17 *-musl* | darwin* | freebsd* | midnightbsd* | netbsd* | openbsd* | aix* | haiku* | cygwin*) 18 *-musl* | midipix* | darwin* | freebsd* | midnightbsd* | netbsd* | openbsd* | aix* | haiku*)
18 gl_cv_func_setlocale_null_all_mtsafe=no ;; 19 gl_cv_func_setlocale_null_all_mtsafe=no ;;
20 # Guess no on Cygwin < 3.4.6.
21 cygwin*)
22 AC_EGREP_CPP([Lucky user],
23 [
24#if defined __CYGWIN__
25 #include <cygwin/version.h>
26 #if CYGWIN_VERSION_DLL_COMBINED >= CYGWIN_VERSION_DLL_MAKE_COMBINED (3004, 6)
27 Lucky user
28 #endif
29#endif
30 ],
31 [gl_cv_func_setlocale_null_all_mtsafe=yes],
32 [gl_cv_func_setlocale_null_all_mtsafe=no])
33 ;;
19 # Guess yes on glibc, HP-UX, IRIX, Solaris, native Windows. 34 # Guess yes on glibc, HP-UX, IRIX, Solaris, native Windows.
20 *-gnu* | gnu* | hpux* | irix* | solaris* | mingw*) 35 *-gnu* | gnu* | hpux* | irix* | solaris* | mingw* | windows*)
21 gl_cv_func_setlocale_null_all_mtsafe=yes ;; 36 gl_cv_func_setlocale_null_all_mtsafe=yes ;;
22 # If we don't know, obey --enable-cross-guesses. 37 # If we don't know, obey --enable-cross-guesses.
23 *) 38 *)
@@ -26,7 +41,7 @@ AC_DEFUN([gl_FUNC_SETLOCALE_NULL],
26 ]) 41 ])
27 dnl On platforms without multithreading, there is no issue. 42 dnl On platforms without multithreading, there is no issue.
28 case "$host_os" in 43 case "$host_os" in
29 mingw*) ;; 44 mingw* | windows*) ;;
30 *) 45 *)
31 if test $gl_pthread_api = no && test $ac_cv_header_threads_h = no; then 46 if test $gl_pthread_api = no && test $ac_cv_header_threads_h = no; then
32 gl_cv_func_setlocale_null_all_mtsafe="trivially yes" 47 gl_cv_func_setlocale_null_all_mtsafe="trivially yes"
@@ -48,7 +63,7 @@ AC_DEFUN([gl_FUNC_SETLOCALE_NULL],
48 openbsd* | aix*) 63 openbsd* | aix*)
49 gl_cv_func_setlocale_null_one_mtsafe=no ;; 64 gl_cv_func_setlocale_null_one_mtsafe=no ;;
50 # Guess yes on glibc, musl libc, macOS, FreeBSD, NetBSD, HP-UX, IRIX, Solaris, Haiku, Cygwin, native Windows. 65 # Guess yes on glibc, musl libc, macOS, FreeBSD, NetBSD, HP-UX, IRIX, Solaris, Haiku, Cygwin, native Windows.
51 *-gnu* | gnu* | *-musl* | darwin* | freebsd* | midnightbsd* | netbsd* | hpux* | irix* | solaris* | haiku* | cygwin* | mingw*) 66 *-gnu* | gnu* | *-musl* | midipix* | darwin* | freebsd* | midnightbsd* | netbsd* | hpux* | irix* | solaris* | haiku* | cygwin* | mingw* | windows*)
52 gl_cv_func_setlocale_null_one_mtsafe=yes ;; 67 gl_cv_func_setlocale_null_one_mtsafe=yes ;;
53 # If we don't know, obey --enable-cross-guesses. 68 # If we don't know, obey --enable-cross-guesses.
54 *) 69 *)
@@ -57,7 +72,7 @@ AC_DEFUN([gl_FUNC_SETLOCALE_NULL],
57 ]) 72 ])
58 dnl On platforms without multithreading, there is no issue. 73 dnl On platforms without multithreading, there is no issue.
59 case "$host_os" in 74 case "$host_os" in
60 mingw*) ;; 75 mingw* | windows*) ;;
61 *) 76 *)
62 if test $gl_pthread_api = no && test $ac_cv_header_threads_h = no; then 77 if test $gl_pthread_api = no && test $ac_cv_header_threads_h = no; then
63 gl_cv_func_setlocale_null_one_mtsafe="trivially yes" 78 gl_cv_func_setlocale_null_one_mtsafe="trivially yes"
@@ -74,20 +89,25 @@ AC_DEFUN([gl_FUNC_SETLOCALE_NULL],
74 dnl Determine link dependencies of lib/setlocale_null.c and lib/setlocale-lock.c. 89 dnl Determine link dependencies of lib/setlocale_null.c and lib/setlocale-lock.c.
75 if test $SETLOCALE_NULL_ALL_MTSAFE = 0 || test $SETLOCALE_NULL_ONE_MTSAFE = 0; then 90 if test $SETLOCALE_NULL_ALL_MTSAFE = 0 || test $SETLOCALE_NULL_ONE_MTSAFE = 0; then
76 case "$host_os" in 91 case "$host_os" in
77 mingw*) LIB_SETLOCALE_NULL= ;; 92 mingw* | windows*)
93 SETLOCALE_NULL_LIB=
94 ;;
78 *) 95 *)
79 gl_WEAK_SYMBOLS 96 gl_WEAK_SYMBOLS
80 case "$gl_cv_have_weak" in 97 case "$gl_cv_have_weak" in
81 *yes) LIB_SETLOCALE_NULL= ;; 98 *yes) SETLOCALE_NULL_LIB= ;;
82 *) LIB_SETLOCALE_NULL="$LIBPTHREAD" ;; 99 *) SETLOCALE_NULL_LIB="$LIBPTHREAD" ;;
83 esac 100 esac
84 ;; 101 ;;
85 esac 102 esac
86 else 103 else
87 LIB_SETLOCALE_NULL= 104 SETLOCALE_NULL_LIB=
88 fi 105 fi
89 dnl LIB_SETLOCALE_NULL is expected to be '-pthread' or '-lpthread' on AIX 106 dnl SETLOCALE_NULL_LIB is expected to be '-pthread' or '-lpthread' on AIX
90 dnl with gcc or xlc, and empty otherwise. 107 dnl with gcc or xlc, and empty otherwise.
108 AC_SUBST([SETLOCALE_NULL_LIB])
109 dnl For backward compatibility.
110 LIB_SETLOCALE_NULL="$SETLOCALE_NULL_LIB"
91 AC_SUBST([LIB_SETLOCALE_NULL]) 111 AC_SUBST([LIB_SETLOCALE_NULL])
92]) 112])
93 113
diff --git a/gl/m4/sha256.m4 b/gl/m4/sha256.m4
index 4d1d1dda..ad5596a4 100644
--- a/gl/m4/sha256.m4
+++ b/gl/m4/sha256.m4
@@ -1,5 +1,6 @@
1# sha256.m4 serial 8 1# sha256.m4
2dnl Copyright (C) 2005, 2008-2023 Free Software Foundation, Inc. 2# serial 8
3dnl Copyright (C) 2005, 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/size_max.m4 b/gl/m4/size_max.m4
index 0763366d..df91cf06 100644
--- a/gl/m4/size_max.m4
+++ b/gl/m4/size_max.m4
@@ -1,5 +1,6 @@
1# size_max.m4 serial 12 1# size_max.m4
2dnl Copyright (C) 2003, 2005-2006, 2008-2023 Free Software Foundation, Inc. 2# serial 12
3dnl Copyright (C) 2003, 2005-2006, 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/snprintf.m4 b/gl/m4/snprintf.m4
index 4b5fbdbf..6dbe146f 100644
--- a/gl/m4/snprintf.m4
+++ b/gl/m4/snprintf.m4
@@ -1,5 +1,6 @@
1# snprintf.m4 serial 7 1# snprintf.m4
2dnl Copyright (C) 2002-2004, 2007-2023 Free Software Foundation, Inc. 2# serial 7
3dnl Copyright (C) 2002-2004, 2007-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/socketlib.m4 b/gl/m4/socketlib.m4
index a556af1e..09f01161 100644
--- a/gl/m4/socketlib.m4
+++ b/gl/m4/socketlib.m4
@@ -1,5 +1,6 @@
1# socketlib.m4 serial 3 1# socketlib.m4
2dnl Copyright (C) 2008-2023 Free Software Foundation, Inc. 2# serial 4
3dnl Copyright (C) 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -18,7 +19,7 @@ AC_DEFUN([gl_SOCKETLIB],
18 dnl defined through -lws2_32), we need to call it. 19 dnl defined through -lws2_32), we need to call it.
19 AC_CACHE_CHECK([for WSAStartup], 20 AC_CACHE_CHECK([for WSAStartup],
20 [gl_cv_func_wsastartup], [ 21 [gl_cv_func_wsastartup], [
21 gl_save_LIBS="$LIBS" 22 gl_saved_LIBS="$LIBS"
22 LIBS="$LIBS -lws2_32" 23 LIBS="$LIBS -lws2_32"
23 AC_LINK_IFELSE( 24 AC_LINK_IFELSE(
24 [AC_LANG_PROGRAM([[ 25 [AC_LANG_PROGRAM([[
@@ -33,7 +34,7 @@ AC_DEFUN([gl_SOCKETLIB],
33 ], 34 ],
34 [gl_cv_func_wsastartup=yes], 35 [gl_cv_func_wsastartup=yes],
35 [gl_cv_func_wsastartup=no]) 36 [gl_cv_func_wsastartup=no])
36 LIBS="$gl_save_LIBS" 37 LIBS="$gl_saved_LIBS"
37 ]) 38 ])
38 if test "$gl_cv_func_wsastartup" = "yes"; then 39 if test "$gl_cv_func_wsastartup" = "yes"; then
39 AC_DEFINE([WINDOWS_SOCKETS], [1], [Define if WSAStartup is needed.]) 40 AC_DEFINE([WINDOWS_SOCKETS], [1], [Define if WSAStartup is needed.])
@@ -56,8 +57,8 @@ AC_DEFUN([gl_SOCKETLIB],
56#endif 57#endif
57char setsockopt();]], [[setsockopt();]])], 58char setsockopt();]], [[setsockopt();]])],
58 [], 59 [],
59 [gl_save_LIBS="$LIBS" 60 [gl_saved_LIBS="$LIBS"
60 LIBS="$gl_save_LIBS -lsocket" 61 LIBS="$gl_saved_LIBS -lsocket"
61 AC_LINK_IFELSE([AC_LANG_PROGRAM([[extern 62 AC_LINK_IFELSE([AC_LANG_PROGRAM([[extern
62#ifdef __cplusplus 63#ifdef __cplusplus
63"C" 64"C"
@@ -65,7 +66,7 @@ char setsockopt();]], [[setsockopt();]])],
65char setsockopt();]], [[setsockopt();]])], 66char setsockopt();]], [[setsockopt();]])],
66 [gl_cv_lib_socket="-lsocket"]) 67 [gl_cv_lib_socket="-lsocket"])
67 if test -z "$gl_cv_lib_socket"; then 68 if test -z "$gl_cv_lib_socket"; then
68 LIBS="$gl_save_LIBS -lnetwork" 69 LIBS="$gl_saved_LIBS -lnetwork"
69 AC_LINK_IFELSE([AC_LANG_PROGRAM([[extern 70 AC_LINK_IFELSE([AC_LANG_PROGRAM([[extern
70#ifdef __cplusplus 71#ifdef __cplusplus
71"C" 72"C"
@@ -73,7 +74,7 @@ char setsockopt();]], [[setsockopt();]])],
73char setsockopt();]], [[setsockopt();]])], 74char setsockopt();]], [[setsockopt();]])],
74 [gl_cv_lib_socket="-lnetwork"]) 75 [gl_cv_lib_socket="-lnetwork"])
75 if test -z "$gl_cv_lib_socket"; then 76 if test -z "$gl_cv_lib_socket"; then
76 LIBS="$gl_save_LIBS -lnet" 77 LIBS="$gl_saved_LIBS -lnet"
77 AC_LINK_IFELSE([AC_LANG_PROGRAM([[extern 78 AC_LINK_IFELSE([AC_LANG_PROGRAM([[extern
78#ifdef __cplusplus 79#ifdef __cplusplus
79"C" 80"C"
@@ -82,7 +83,7 @@ char setsockopt();]], [[setsockopt();]])],
82 [gl_cv_lib_socket="-lnet"]) 83 [gl_cv_lib_socket="-lnet"])
83 fi 84 fi
84 fi 85 fi
85 LIBS="$gl_save_LIBS" 86 LIBS="$gl_saved_LIBS"
86 ]) 87 ])
87 if test -z "$gl_cv_lib_socket"; then 88 if test -z "$gl_cv_lib_socket"; then
88 gl_cv_lib_socket="none needed" 89 gl_cv_lib_socket="none needed"
diff --git a/gl/m4/sockets.m4 b/gl/m4/sockets.m4
index ed9cb873..a3dfe92f 100644
--- a/gl/m4/sockets.m4
+++ b/gl/m4/sockets.m4
@@ -1,5 +1,6 @@
1# sockets.m4 serial 7 1# sockets.m4
2dnl Copyright (C) 2008-2023 Free Software Foundation, Inc. 2# serial 7
3dnl Copyright (C) 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/socklen.m4 b/gl/m4/socklen.m4
index 1c63a853..9ece0abb 100644
--- a/gl/m4/socklen.m4
+++ b/gl/m4/socklen.m4
@@ -1,5 +1,6 @@
1# socklen.m4 serial 11 1# socklen.m4
2dnl Copyright (C) 2005-2007, 2009-2023 Free Software Foundation, Inc. 2# serial 11
3dnl Copyright (C) 2005-2007, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/sockpfaf.m4 b/gl/m4/sockpfaf.m4
index 6c6dc2f7..c68b3abb 100644
--- a/gl/m4/sockpfaf.m4
+++ b/gl/m4/sockpfaf.m4
@@ -1,5 +1,6 @@
1# sockpfaf.m4 serial 10 1# sockpfaf.m4
2dnl Copyright (C) 2004, 2006, 2009-2023 Free Software Foundation, Inc. 2# serial 10
3dnl Copyright (C) 2004, 2006, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/ssize_t.m4 b/gl/m4/ssize_t.m4
index 1c12c33e..c15f948a 100644
--- a/gl/m4/ssize_t.m4
+++ b/gl/m4/ssize_t.m4
@@ -1,23 +1,38 @@
1# ssize_t.m4 serial 5 (gettext-0.18.2) 1# ssize_t.m4
2dnl Copyright (C) 2001-2003, 2006, 2010-2023 Free Software Foundation, Inc. 2# serial 6
3dnl Copyright (C) 2001-2003, 2006, 2010-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
6 7
7dnl From Bruno Haible. 8dnl From Bruno Haible.
8dnl Test whether ssize_t is defined. 9dnl Define ssize_t if it does not already exist.
9 10
10AC_DEFUN([gt_TYPE_SSIZE_T], 11AC_DEFUN([gt_TYPE_SSIZE_T],
11[ 12[
12 AC_CACHE_CHECK([for ssize_t], [gt_cv_ssize_t], 13 AC_CACHE_CHECK([for ssize_t], [gl_cv_ssize_t],
13 [AC_COMPILE_IFELSE( 14 [AC_COMPILE_IFELSE(
14 [AC_LANG_PROGRAM( 15 [AC_LANG_PROGRAM(
15 [[#include <sys/types.h>]], 16 [[#include <sys/types.h>]],
16 [[int x = sizeof (ssize_t *) + sizeof (ssize_t); 17 [[int x = sizeof (ssize_t *) + sizeof (ssize_t);
17 return !x;]])], 18 return !x;]])],
18 [gt_cv_ssize_t=yes], [gt_cv_ssize_t=no])]) 19 [gl_cv_ssize_t=yes], [gl_cv_ssize_t=no])])
19 if test $gt_cv_ssize_t = no; then 20 if test $gl_cv_ssize_t = no; then
20 AC_DEFINE([ssize_t], [int], 21 dnl On 64-bit native Windows, ssize_t needs to be defined as 'long long',
21 [Define as a signed type of the same size as size_t.]) 22 dnl for consistency with the 64-bit size_t.
23 AC_CACHE_CHECK([whether size_t is wider than 'long'], [gl_cv_size_t_large],
24 [AC_COMPILE_IFELSE(
25 [AC_LANG_PROGRAM(
26 [[#include <sys/types.h>
27 typedef int array [2 * (sizeof (size_t) > sizeof (long)) - 1];
28 ]])],
29 [gl_cv_size_t_large=yes], [gl_cv_size_t_large=no])])
30 if test $gl_cv_size_t_large = yes; then
31 gl_def_ssize_t='long long'
32 else
33 gl_def_ssize_t='long'
34 fi
35 AC_DEFINE_UNQUOTED([ssize_t], [$gl_def_ssize_t],
36 [Define as a signed type of the same size as size_t.])
22 fi 37 fi
23]) 38])
diff --git a/gl/m4/stat-time.m4 b/gl/m4/stat-time.m4
index 40993d57..e8ee7d51 100644
--- a/gl/m4/stat-time.m4
+++ b/gl/m4/stat-time.m4
@@ -1,11 +1,11 @@
1# Checks for stat-related time functions. 1# stat-time.m4
2 2# serial 1
3# Copyright (C) 1998-1999, 2001, 2003, 2005-2007, 2009-2023 Free Software 3dnl Copyright (C) 1998-1999, 2001, 2003, 2005-2007, 2009-2024 Free Software Foundation, Inc.
4# 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.
5 7
6# This file is free software; the Free Software Foundation 8# Checks for stat-related time functions.
7# gives unlimited permission to copy and/or distribute it,
8# with or without modifications, as long as this notice is preserved.
9 9
10dnl From Paul Eggert. 10dnl From Paul Eggert.
11 11
diff --git a/gl/m4/stat.m4 b/gl/m4/stat.m4
index 4d241e27..fabd360c 100644
--- a/gl/m4/stat.m4
+++ b/gl/m4/stat.m4
@@ -1,10 +1,9 @@
1# serial 18 1# stat.m4
2 2# serial 21
3# Copyright (C) 2009-2023 Free Software Foundation, Inc. 3dnl Copyright (C) 2009-2024 Free Software Foundation, Inc.
4# 4dnl This file is free software; the Free Software Foundation
5# This file is free software; the Free Software Foundation 5dnl gives unlimited permission to copy and/or distribute it,
6# gives unlimited permission to copy and/or distribute it, 6dnl with or without modifications, as long as this notice is preserved.
7# with or without modifications, as long as this notice is preserved.
8 7
9AC_DEFUN([gl_FUNC_STAT], 8AC_DEFUN([gl_FUNC_STAT],
10[ 9[
@@ -12,7 +11,7 @@ AC_DEFUN([gl_FUNC_STAT],
12 AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS]) 11 AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])
13 AC_CHECK_FUNCS_ONCE([lstat]) 12 AC_CHECK_FUNCS_ONCE([lstat])
14 case "$host_os" in 13 case "$host_os" in
15 mingw*) 14 mingw* | windows*)
16 dnl On this platform, the original stat() returns st_atime, st_mtime, 15 dnl On this platform, the original stat() returns st_atime, st_mtime,
17 dnl st_ctime values that are affected by the time zone. 16 dnl st_ctime values that are affected by the time zone.
18 REPLACE_STAT=1 17 REPLACE_STAT=1
@@ -45,6 +44,8 @@ AC_DEFUN([gl_FUNC_STAT],
45 [case "$host_os" in 44 [case "$host_os" in
46 # Guess yes on Linux systems. 45 # Guess yes on Linux systems.
47 linux-* | linux) gl_cv_func_stat_file_slash="guessing yes" ;; 46 linux-* | linux) gl_cv_func_stat_file_slash="guessing yes" ;;
47 # Guess yes on systems that emulate the Linux system calls.
48 midipix*) gl_cv_func_stat_file_slash="guessing yes" ;;
48 # Guess yes on glibc systems. 49 # Guess yes on glibc systems.
49 *-gnu* | gnu*) gl_cv_func_stat_file_slash="guessing yes" ;; 50 *-gnu* | gnu*) gl_cv_func_stat_file_slash="guessing yes" ;;
50 # If we don't know, obey --enable-cross-guesses. 51 # If we don't know, obey --enable-cross-guesses.
@@ -59,8 +60,8 @@ AC_DEFUN([gl_FUNC_STAT],
59 help when passed a file name with a trailing slash]);; 60 help when passed a file name with a trailing slash]);;
60 esac 61 esac
61 case $host_os in 62 case $host_os in
62 dnl Solaris stat can return a negative tv_nsec. 63 dnl macOS and Solaris stat can return a negative tv_nsec.
63 solaris*) 64 darwin* | solaris*)
64 REPLACE_FSTAT=1 ;; 65 REPLACE_FSTAT=1 ;;
65 esac 66 esac
66 ;; 67 ;;
@@ -78,7 +79,7 @@ AC_DEFUN([gl_PREREQ_STAT], [
78AC_DEFUN([gl_PREREQ_STAT_W32], [ 79AC_DEFUN([gl_PREREQ_STAT_W32], [
79 AC_REQUIRE([AC_CANONICAL_HOST]) 80 AC_REQUIRE([AC_CANONICAL_HOST])
80 case "$host_os" in 81 case "$host_os" in
81 mingw*) 82 mingw* | windows*)
82 AC_CHECK_HEADERS([sdkddkver.h]) 83 AC_CHECK_HEADERS([sdkddkver.h])
83 ;; 84 ;;
84 esac 85 esac
diff --git a/gl/m4/std-gnu11.m4 b/gl/m4/std-gnu11.m4
index 4179470e..37324c15 100644
--- a/gl/m4/std-gnu11.m4
+++ b/gl/m4/std-gnu11.m4
@@ -1,3 +1,6 @@
1# std-gnu11.m4
2# serial 1
3
1# 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 -*-
2 5
3# This implementation is taken from GNU Autoconf lib/autoconf/c.m4 6# This implementation is taken from GNU Autoconf lib/autoconf/c.m4
@@ -9,7 +12,7 @@
9m4_version_prereq([2.70], [], [ 12m4_version_prereq([2.70], [], [
10 13
11 14
12# Copyright (C) 2001-2023 Free Software Foundation, Inc. 15# Copyright (C) 2001-2024 Free Software Foundation, Inc.
13 16
14# This program is free software; you can redistribute it and/or modify 17# This program is free software; you can redistribute it and/or modify
15# it under the terms of the GNU General Public License as published by 18# it under the terms of the GNU General Public License as published by
diff --git a/gl/m4/stdalign.m4 b/gl/m4/stdalign.m4
index dc297175..2b4762f3 100644
--- a/gl/m4/stdalign.m4
+++ b/gl/m4/stdalign.m4
@@ -1,20 +1,24 @@
1# Check for alignas and alignof that conform to C23. 1# stdalign.m4
2 2# serial 1
3dnl Copyright 2011-2023 Free Software Foundation, Inc. 3dnl Copyright 2011-2024 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 7
8# Check for alignas and alignof that conform to C23.
9
10dnl Written by Paul Eggert and Bruno Haible.
11
8# Prepare for substituting <stdalign.h> if it is not supported. 12# Prepare for substituting <stdalign.h> if it is not supported.
9 13
10AC_DEFUN([gl_STDALIGN_H], 14AC_DEFUN([gl_ALIGNASOF],
11[ 15[
12 AC_CACHE_CHECK([for alignas and alignof], 16 AC_CACHE_CHECK([for alignas and alignof],
13 [gl_cv_header_working_stdalign_h], 17 [gl_cv_header_working_stdalign_h],
14 [gl_save_CFLAGS=$CFLAGS 18 [gl_saved_CFLAGS=$CFLAGS
15 for gl_working in "yes, keywords" "yes, <stdalign.h> macros"; do 19 for gl_working in "yes, keywords" "yes, <stdalign.h> macros"; do
16 AS_CASE([$gl_working], 20 AS_CASE([$gl_working],
17 [*stdalign.h*], [CFLAGS="$gl_save_CFLAGS -DINCLUDE_STDALIGN_H"]) 21 [*stdalign.h*], [CFLAGS="$gl_saved_CFLAGS -DINCLUDE_STDALIGN_H"])
18 AC_COMPILE_IFELSE( 22 AC_COMPILE_IFELSE(
19 [AC_LANG_PROGRAM( 23 [AC_LANG_PROGRAM(
20 [[#include <stdint.h> 24 [[#include <stdint.h>
@@ -54,85 +58,151 @@ AC_DEFUN([gl_STDALIGN_H],
54 [gl_cv_header_working_stdalign_h=$gl_working], 58 [gl_cv_header_working_stdalign_h=$gl_working],
55 [gl_cv_header_working_stdalign_h=no]) 59 [gl_cv_header_working_stdalign_h=no])
56 60
57 CFLAGS=$gl_save_CFLAGS 61 CFLAGS=$gl_saved_CFLAGS
58 test "$gl_cv_header_working_stdalign_h" != no && break 62 test "$gl_cv_header_working_stdalign_h" != no && break
59 done]) 63 done])
60 64
61 GL_GENERATE_STDALIGN_H=false
62 AS_CASE([$gl_cv_header_working_stdalign_h], 65 AS_CASE([$gl_cv_header_working_stdalign_h],
63 [no],
64 [GL_GENERATE_STDALIGN_H=true],
65 [yes*keyword*], 66 [yes*keyword*],
66 [AC_DEFINE([HAVE_C_ALIGNASOF], [1], 67 [AC_DEFINE([HAVE_C_ALIGNASOF], [1],
67 [Define to 1 if the alignas and alignof keywords work.])]) 68 [Define to 1 if the alignas and alignof keywords work.])])
68 69
69 AC_CHECK_HEADERS_ONCE([stdalign.h])
70
71 dnl The "zz" puts this toward config.h's end, to avoid potential 70 dnl The "zz" puts this toward config.h's end, to avoid potential
72 dnl collisions with other definitions. 71 dnl collisions with other definitions.
73 AH_VERBATIM([zzalignas], 72 AH_VERBATIM([zzalignas],
74[#if !defined HAVE_C_ALIGNASOF && __cplusplus < 201103 && !defined alignof 73[#if !defined HAVE_C_ALIGNASOF \
75# if HAVE_STDALIGN_H 74 && !(defined __cplusplus && 201103 <= __cplusplus) \
75 && !defined alignof
76# if defined HAVE_STDALIGN_H
76# include <stdalign.h> 77# include <stdalign.h>
77# else 78# endif
78 /* Substitute. Keep consistent with gnulib/lib/stdalign.in.h. */ 79
79# ifndef _GL_STDALIGN_H 80/* ISO C23 alignas and alignof for platforms that lack it.
80# define _GL_STDALIGN_H 81
81# undef _Alignas 82 References:
82# undef _Alignof 83 ISO C23 (latest free draft
83# if (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112 \ 84 <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n3047.pdf>)
84 || (defined __GNUC__ && __GNUC__ < 4 + (__GNUC_MINOR__ < 9) \ 85 sections 6.5.3.4, 6.7.5, 7.15.
85 && !defined __clang__) \ 86 C++11 (latest free draft
86 || (defined __clang__ && __clang_major__ < 8)) 87 <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf>)
87# ifdef __cplusplus 88 section 18.10. */
88# if (201103 <= __cplusplus || defined _MSC_VER) 89
89# define _Alignof(type) alignof (type) 90/* alignof (TYPE), also known as _Alignof (TYPE), yields the alignment
90# else 91 requirement of a structure member (i.e., slot or field) that is of
91 template <class __t> struct __alignof_helper { char __a; __t __b; }; 92 type TYPE, as an integer constant expression.
92# define _Alignof(type) offsetof (__alignof_helper<type>, __b) 93
93# define _GL_STDALIGN_NEEDS_STDDEF 1 94 This differs from GCC's and clang's __alignof__ operator, which can
94# endif 95 yield a better-performing alignment for an object of that type. For
96 example, on x86 with GCC and on Linux/x86 with clang,
97 __alignof__ (double) and __alignof__ (long long) are 8, whereas
98 alignof (double) and alignof (long long) are 4 unless the option
99 '-malign-double' is used.
100
101 The result cannot be used as a value for an 'enum' constant, if you
102 want to be portable to HP-UX 10.20 cc and AIX 3.2.5 xlc. */
103
104/* 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 clang versions < 8.0.0 have the same bug. */
107# if (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112 \
108 || (defined __GNUC__ && __GNUC__ < 4 + (__GNUC_MINOR__ < 9) \
109 && !defined __clang__) \
110 || (defined __clang__ && __clang_major__ < 8))
111# undef/**/_Alignof
112# ifdef __cplusplus
113# if (201103 <= __cplusplus || defined _MSC_VER)
114# define _Alignof(type) alignof (type)
95# else 115# else
116 template <class __t> struct __alignof_helper { char __a; __t __b; };
96# if (defined __GNUC__ && 4 <= __GNUC__) || defined __clang__ 117# if (defined __GNUC__ && 4 <= __GNUC__) || defined __clang__
97# define _Alignof(type) __builtin_offsetof (struct { char __a; type __b; }, __b) 118# define _Alignof(type) __builtin_offsetof (__alignof_helper<type>, __b)
98# else 119# else
99# define _Alignof(type) offsetof (struct { char __a; type __b; }, __b) 120# define _Alignof(type) offsetof (__alignof_helper<type>, __b)
100# define _GL_STDALIGN_NEEDS_STDDEF 1
101# endif 121# endif
122# define _GL_STDALIGN_NEEDS_STDDEF 1
102# endif 123# endif
103# endif 124# else
104# if ! (defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER)) 125# if (defined __GNUC__ && 4 <= __GNUC__) || defined __clang__
105# define alignof _Alignof 126# define _Alignof(type) __builtin_offsetof (struct { char __a; type __b; }, __b)
106# endif 127# else
107# define __alignof_is_defined 1 128# define _Alignof(type) offsetof (struct { char __a; type __b; }, __b)
108# if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112 129# define _GL_STDALIGN_NEEDS_STDDEF 1
109# if defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER)
110# define _Alignas(a) alignas (a)
111# elif (!defined __attribute__ \
112 && ((defined __APPLE__ && defined __MACH__ \
113 ? 4 < __GNUC__ + (1 <= __GNUC_MINOR__) \
114 : __GNUC__ && !defined __ibmxl__) \
115 || (4 <= __clang_major__) \
116 || (__ia64 && (61200 <= __HP_cc || 61200 <= __HP_aCC)) \
117 || __ICC || 0x590 <= __SUNPRO_C || 0x0600 <= __xlC__))
118# define _Alignas(a) __attribute__ ((__aligned__ (a)))
119# elif 1300 <= _MSC_VER
120# define _Alignas(a) __declspec (align (a))
121# endif 130# endif
122# endif 131# endif
123# if ((defined _Alignas \ 132# endif
124 && !(defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER))) \ 133# if ! (defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER))
125 || (defined __STDC_VERSION__ && 201112 <= __STDC_VERSION__)) 134# undef/**/alignof
126# define alignas _Alignas 135# define alignof _Alignof
127# endif 136# endif
128# if (defined alignas \ 137
129 || (defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER))) 138/* alignas (A), also known as _Alignas (A), aligns a variable or type
130# define __alignas_is_defined 1 139 to the alignment A, where A is an integer constant expression. For
131# endif 140 example:
132# if _GL_STDALIGN_NEEDS_STDDEF 141
133# include <stddef.h> 142 int alignas (8) foo;
134# endif 143 struct s { int a; int alignas (8) bar; };
135# endif /* _GL_STDALIGN_H */ 144
145 aligns the address of FOO and the offset of BAR to be multiples of 8.
146
147 A should be a power of two that is at least the type's alignment
148 and at most the implementation's alignment limit. This limit is
149 2**28 on typical GNUish hosts, and 2**13 on MSVC. To be portable
150 to MSVC through at least version 10.0, A should be an integer
151 constant, as MSVC does not support expressions such as 1 << 3.
152 To be portable to Sun C 5.11, do not align auto variables to
153 anything stricter than their default alignment.
154
155 The following C23 requirements are not supported here:
156
157 - If A is zero, alignas has no effect.
158 - alignas can be used multiple times; the strictest one wins.
159 - alignas (TYPE) is equivalent to alignas (alignof (TYPE)).
160
161 */
162# if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112
163# if defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER)
164# define _Alignas(a) alignas (a)
165# elif (!defined __attribute__ \
166 && ((defined __APPLE__ && defined __MACH__ \
167 ? 4 < __GNUC__ + (1 <= __GNUC_MINOR__) \
168 : __GNUC__ && !defined __ibmxl__) \
169 || (4 <= __clang_major__) \
170 || (__ia64 && (61200 <= __HP_cc || 61200 <= __HP_aCC)) \
171 || __ICC || 0x590 <= __SUNPRO_C || 0x0600 <= __xlC__))
172# define _Alignas(a) __attribute__ ((__aligned__ (a)))
173# elif 1300 <= _MSC_VER
174# define _Alignas(a) __declspec (align (a))
175# endif
176# endif
177# if !defined HAVE_STDALIGN_H
178# if ((defined _Alignas \
179 && !(defined __cplusplus \
180 && (201103 <= __cplusplus || defined _MSC_VER))) \
181 || (defined __STDC_VERSION__ && 201112 <= __STDC_VERSION__))
182# define alignas _Alignas
183# endif
184# endif
185
186# if defined _GL_STDALIGN_NEEDS_STDDEF
187# include <stddef.h>
136# endif 188# endif
137#endif]) 189#endif])
138]) 190])
191
192AC_DEFUN([gl_STDALIGN_H],
193[
194 AC_REQUIRE([gl_ALIGNASOF])
195 if test "$gl_cv_header_working_stdalign_h" = no; then
196 GL_GENERATE_STDALIGN_H=true
197 else
198 GL_GENERATE_STDALIGN_H=false
199 fi
200
201 gl_CHECK_NEXT_HEADERS([stdalign.h])
202 if test $ac_cv_header_stdalign_h = yes; then
203 HAVE_STDALIGN_H=1
204 else
205 HAVE_STDALIGN_H=0
206 fi
207 AC_SUBST([HAVE_STDALIGN_H])
208])
diff --git a/gl/m4/stddef_h.m4 b/gl/m4/stddef_h.m4
index a2322ebb..84d3bae8 100644
--- a/gl/m4/stddef_h.m4
+++ b/gl/m4/stddef_h.m4
@@ -1,5 +1,6 @@
1# stddef_h.m4 serial 13 1# stddef_h.m4
2dnl Copyright (C) 2009-2023 Free Software Foundation, Inc. 2# serial 14
3dnl Copyright (C) 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -68,6 +69,21 @@ AC_DEFUN_ONCE([gl_STDDEF_H],
68 GL_GENERATE_STDDEF_H=true 69 GL_GENERATE_STDDEF_H=true
69 fi 70 fi
70 71
72 AC_CACHE_CHECK([for unreachable],
73 [gl_cv_func_unreachable],
74 [AC_LINK_IFELSE(
75 [AC_LANG_PROGRAM(
76 [[#include <stddef.h>
77 ]],
78 [[unreachable ();
79 ]])],
80 [gl_cv_func_unreachable=yes],
81 [gl_cv_func_unreachable=no])
82 ])
83 if test $gl_cv_func_unreachable = no; then
84 GL_GENERATE_STDDEF_H=true
85 fi
86
71 if $GL_GENERATE_STDDEF_H; then 87 if $GL_GENERATE_STDDEF_H; then
72 gl_NEXT_HEADERS([stddef.h]) 88 gl_NEXT_HEADERS([stddef.h])
73 fi 89 fi
diff --git a/gl/m4/stdint.m4 b/gl/m4/stdint.m4
index d6961b09..2dea8469 100644
--- a/gl/m4/stdint.m4
+++ b/gl/m4/stdint.m4
@@ -1,5 +1,6 @@
1# stdint.m4 serial 61 1# stdint.m4
2dnl Copyright (C) 2001-2023 Free Software Foundation, Inc. 2# serial 63
3dnl Copyright (C) 2001-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -150,7 +151,10 @@ intmax_t i = INTMAX_MAX;
150uintmax_t j = UINTMAX_MAX; 151uintmax_t j = UINTMAX_MAX;
151 152
152/* Check that SIZE_MAX has the correct type, if possible. */ 153/* Check that SIZE_MAX has the correct type, if possible. */
153#if 201112 <= __STDC_VERSION__ 154/* ISO C 11 mandates _Generic, but GCC versions < 4.9 lack it. */
155#if 201112 <= __STDC_VERSION__ \
156 && (!defined __GNUC__ || 4 < __GNUC__ + (9 <= __GNUC_MINOR__) \
157 || defined __clang__)
154int k = _Generic (SIZE_MAX, size_t: 0); 158int k = _Generic (SIZE_MAX, size_t: 0);
155#elif (2 <= __GNUC__ || 4 <= __clang_major__ || defined __IBM__TYPEOF__ \ 159#elif (2 <= __GNUC__ || 4 <= __clang_major__ || defined __IBM__TYPEOF__ \
156 || (0x5110 <= __SUNPRO_C && !__STDC__)) 160 || (0x5110 <= __SUNPRO_C && !__STDC__))
@@ -283,10 +287,10 @@ static const char *macro_values[] =
283 [gl_cv_header_working_stdint_h=yes], 287 [gl_cv_header_working_stdint_h=yes],
284 [], 288 [],
285 [case "$host_os" in 289 [case "$host_os" in
286 # Guess yes on native Windows. 290 # Guess yes on native Windows.
287 mingw*) gl_cv_header_working_stdint_h="guessing yes" ;; 291 mingw* | windows*) gl_cv_header_working_stdint_h="guessing yes" ;;
288 # In general, assume it works. 292 # In general, assume it works.
289 *) gl_cv_header_working_stdint_h="guessing yes" ;; 293 *) gl_cv_header_working_stdint_h="guessing yes" ;;
290 esac 294 esac
291 ]) 295 ])
292 ]) 296 ])
diff --git a/gl/m4/stdint_h.m4 b/gl/m4/stdint_h.m4
index 70349f6c..29f42160 100644
--- a/gl/m4/stdint_h.m4
+++ b/gl/m4/stdint_h.m4
@@ -1,5 +1,6 @@
1# stdint_h.m4 serial 9 1# stdint_h.m4
2dnl Copyright (C) 1997-2004, 2006, 2008-2023 Free Software Foundation, Inc. 2# serial 9
3dnl Copyright (C) 1997-2004, 2006, 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/stdio_h.m4 b/gl/m4/stdio_h.m4
index 94271e11..8eb5816a 100644
--- a/gl/m4/stdio_h.m4
+++ b/gl/m4/stdio_h.m4
@@ -1,12 +1,23 @@
1# stdio_h.m4 serial 59 1# stdio_h.m4
2dnl Copyright (C) 2007-2023 Free Software Foundation, Inc. 2# serial 63
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
6 7
7AC_DEFUN_ONCE([gl_STDIO_H], 8AC_DEFUN([gl_STDIO_H_EARLY],
8[ 9[
9 AC_REQUIRE([gl_STDIO_H_DEFAULTS]) 10 dnl Defining __USE_MINGW_ANSI_STDIO to 1 must be done early, because
11 dnl the results of several configure tests depend on it: The tests
12 dnl - checking whether snprintf returns a byte count as in C99...
13 dnl - checking whether snprintf truncates the result as in C99...
14 dnl - checking whether printf supports the 'F' directive...
15 dnl - checking whether printf supports the grouping flag...
16 dnl - checking whether printf supports the zero flag correctly...
17 dnl - checking whether printf supports infinite 'double' arguments...
18 dnl - checking whether printf supports large precisions...
19 dnl report 'yes' if __USE_MINGW_ANSI_STDIO is 1 but 'no' if
20 dnl __USE_MINGW_ANSI_STDIO is not set.
10 AH_VERBATIM([MINGW_ANSI_STDIO], 21 AH_VERBATIM([MINGW_ANSI_STDIO],
11[/* Use GNU style printf and scanf. */ 22[/* Use GNU style printf and scanf. */
12#ifndef __USE_MINGW_ANSI_STDIO 23#ifndef __USE_MINGW_ANSI_STDIO
@@ -14,6 +25,11 @@ AC_DEFUN_ONCE([gl_STDIO_H],
14#endif 25#endif
15]) 26])
16 AC_DEFINE([__USE_MINGW_ANSI_STDIO]) 27 AC_DEFINE([__USE_MINGW_ANSI_STDIO])
28])
29
30AC_DEFUN_ONCE([gl_STDIO_H],
31[
32 AC_REQUIRE([gl_STDIO_H_DEFAULTS])
17 gl_NEXT_HEADERS([stdio.h]) 33 gl_NEXT_HEADERS([stdio.h])
18 34
19 dnl Determine whether __USE_MINGW_ANSI_STDIO makes printf and 35 dnl Determine whether __USE_MINGW_ANSI_STDIO makes printf and
@@ -40,6 +56,9 @@ AC_DEFUN_ONCE([gl_STDIO_H],
40 attribute "__gnu_printf__" instead of "__printf__"]) 56 attribute "__gnu_printf__" instead of "__printf__"])
41 fi 57 fi
42 58
59 dnl For defining _PRINTF_NAN_LEN_MAX.
60 gl_MUSL_LIBC
61
43 dnl This ifdef is an optimization, to avoid performing a configure check whose 62 dnl This ifdef is an optimization, to avoid performing a configure check whose
44 dnl result is not used. But it does not make the test of 63 dnl result is not used. But it does not make the test of
45 dnl GNULIB_STDIO_H_NONBLOCKING or GNULIB_NONBLOCKING redundant. 64 dnl GNULIB_STDIO_H_NONBLOCKING or GNULIB_NONBLOCKING redundant.
@@ -82,6 +101,16 @@ AC_DEFUN_ONCE([gl_STDIO_H],
82 if test $ac_cv_have_decl_fcloseall = no; then 101 if test $ac_cv_have_decl_fcloseall = no; then
83 HAVE_DECL_FCLOSEALL=0 102 HAVE_DECL_FCLOSEALL=0
84 fi 103 fi
104
105 AC_CHECK_DECLS_ONCE([getw])
106 if test $ac_cv_have_decl_getw = no; then
107 HAVE_DECL_GETW=0
108 fi
109
110 AC_CHECK_DECLS_ONCE([putw])
111 if test $ac_cv_have_decl_putw = no; then
112 HAVE_DECL_PUTW=0
113 fi
85]) 114])
86 115
87# gl_STDIO_MODULE_INDICATOR([modulename]) 116# gl_STDIO_MODULE_INDICATOR([modulename])
@@ -178,7 +207,9 @@ AC_DEFUN([gl_STDIO_H_DEFAULTS],
178 HAVE_DECL_FTELLO=1; AC_SUBST([HAVE_DECL_FTELLO]) 207 HAVE_DECL_FTELLO=1; AC_SUBST([HAVE_DECL_FTELLO])
179 HAVE_DECL_GETDELIM=1; AC_SUBST([HAVE_DECL_GETDELIM]) 208 HAVE_DECL_GETDELIM=1; AC_SUBST([HAVE_DECL_GETDELIM])
180 HAVE_DECL_GETLINE=1; AC_SUBST([HAVE_DECL_GETLINE]) 209 HAVE_DECL_GETLINE=1; AC_SUBST([HAVE_DECL_GETLINE])
210 HAVE_DECL_GETW=1; AC_SUBST([HAVE_DECL_GETW])
181 HAVE_DECL_OBSTACK_PRINTF=1; AC_SUBST([HAVE_DECL_OBSTACK_PRINTF]) 211 HAVE_DECL_OBSTACK_PRINTF=1; AC_SUBST([HAVE_DECL_OBSTACK_PRINTF])
212 HAVE_DECL_PUTW=1; AC_SUBST([HAVE_DECL_PUTW])
182 HAVE_DECL_SNPRINTF=1; AC_SUBST([HAVE_DECL_SNPRINTF]) 213 HAVE_DECL_SNPRINTF=1; AC_SUBST([HAVE_DECL_SNPRINTF])
183 HAVE_DECL_VSNPRINTF=1; AC_SUBST([HAVE_DECL_VSNPRINTF]) 214 HAVE_DECL_VSNPRINTF=1; AC_SUBST([HAVE_DECL_VSNPRINTF])
184 HAVE_DPRINTF=1; AC_SUBST([HAVE_DPRINTF]) 215 HAVE_DPRINTF=1; AC_SUBST([HAVE_DPRINTF])
diff --git a/gl/m4/stdlib_h.m4 b/gl/m4/stdlib_h.m4
index e96be22f..a4662f29 100644
--- a/gl/m4/stdlib_h.m4
+++ b/gl/m4/stdlib_h.m4
@@ -1,5 +1,6 @@
1# stdlib_h.m4 serial 66 1# stdlib_h.m4
2dnl Copyright (C) 2007-2023 Free Software Foundation, Inc. 2# serial 77
3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -23,15 +24,58 @@ AC_DEFUN_ONCE([gl_STDLIB_H],
23# include <random.h> 24# include <random.h>
24#endif 25#endif
25 ]], [_Exit aligned_alloc atoll canonicalize_file_name free 26 ]], [_Exit aligned_alloc atoll canonicalize_file_name free
26 getloadavg getsubopt grantpt 27 getloadavg getprogname getsubopt grantpt
27 initstate initstate_r mbtowc mkdtemp mkostemp mkostemps mkstemp mkstemps 28 initstate initstate_r mbstowcs mbtowc mkdtemp mkostemp mkostemps mkstemp
28 posix_memalign posix_openpt ptsname ptsname_r qsort_r 29 mkstemps posix_memalign posix_openpt ptsname ptsname_r qsort_r
29 random random_r reallocarray realpath rpmatch secure_getenv setenv 30 random random_r reallocarray realpath rpmatch secure_getenv setenv
30 setstate setstate_r srandom srandom_r 31 setstate setstate_r srandom srandom_r
31 strtod strtol strtold strtoll strtoul strtoull unlockpt unsetenv]) 32 strtod strtol strtold strtoll strtoul strtoull unlockpt unsetenv])
32 33
33 AC_REQUIRE([AC_C_RESTRICT]) 34 AC_REQUIRE([AC_C_RESTRICT])
34 35
36 dnl Test whether MB_CUR_MAX needs to be overridden.
37 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 AC_REQUIRE([AC_CANONICAL_HOST])
40 AC_REQUIRE([gt_LOCALE_FR_UTF8])
41 AC_CACHE_CHECK([whether MB_CUR_MAX is correct],
42 [gl_cv_macro_MB_CUR_MAX_good],
43 [
44 dnl Initial guess, used when cross-compiling or when no suitable locale
45 dnl is present.
46changequote(,)dnl
47 case "$host_os" in
48 # Guess no on Solaris.
49 solaris*) gl_cv_macro_MB_CUR_MAX_good="guessing no" ;;
50 # Guess yes otherwise.
51 *) gl_cv_macro_MB_CUR_MAX_good="guessing yes" ;;
52 esac
53changequote([,])dnl
54 if test $LOCALE_FR_UTF8 != none; then
55 AC_RUN_IFELSE(
56 [AC_LANG_SOURCE([[
57#include <locale.h>
58#include <stdlib.h>
59int main ()
60{
61 int result = 0;
62 if (setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL)
63 {
64 if (MB_CUR_MAX < 4)
65 result |= 1;
66 }
67 return result;
68}]])],
69 [gl_cv_macro_MB_CUR_MAX_good=yes],
70 [gl_cv_macro_MB_CUR_MAX_good=no],
71 [:])
72 fi
73 ])
74 case "$gl_cv_macro_MB_CUR_MAX_good" in
75 *yes) ;;
76 *) REPLACE_MB_CUR_MAX=1 ;;
77 esac
78
35 AC_CHECK_DECLS_ONCE([ecvt]) 79 AC_CHECK_DECLS_ONCE([ecvt])
36 if test $ac_cv_have_decl_ecvt = no; then 80 if test $ac_cv_have_decl_ecvt = no; then
37 HAVE_DECL_ECVT=0 81 HAVE_DECL_ECVT=0
@@ -73,10 +117,12 @@ AC_DEFUN([gl_STDLIB_H_REQUIRE_DEFAULTS],
73 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CANONICALIZE_FILE_NAME]) 117 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CANONICALIZE_FILE_NAME])
74 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREE_POSIX]) 118 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREE_POSIX])
75 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETLOADAVG]) 119 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETLOADAVG])
120 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETPROGNAME])
76 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETSUBOPT]) 121 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETSUBOPT])
77 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GRANTPT]) 122 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GRANTPT])
78 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MALLOC_GNU]) 123 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MALLOC_GNU])
79 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MALLOC_POSIX]) 124 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MALLOC_POSIX])
125 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSTOWCS])
80 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBTOWC]) 126 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBTOWC])
81 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKDTEMP]) 127 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKDTEMP])
82 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKOSTEMP]) 128 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKOSTEMP])
@@ -89,6 +135,7 @@ AC_DEFUN([gl_STDLIB_H_REQUIRE_DEFAULTS],
89 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PTSNAME_R]) 135 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PTSNAME_R])
90 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PUTENV]) 136 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PUTENV])
91 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_QSORT_R]) 137 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_QSORT_R])
138 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RAND])
92 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RANDOM]) 139 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RANDOM])
93 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RANDOM_R]) 140 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RANDOM_R])
94 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_REALLOCARRAY]) 141 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_REALLOCARRAY])
@@ -99,6 +146,7 @@ AC_DEFUN([gl_STDLIB_H_REQUIRE_DEFAULTS],
99 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SECURE_GETENV]) 146 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SECURE_GETENV])
100 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETENV]) 147 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETENV])
101 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOD]) 148 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOD])
149 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOF])
102 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOL]) 150 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOL])
103 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOLD]) 151 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOLD])
104 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOLL]) 152 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOLL])
@@ -130,6 +178,8 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS],
130 HAVE_DECL_FCVT=1; AC_SUBST([HAVE_DECL_FCVT]) 178 HAVE_DECL_FCVT=1; AC_SUBST([HAVE_DECL_FCVT])
131 HAVE_DECL_GCVT=1; AC_SUBST([HAVE_DECL_GCVT]) 179 HAVE_DECL_GCVT=1; AC_SUBST([HAVE_DECL_GCVT])
132 HAVE_DECL_GETLOADAVG=1; AC_SUBST([HAVE_DECL_GETLOADAVG]) 180 HAVE_DECL_GETLOADAVG=1; AC_SUBST([HAVE_DECL_GETLOADAVG])
181 HAVE_DECL_PROGRAM_INVOCATION_NAME=1; AC_SUBST([HAVE_DECL_PROGRAM_INVOCATION_NAME])
182 HAVE_GETPROGNAME=1; AC_SUBST([HAVE_GETPROGNAME])
133 HAVE_GETSUBOPT=1; AC_SUBST([HAVE_GETSUBOPT]) 183 HAVE_GETSUBOPT=1; AC_SUBST([HAVE_GETSUBOPT])
134 HAVE_GRANTPT=1; AC_SUBST([HAVE_GRANTPT]) 184 HAVE_GRANTPT=1; AC_SUBST([HAVE_GRANTPT])
135 HAVE_INITSTATE=1; AC_SUBST([HAVE_INITSTATE]) 185 HAVE_INITSTATE=1; AC_SUBST([HAVE_INITSTATE])
@@ -157,6 +207,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS],
157 HAVE_SETSTATE=1; AC_SUBST([HAVE_SETSTATE]) 207 HAVE_SETSTATE=1; AC_SUBST([HAVE_SETSTATE])
158 HAVE_DECL_SETSTATE=1; AC_SUBST([HAVE_DECL_SETSTATE]) 208 HAVE_DECL_SETSTATE=1; AC_SUBST([HAVE_DECL_SETSTATE])
159 HAVE_STRTOD=1; AC_SUBST([HAVE_STRTOD]) 209 HAVE_STRTOD=1; AC_SUBST([HAVE_STRTOD])
210 HAVE_STRTOF=1; AC_SUBST([HAVE_STRTOF])
160 HAVE_STRTOL=1; AC_SUBST([HAVE_STRTOL]) 211 HAVE_STRTOL=1; AC_SUBST([HAVE_STRTOL])
161 HAVE_STRTOLD=1; AC_SUBST([HAVE_STRTOLD]) 212 HAVE_STRTOLD=1; AC_SUBST([HAVE_STRTOLD])
162 HAVE_STRTOLL=1; AC_SUBST([HAVE_STRTOLL]) 213 HAVE_STRTOLL=1; AC_SUBST([HAVE_STRTOLL])
@@ -166,21 +217,31 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS],
166 HAVE_SYS_LOADAVG_H=0; AC_SUBST([HAVE_SYS_LOADAVG_H]) 217 HAVE_SYS_LOADAVG_H=0; AC_SUBST([HAVE_SYS_LOADAVG_H])
167 HAVE_UNLOCKPT=1; AC_SUBST([HAVE_UNLOCKPT]) 218 HAVE_UNLOCKPT=1; AC_SUBST([HAVE_UNLOCKPT])
168 HAVE_DECL_UNSETENV=1; AC_SUBST([HAVE_DECL_UNSETENV]) 219 HAVE_DECL_UNSETENV=1; AC_SUBST([HAVE_DECL_UNSETENV])
220 REPLACE__EXIT=0; AC_SUBST([REPLACE__EXIT])
169 REPLACE_ALIGNED_ALLOC=0; AC_SUBST([REPLACE_ALIGNED_ALLOC]) 221 REPLACE_ALIGNED_ALLOC=0; AC_SUBST([REPLACE_ALIGNED_ALLOC])
170 REPLACE_CALLOC_FOR_CALLOC_GNU=0; AC_SUBST([REPLACE_CALLOC_FOR_CALLOC_GNU]) 222 REPLACE_CALLOC_FOR_CALLOC_GNU=0; AC_SUBST([REPLACE_CALLOC_FOR_CALLOC_GNU])
171 REPLACE_CALLOC_FOR_CALLOC_POSIX=0; AC_SUBST([REPLACE_CALLOC_FOR_CALLOC_POSIX]) 223 REPLACE_CALLOC_FOR_CALLOC_POSIX=0; AC_SUBST([REPLACE_CALLOC_FOR_CALLOC_POSIX])
172 REPLACE_CANONICALIZE_FILE_NAME=0; AC_SUBST([REPLACE_CANONICALIZE_FILE_NAME]) 224 REPLACE_CANONICALIZE_FILE_NAME=0; AC_SUBST([REPLACE_CANONICALIZE_FILE_NAME])
173 REPLACE_FREE=0; AC_SUBST([REPLACE_FREE]) 225 REPLACE_FREE=0; AC_SUBST([REPLACE_FREE])
226 REPLACE_GETLOADAVG=0; AC_SUBST([REPLACE_GETLOADAVG])
227 REPLACE_GETPROGNAME=0; AC_SUBST([REPLACE_GETPROGNAME])
228 REPLACE_GETSUBOPT=0; AC_SUBST([REPLACE_GETSUBOPT])
174 REPLACE_INITSTATE=0; AC_SUBST([REPLACE_INITSTATE]) 229 REPLACE_INITSTATE=0; AC_SUBST([REPLACE_INITSTATE])
175 REPLACE_MALLOC_FOR_MALLOC_GNU=0; AC_SUBST([REPLACE_MALLOC_FOR_MALLOC_GNU]) 230 REPLACE_MALLOC_FOR_MALLOC_GNU=0; AC_SUBST([REPLACE_MALLOC_FOR_MALLOC_GNU])
176 REPLACE_MALLOC_FOR_MALLOC_POSIX=0; AC_SUBST([REPLACE_MALLOC_FOR_MALLOC_POSIX]) 231 REPLACE_MALLOC_FOR_MALLOC_POSIX=0; AC_SUBST([REPLACE_MALLOC_FOR_MALLOC_POSIX])
232 REPLACE_MB_CUR_MAX=0; AC_SUBST([REPLACE_MB_CUR_MAX])
233 REPLACE_MBSTOWCS=0; AC_SUBST([REPLACE_MBSTOWCS])
177 REPLACE_MBTOWC=0; AC_SUBST([REPLACE_MBTOWC]) 234 REPLACE_MBTOWC=0; AC_SUBST([REPLACE_MBTOWC])
235 REPLACE_MKOSTEMP=0; AC_SUBST([REPLACE_MKOSTEMP])
236 REPLACE_MKOSTEMPS=0; AC_SUBST([REPLACE_MKOSTEMPS])
178 REPLACE_MKSTEMP=0; AC_SUBST([REPLACE_MKSTEMP]) 237 REPLACE_MKSTEMP=0; AC_SUBST([REPLACE_MKSTEMP])
179 REPLACE_POSIX_MEMALIGN=0; AC_SUBST([REPLACE_POSIX_MEMALIGN]) 238 REPLACE_POSIX_MEMALIGN=0; AC_SUBST([REPLACE_POSIX_MEMALIGN])
239 REPLACE_POSIX_OPENPT=0; AC_SUBST([REPLACE_POSIX_OPENPT])
180 REPLACE_PTSNAME=0; AC_SUBST([REPLACE_PTSNAME]) 240 REPLACE_PTSNAME=0; AC_SUBST([REPLACE_PTSNAME])
181 REPLACE_PTSNAME_R=0; AC_SUBST([REPLACE_PTSNAME_R]) 241 REPLACE_PTSNAME_R=0; AC_SUBST([REPLACE_PTSNAME_R])
182 REPLACE_PUTENV=0; AC_SUBST([REPLACE_PUTENV]) 242 REPLACE_PUTENV=0; AC_SUBST([REPLACE_PUTENV])
183 REPLACE_QSORT_R=0; AC_SUBST([REPLACE_QSORT_R]) 243 REPLACE_QSORT_R=0; AC_SUBST([REPLACE_QSORT_R])
244 REPLACE_RAND=0; AC_SUBST([REPLACE_RAND])
184 REPLACE_RANDOM=0; AC_SUBST([REPLACE_RANDOM]) 245 REPLACE_RANDOM=0; AC_SUBST([REPLACE_RANDOM])
185 REPLACE_RANDOM_R=0; AC_SUBST([REPLACE_RANDOM_R]) 246 REPLACE_RANDOM_R=0; AC_SUBST([REPLACE_RANDOM_R])
186 REPLACE_REALLOC_FOR_REALLOC_GNU=0; AC_SUBST([REPLACE_REALLOC_FOR_REALLOC_GNU]) 247 REPLACE_REALLOC_FOR_REALLOC_GNU=0; AC_SUBST([REPLACE_REALLOC_FOR_REALLOC_GNU])
@@ -190,6 +251,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS],
190 REPLACE_SETENV=0; AC_SUBST([REPLACE_SETENV]) 251 REPLACE_SETENV=0; AC_SUBST([REPLACE_SETENV])
191 REPLACE_SETSTATE=0; AC_SUBST([REPLACE_SETSTATE]) 252 REPLACE_SETSTATE=0; AC_SUBST([REPLACE_SETSTATE])
192 REPLACE_STRTOD=0; AC_SUBST([REPLACE_STRTOD]) 253 REPLACE_STRTOD=0; AC_SUBST([REPLACE_STRTOD])
254 REPLACE_STRTOF=0; AC_SUBST([REPLACE_STRTOF])
193 REPLACE_STRTOL=0; AC_SUBST([REPLACE_STRTOL]) 255 REPLACE_STRTOL=0; AC_SUBST([REPLACE_STRTOL])
194 REPLACE_STRTOLD=0; AC_SUBST([REPLACE_STRTOLD]) 256 REPLACE_STRTOLD=0; AC_SUBST([REPLACE_STRTOLD])
195 REPLACE_STRTOLL=0; AC_SUBST([REPLACE_STRTOLL]) 257 REPLACE_STRTOLL=0; AC_SUBST([REPLACE_STRTOLL])
diff --git a/gl/m4/strcase.m4 b/gl/m4/strcase.m4
index 3cf740d2..63021733 100644
--- a/gl/m4/strcase.m4
+++ b/gl/m4/strcase.m4
@@ -1,5 +1,6 @@
1# strcase.m4 serial 12 1# strcase.m4
2dnl Copyright (C) 2002, 2005-2023 Free Software Foundation, Inc. 2# serial 12
3dnl Copyright (C) 2002, 2005-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/strcasestr.m4 b/gl/m4/strcasestr.m4
index 971e0b23..d2548716 100644
--- a/gl/m4/strcasestr.m4
+++ b/gl/m4/strcasestr.m4
@@ -1,5 +1,6 @@
1# strcasestr.m4 serial 28 1# strcasestr.m4
2dnl Copyright (C) 2005, 2007-2023 Free Software Foundation, Inc. 2# serial 28
3dnl Copyright (C) 2005, 2007-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/strerror.m4 b/gl/m4/strerror.m4
index 8879eb08..0272c6f4 100644
--- a/gl/m4/strerror.m4
+++ b/gl/m4/strerror.m4
@@ -1,5 +1,6 @@
1# strerror.m4 serial 23 1# strerror.m4
2dnl Copyright (C) 2002, 2007-2023 Free Software Foundation, Inc. 2# serial 25
3dnl Copyright (C) 2002, 2007-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -24,12 +25,12 @@ AC_DEFUN([gl_FUNC_STRERROR],
24 [gl_cv_func_working_strerror=yes], 25 [gl_cv_func_working_strerror=yes],
25 [gl_cv_func_working_strerror=no], 26 [gl_cv_func_working_strerror=no],
26 [case "$host_os" in 27 [case "$host_os" in
27 # Guess yes on glibc systems. 28 # Guess yes on glibc systems.
28 *-gnu* | gnu*) gl_cv_func_working_strerror="guessing yes" ;; 29 *-gnu* | gnu*) gl_cv_func_working_strerror="guessing yes" ;;
29 # Guess yes on musl systems. 30 # Guess yes on musl systems.
30 *-musl*) gl_cv_func_working_strerror="guessing yes" ;; 31 *-musl* | midipix*) gl_cv_func_working_strerror="guessing yes" ;;
31 # If we don't know, obey --enable-cross-guesses. 32 # If we don't know, obey --enable-cross-guesses.
32 *) gl_cv_func_working_strerror="$gl_cross_guess_normal" ;; 33 *) gl_cv_func_working_strerror="$gl_cross_guess_normal" ;;
33 esac 34 esac
34 ]) 35 ])
35 ]) 36 ])
@@ -80,14 +81,14 @@ AC_DEFUN([gl_FUNC_STRERROR_0],
80 [gl_cv_func_strerror_0_works=yes], 81 [gl_cv_func_strerror_0_works=yes],
81 [gl_cv_func_strerror_0_works=no], 82 [gl_cv_func_strerror_0_works=no],
82 [case "$host_os" in 83 [case "$host_os" in
83 # Guess yes on glibc systems. 84 # Guess yes on glibc systems.
84 *-gnu* | gnu*) gl_cv_func_strerror_0_works="guessing yes" ;; 85 *-gnu* | gnu*) gl_cv_func_strerror_0_works="guessing yes" ;;
85 # Guess yes on musl systems. 86 # Guess yes on musl systems.
86 *-musl*) gl_cv_func_strerror_0_works="guessing yes" ;; 87 *-musl* | midipix*) gl_cv_func_strerror_0_works="guessing yes" ;;
87 # Guess yes on native Windows. 88 # Guess yes on native Windows.
88 mingw*) gl_cv_func_strerror_0_works="guessing yes" ;; 89 mingw* | windows*) gl_cv_func_strerror_0_works="guessing yes" ;;
89 # If we don't know, obey --enable-cross-guesses. 90 # If we don't know, obey --enable-cross-guesses.
90 *) gl_cv_func_strerror_0_works="$gl_cross_guess_normal" ;; 91 *) gl_cv_func_strerror_0_works="$gl_cross_guess_normal" ;;
91 esac 92 esac
92 ]) 93 ])
93 ]) 94 ])
diff --git a/gl/m4/string_h.m4 b/gl/m4/string_h.m4
index 5da3cc25..f31264ae 100644
--- a/gl/m4/string_h.m4
+++ b/gl/m4/string_h.m4
@@ -1,11 +1,11 @@
1# Configure a GNU-like replacement for <string.h>. 1# string_h.m4
2 2# serial 39
3# Copyright (C) 2007-2023 Free Software Foundation, Inc. 3dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
4# This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
5# gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
6# with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
7 7
8# serial 35 8# Configure a GNU-like replacement for <string.h>.
9 9
10# Written by Paul Eggert. 10# Written by Paul Eggert.
11 11
@@ -131,6 +131,9 @@ AC_DEFUN([gl_STRING_H_DEFAULTS],
131 REPLACE_FFSLL=0; AC_SUBST([REPLACE_FFSLL]) 131 REPLACE_FFSLL=0; AC_SUBST([REPLACE_FFSLL])
132 REPLACE_MEMCHR=0; AC_SUBST([REPLACE_MEMCHR]) 132 REPLACE_MEMCHR=0; AC_SUBST([REPLACE_MEMCHR])
133 REPLACE_MEMMEM=0; AC_SUBST([REPLACE_MEMMEM]) 133 REPLACE_MEMMEM=0; AC_SUBST([REPLACE_MEMMEM])
134 REPLACE_MEMPCPY=0; AC_SUBST([REPLACE_MEMPCPY])
135 REPLACE_MEMSET_EXPLICIT=0; AC_SUBST([REPLACE_MEMSET_EXPLICIT])
136 REPLACE_STPCPY=0; AC_SUBST([REPLACE_STPCPY])
134 REPLACE_STPNCPY=0; AC_SUBST([REPLACE_STPNCPY]) 137 REPLACE_STPNCPY=0; AC_SUBST([REPLACE_STPNCPY])
135 REPLACE_STRCHRNUL=0; AC_SUBST([REPLACE_STRCHRNUL]) 138 REPLACE_STRCHRNUL=0; AC_SUBST([REPLACE_STRCHRNUL])
136 REPLACE_STRDUP=0; AC_SUBST([REPLACE_STRDUP]) 139 REPLACE_STRDUP=0; AC_SUBST([REPLACE_STRDUP])
@@ -144,5 +147,6 @@ AC_DEFUN([gl_STRING_H_DEFAULTS],
144 REPLACE_STRERROR_R=0; AC_SUBST([REPLACE_STRERROR_R]) 147 REPLACE_STRERROR_R=0; AC_SUBST([REPLACE_STRERROR_R])
145 REPLACE_STRERRORNAME_NP=0; AC_SUBST([REPLACE_STRERRORNAME_NP]) 148 REPLACE_STRERRORNAME_NP=0; AC_SUBST([REPLACE_STRERRORNAME_NP])
146 REPLACE_STRSIGNAL=0; AC_SUBST([REPLACE_STRSIGNAL]) 149 REPLACE_STRSIGNAL=0; AC_SUBST([REPLACE_STRSIGNAL])
150 REPLACE_STRVERSCMP=0; AC_SUBST([REPLACE_STRVERSCMP])
147 UNDEFINE_STRTOK_R=0; AC_SUBST([UNDEFINE_STRTOK_R]) 151 UNDEFINE_STRTOK_R=0; AC_SUBST([UNDEFINE_STRTOK_R])
148]) 152])
diff --git a/gl/m4/strings_h.m4 b/gl/m4/strings_h.m4
index 4c41221b..aaafb559 100644
--- a/gl/m4/strings_h.m4
+++ b/gl/m4/strings_h.m4
@@ -1,10 +1,11 @@
1# Configure a replacement for <strings.h>. 1# strings_h.m4
2# serial 9 2# serial 9
3dnl Copyright (C) 2007, 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.
3 7
4# Copyright (C) 2007, 2009-2023 Free Software Foundation, Inc. 8# Configure a replacement for <strings.h>.
5# This file is free software; the Free Software Foundation
6# gives unlimited permission to copy and/or distribute it,
7# with or without modifications, as long as this notice is preserved.
8 9
9AC_DEFUN_ONCE([gl_STRINGS_H], 10AC_DEFUN_ONCE([gl_STRINGS_H],
10[ 11[
diff --git a/gl/m4/strsep.m4 b/gl/m4/strsep.m4
index e0da09a3..cfde87a5 100644
--- a/gl/m4/strsep.m4
+++ b/gl/m4/strsep.m4
@@ -1,5 +1,6 @@
1# strsep.m4 serial 11 1# strsep.m4
2dnl Copyright (C) 2002-2004, 2007, 2009-2023 Free Software Foundation, Inc. 2# serial 11
3dnl Copyright (C) 2002-2004, 2007, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/strstr.m4 b/gl/m4/strstr.m4
index 7de203a7..957ed2e3 100644
--- a/gl/m4/strstr.m4
+++ b/gl/m4/strstr.m4
@@ -1,5 +1,6 @@
1# strstr.m4 serial 24 1# strstr.m4
2dnl Copyright (C) 2008-2023 Free Software Foundation, Inc. 2# serial 24
3dnl Copyright (C) 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/sys_socket_h.m4 b/gl/m4/sys_socket_h.m4
index 98a10416..3bf3cb47 100644
--- a/gl/m4/sys_socket_h.m4
+++ b/gl/m4/sys_socket_h.m4
@@ -1,5 +1,6 @@
1# sys_socket_h.m4 serial 29 1# sys_socket_h.m4
2dnl Copyright (C) 2005-2023 Free Software Foundation, Inc. 2# serial 29
3dnl Copyright (C) 2005-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/sys_stat_h.m4 b/gl/m4/sys_stat_h.m4
index ca57398a..3cc50ce6 100644
--- a/gl/m4/sys_stat_h.m4
+++ b/gl/m4/sys_stat_h.m4
@@ -1,5 +1,6 @@
1# sys_stat_h.m4 serial 42 -*- Autoconf -*- 1# sys_stat_h.m4
2dnl Copyright (C) 2006-2023 Free Software Foundation, Inc. 2# serial 42 -*- Autoconf -*-
3dnl Copyright (C) 2006-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/sys_types_h.m4 b/gl/m4/sys_types_h.m4
index 627671fb..00d2437b 100644
--- a/gl/m4/sys_types_h.m4
+++ b/gl/m4/sys_types_h.m4
@@ -1,5 +1,6 @@
1# sys_types_h.m4 serial 13 1# sys_types_h.m4
2dnl Copyright (C) 2011-2023 Free Software Foundation, Inc. 2# serial 13
3dnl Copyright (C) 2011-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/sys_uio_h.m4 b/gl/m4/sys_uio_h.m4
index 93a65d26..a471c720 100644
--- a/gl/m4/sys_uio_h.m4
+++ b/gl/m4/sys_uio_h.m4
@@ -1,5 +1,6 @@
1# sys_uio_h.m4 serial 3 1# sys_uio_h.m4
2dnl Copyright (C) 2011-2023 Free Software Foundation, Inc. 2# serial 3
3dnl Copyright (C) 2011-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/threadlib.m4 b/gl/m4/threadlib.m4
index b536b047..f5e81479 100644
--- a/gl/m4/threadlib.m4
+++ b/gl/m4/threadlib.m4
@@ -1,5 +1,6 @@
1# threadlib.m4 serial 32a 1# threadlib.m4
2dnl Copyright (C) 2005-2023 Free Software Foundation, Inc. 2# serial 42
3dnl Copyright (C) 2005-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -85,10 +86,11 @@ AC_DEFUN([gl_WEAK_SYMBOLS],
85 AC_CACHE_CHECK([whether imported symbols can be declared weak], 86 AC_CACHE_CHECK([whether imported symbols can be declared weak],
86 [gl_cv_have_weak], 87 [gl_cv_have_weak],
87 [case "$host_os" in 88 [case "$host_os" in
88 cygwin*) 89 cygwin* | mingw* | windows*)
89 dnl On Cygwin 3.2.0 with gcc 10.2, the test below would succeed, but 90 dnl On Cygwin 3.2.0 with gcc 10.2, and likewise on mingw 10.0.0 with
90 dnl programs that use pthread_in_use() with weak symbol references 91 dnl gcc 11.3, the test below would succeed, but programs that use
91 dnl crash miserably at runtime. 92 dnl pthread_in_use() with weak symbol references crash miserably at
93 dnl runtime.
92 gl_cv_have_weak="guessing no" 94 gl_cv_have_weak="guessing no"
93 ;; 95 ;;
94 *) 96 *)
@@ -174,7 +176,7 @@ dnl Sets the variable LIBPMULTITHREAD, for programs that really need
174dnl multithread functionality. The difference between LIBPTHREAD and 176dnl multithread functionality. The difference between LIBPTHREAD and
175dnl LIBPMULTITHREAD is that on platforms supporting weak symbols, typically 177dnl LIBPMULTITHREAD is that on platforms supporting weak symbols, typically
176dnl LIBPTHREAD is empty whereas LIBPMULTITHREAD is not. 178dnl LIBPTHREAD is empty whereas LIBPMULTITHREAD is not.
177dnl Sets the variable LIB_SCHED_YIELD to the linker options needed to use the 179dnl Sets the variable SCHED_YIELD_LIB to the linker options needed to use the
178dnl sched_yield() function. 180dnl sched_yield() function.
179dnl Adds to CPPFLAGS the flag -D_REENTRANT or -D_THREAD_SAFE if needed for 181dnl Adds to CPPFLAGS the flag -D_REENTRANT or -D_THREAD_SAFE if needed for
180dnl multithread-safe programs. 182dnl multithread-safe programs.
@@ -205,7 +207,7 @@ AC_DEFUN([gl_PTHREADLIB_BODY],
205 # If -pthread works, prefer it to -lpthread, since Ubuntu 14.04 207 # If -pthread works, prefer it to -lpthread, since Ubuntu 14.04
206 # needs -pthread for some reason. See: 208 # needs -pthread for some reason. See:
207 # https://lists.gnu.org/r/bug-gnulib/2014-09/msg00023.html 209 # https://lists.gnu.org/r/bug-gnulib/2014-09/msg00023.html
208 save_LIBS=$LIBS 210 saved_LIBS="$LIBS"
209 for gl_pthread in '' '-pthread'; do 211 for gl_pthread in '' '-pthread'; do
210 LIBS="$LIBS $gl_pthread" 212 LIBS="$LIBS $gl_pthread"
211 AC_LINK_IFELSE( 213 AC_LINK_IFELSE(
@@ -219,7 +221,7 @@ AC_DEFUN([gl_PTHREADLIB_BODY],
219 [gl_pthread_api=yes 221 [gl_pthread_api=yes
220 LIBPTHREAD=$gl_pthread 222 LIBPTHREAD=$gl_pthread
221 LIBPMULTITHREAD=$gl_pthread]) 223 LIBPMULTITHREAD=$gl_pthread])
222 LIBS=$save_LIBS 224 LIBS="$saved_LIBS"
223 test $gl_pthread_api = yes && break 225 test $gl_pthread_api = yes && break
224 done 226 done
225 echo "$as_me:__oline__: gl_pthread_api=$gl_pthread_api" >&AS_MESSAGE_LOG_FD 227 echo "$as_me:__oline__: gl_pthread_api=$gl_pthread_api" >&AS_MESSAGE_LOG_FD
@@ -268,6 +270,15 @@ changequote([,])dnl
268 [Define if the pthread_in_use() detection is hard.]) 270 [Define if the pthread_in_use() detection is hard.])
269 esac 271 esac
270 fi 272 fi
273 ],
274 [dnl This is needed on FreeBSD 5.2.1.
275 AC_CHECK_LIB([thr], [pthread_kill],
276 [if test $gl_pthread_in_glibc = yes; then
277 LIBPMULTITHREAD=
278 else
279 LIBPMULTITHREAD=-lthr
280 fi
281 ])
271 ]) 282 ])
272 elif test $gl_pthread_api != yes; then 283 elif test $gl_pthread_api != yes; then
273 # Some library is needed. Try libpthread and libc_r. 284 # Some library is needed. Try libpthread and libc_r.
@@ -299,13 +310,16 @@ changequote([,])dnl
299 [AC_LANG_PROGRAM( 310 [AC_LANG_PROGRAM(
300 [[#include <sched.h>]], 311 [[#include <sched.h>]],
301 [[sched_yield ();]])], 312 [[sched_yield ();]])],
302 [LIB_SCHED_YIELD= 313 [SCHED_YIELD_LIB=
303 ], 314 ],
304 [dnl Solaris 7...10 has sched_yield in librt, not in libpthread or libc. 315 [dnl Solaris 7...10 has sched_yield in librt, not in libpthread or libc.
305 AC_CHECK_LIB([rt], [sched_yield], [LIB_SCHED_YIELD=-lrt], 316 AC_CHECK_LIB([rt], [sched_yield], [SCHED_YIELD_LIB=-lrt],
306 [dnl Solaris 2.5.1, 2.6 has sched_yield in libposix4, not librt. 317 [dnl Solaris 2.5.1, 2.6 has sched_yield in libposix4, not librt.
307 AC_CHECK_LIB([posix4], [sched_yield], [LIB_SCHED_YIELD=-lposix4])]) 318 AC_CHECK_LIB([posix4], [sched_yield], [SCHED_YIELD_LIB=-lposix4])])
308 ]) 319 ])
320 AC_SUBST([SCHED_YIELD_LIB])
321 dnl For backward compatibility.
322 LIB_SCHED_YIELD="$SCHED_YIELD_LIB"
309 AC_SUBST([LIB_SCHED_YIELD]) 323 AC_SUBST([LIB_SCHED_YIELD])
310 324
311 gl_pthreadlib_body_done=done 325 gl_pthreadlib_body_done=done
@@ -340,7 +354,7 @@ AC_DEFUN([gl_STDTHREADLIB_BODY],
340 AC_CHECK_HEADERS_ONCE([threads.h]) 354 AC_CHECK_HEADERS_ONCE([threads.h])
341 355
342 case "$host_os" in 356 case "$host_os" in
343 mingw*) 357 mingw* | windows*)
344 LIBSTDTHREAD= 358 LIBSTDTHREAD=
345 ;; 359 ;;
346 *) 360 *)
@@ -351,7 +365,7 @@ AC_DEFUN([gl_STDTHREADLIB_BODY],
351 dnl on libpthread (for the symbol 'pthread_mutexattr_gettype'). 365 dnl on libpthread (for the symbol 'pthread_mutexattr_gettype').
352 dnl glibc >= 2.34, AIX >= 7.1, and Solaris >= 11.4 have thrd_create in 366 dnl glibc >= 2.34, AIX >= 7.1, and Solaris >= 11.4 have thrd_create in
353 dnl libc. 367 dnl libc.
354 AC_CHECK_FUNCS([thrd_create]) 368 gl_CHECK_FUNCS_ANDROID([thrd_create], [[#include <threads.h>]])
355 if test $ac_cv_func_thrd_create = yes; then 369 if test $ac_cv_func_thrd_create = yes; then
356 LIBSTDTHREAD= 370 LIBSTDTHREAD=
357 else 371 else
@@ -364,7 +378,7 @@ AC_DEFUN([gl_STDTHREADLIB_BODY],
364 fi 378 fi
365 else 379 else
366 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.
367 LIBSTDTHREAD="$LIBPMULTITHREAD $LIB_SCHED_YIELD" 381 LIBSTDTHREAD="$LIBPMULTITHREAD $SCHED_YIELD_LIB"
368 fi 382 fi
369 ;; 383 ;;
370 esac 384 esac
@@ -435,10 +449,12 @@ AC_DEFUN([gl_THREADLIB_EARLY_BODY],
435 m4_ifdef([gl_THREADLIB_DEFAULT_NO], 449 m4_ifdef([gl_THREADLIB_DEFAULT_NO],
436 [m4_divert_text([DEFAULTS], [gl_use_threads_default=no])], 450 [m4_divert_text([DEFAULTS], [gl_use_threads_default=no])],
437 [m4_divert_text([DEFAULTS], [gl_use_threads_default=])]) 451 [m4_divert_text([DEFAULTS], [gl_use_threads_default=])])
438 m4_divert_text([DEFAULTS], [gl_use_winpthreads_default=]) 452 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.
454 m4_divert_text([DEFAULTS], [gl_use_winpthreads_default=no])
439 AC_ARG_ENABLE([threads], 455 AC_ARG_ENABLE([threads],
440AS_HELP_STRING([--enable-threads={isoc|posix|isoc+posix|windows}], [specify multithreading API])m4_ifdef([gl_THREADLIB_DEFAULT_NO], [], [ 456AS_HELP_STRING([[--enable-threads={isoc|posix|isoc+posix|windows}]], [specify multithreading API])m4_ifdef([gl_THREADLIB_DEFAULT_NO], [], [
441AS_HELP_STRING([--disable-threads], [build without multithread safety])]), 457AS_HELP_STRING([[--disable-threads]], [build without multithread safety])]),
442 [gl_use_threads=$enableval], 458 [gl_use_threads=$enableval],
443 [if test -n "$gl_use_threads_default"; then 459 [if test -n "$gl_use_threads_default"; then
444 gl_use_threads="$gl_use_threads_default" 460 gl_use_threads="$gl_use_threads_default"
@@ -459,7 +475,7 @@ changequote(,)dnl
459 esac 475 esac
460 ;; 476 ;;
461 dnl Obey gl_AVOID_WINPTHREAD on mingw. 477 dnl Obey gl_AVOID_WINPTHREAD on mingw.
462 mingw*) 478 mingw* | windows*)
463 case "$gl_use_winpthreads_default" in 479 case "$gl_use_winpthreads_default" in
464 yes) gl_use_threads=posix ;; 480 yes) gl_use_threads=posix ;;
465 no) gl_use_threads=windows ;; 481 no) gl_use_threads=windows ;;
@@ -558,7 +574,7 @@ AC_DEFUN([gl_THREADLIB_BODY],
558 case "$gl_use_threads" in 574 case "$gl_use_threads" in
559 yes | windows | win32) # The 'win32' is for backward compatibility. 575 yes | windows | win32) # The 'win32' is for backward compatibility.
560 if { case "$host_os" in 576 if { case "$host_os" in
561 mingw*) true;; 577 mingw* | windows*) true;;
562 *) false;; 578 *) false;;
563 esac 579 esac
564 }; then 580 }; then
@@ -569,6 +585,10 @@ AC_DEFUN([gl_THREADLIB_BODY],
569 ;; 585 ;;
570 esac 586 esac
571 fi 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.])
572 fi 592 fi
573 AC_MSG_CHECKING([for multithread API to use]) 593 AC_MSG_CHECKING([for multithread API to use])
574 AC_MSG_RESULT([$gl_threads_api]) 594 AC_MSG_RESULT([$gl_threads_api])
@@ -601,7 +621,8 @@ dnl -------------------
601dnl Sets the gl_THREADLIB default so that on mingw, a dependency to the 621dnl Sets the gl_THREADLIB default so that on mingw, a dependency to the
602dnl libwinpthread DLL (mingw-w64 winpthreads library) is avoided. 622dnl libwinpthread DLL (mingw-w64 winpthreads library) is avoided.
603dnl The user can still override it at installation time, by using the 623dnl The user can still override it at installation time, by using the
604dnl configure option '--enable-threads'. 624dnl configure option '--enable-threads=posix'.
625dnl As of 2023, this is now the default.
605 626
606AC_DEFUN([gl_AVOID_WINPTHREAD], [ 627AC_DEFUN([gl_AVOID_WINPTHREAD], [
607 m4_divert_text([INIT_PREPARE], [gl_use_winpthreads_default=no]) 628 m4_divert_text([INIT_PREPARE], [gl_use_winpthreads_default=no])
diff --git a/gl/m4/time_h.m4 b/gl/m4/time_h.m4
index f6bf3a4f..d2f3c970 100644
--- a/gl/m4/time_h.m4
+++ b/gl/m4/time_h.m4
@@ -1,12 +1,11 @@
1# Configure a more-standard replacement for <time.h>. 1# time_h.m4
2 2# serial 25
3# Copyright (C) 2000-2001, 2003-2007, 2009-2023 Free Software Foundation, Inc. 3dnl Copyright (C) 2000-2001, 2003-2007, 2009-2024 Free Software Foundation, Inc.
4 4dnl This file is free software; the Free Software Foundation
5# serial 20 5dnl gives unlimited permission to copy and/or distribute it,
6dnl with or without modifications, as long as this notice is preserved.
6 7
7# This file is free software; the Free Software Foundation 8# Configure a more-standard replacement for <time.h>.
8# gives unlimited permission to copy and/or distribute it,
9# with or without modifications, as long as this notice is preserved.
10 9
11# Written by Paul Eggert and Jim Meyering. 10# Written by Paul Eggert and Jim Meyering.
12 11
@@ -23,7 +22,10 @@ AC_DEFUN_ONCE([gl_TIME_H],
23 dnl corresponding gnulib module is not in use. 22 dnl corresponding gnulib module is not in use.
24 gl_WARN_ON_USE_PREPARE([[ 23 gl_WARN_ON_USE_PREPARE([[
25#include <time.h> 24#include <time.h>
26 ]], [asctime_r ctime_r]) 25 ]], [
26 asctime asctime_r ctime ctime_r gmtime_r localtime localtime_r mktime
27 nanosleep strftime strptime time timegm timespec_get timespec_getres tzset
28 ])
27 29
28 AC_REQUIRE([AC_C_RESTRICT]) 30 AC_REQUIRE([AC_C_RESTRICT])
29 31
@@ -137,6 +139,7 @@ AC_DEFUN([gl_TIME_H_REQUIRE_DEFAULTS],
137 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_NANOSLEEP]) 139 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_NANOSLEEP])
138 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRFTIME]) 140 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRFTIME])
139 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRPTIME]) 141 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRPTIME])
142 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIME])
140 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIMEGM]) 143 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIMEGM])
141 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIMESPEC_GET]) 144 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIMESPEC_GET])
142 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIMESPEC_GETRES]) 145 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIMESPEC_GETRES])
@@ -161,23 +164,16 @@ AC_DEFUN([gl_TIME_H_DEFAULTS],
161 HAVE_TIMESPEC_GETRES=1; AC_SUBST([HAVE_TIMESPEC_GETRES]) 164 HAVE_TIMESPEC_GETRES=1; AC_SUBST([HAVE_TIMESPEC_GETRES])
162 dnl Even GNU libc does not have timezone_t yet. 165 dnl Even GNU libc does not have timezone_t yet.
163 HAVE_TIMEZONE_T=0; AC_SUBST([HAVE_TIMEZONE_T]) 166 HAVE_TIMEZONE_T=0; AC_SUBST([HAVE_TIMEZONE_T])
164 dnl If another module says to replace or to not replace, do that. 167 REPLACE_CTIME=0; AC_SUBST([REPLACE_CTIME])
165 dnl Otherwise, replace only if someone compiles with -DGNULIB_PORTCHECK;
166 dnl this lets maintainers check for portability.
167 REPLACE_CTIME=GNULIB_PORTCHECK; AC_SUBST([REPLACE_CTIME])
168 REPLACE_LOCALTIME_R=GNULIB_PORTCHECK; AC_SUBST([REPLACE_LOCALTIME_R])
169 REPLACE_MKTIME=GNULIB_PORTCHECK; AC_SUBST([REPLACE_MKTIME])
170 REPLACE_NANOSLEEP=GNULIB_PORTCHECK; AC_SUBST([REPLACE_NANOSLEEP])
171 REPLACE_STRFTIME=GNULIB_PORTCHECK; AC_SUBST([REPLACE_STRFTIME])
172 REPLACE_TIMEGM=GNULIB_PORTCHECK; AC_SUBST([REPLACE_TIMEGM])
173 REPLACE_TZSET=GNULIB_PORTCHECK; AC_SUBST([REPLACE_TZSET])
174
175 dnl Hack so that the time module doesn't depend on the sys_time module.
176 dnl First, default GNULIB_GETTIMEOFDAY to 0 if sys_time is absent.
177 : ${GNULIB_GETTIMEOFDAY=0}; AC_SUBST([GNULIB_GETTIMEOFDAY])
178 dnl Second, it's OK to not use GNULIB_PORTCHECK for REPLACE_GMTIME
179 dnl and REPLACE_LOCALTIME, as portability to Solaris 2.6 and earlier
180 dnl is no longer a big deal.
181 REPLACE_GMTIME=0; AC_SUBST([REPLACE_GMTIME]) 168 REPLACE_GMTIME=0; AC_SUBST([REPLACE_GMTIME])
182 REPLACE_LOCALTIME=0; AC_SUBST([REPLACE_LOCALTIME]) 169 REPLACE_LOCALTIME=0; AC_SUBST([REPLACE_LOCALTIME])
170 REPLACE_LOCALTIME_R=0; AC_SUBST([REPLACE_LOCALTIME_R])
171 REPLACE_MKTIME=0; AC_SUBST([REPLACE_MKTIME])
172 REPLACE_NANOSLEEP=0; AC_SUBST([REPLACE_NANOSLEEP])
173 REPLACE_STRFTIME=0; AC_SUBST([REPLACE_STRFTIME])
174 REPLACE_TIME=0; AC_SUBST([REPLACE_TIME])
175 REPLACE_TIMEGM=0; AC_SUBST([REPLACE_TIMEGM])
176 REPLACE_TIMESPEC_GET=0; AC_SUBST([REPLACE_TIMESPEC_GET])
177 REPLACE_TIMESPEC_GETRES=0; AC_SUBST([REPLACE_TIMESPEC_GETRES])
178 REPLACE_TZSET=0; AC_SUBST([REPLACE_TZSET])
183]) 179])
diff --git a/gl/m4/time_r.m4 b/gl/m4/time_r.m4
index adce438a..3675390e 100644
--- a/gl/m4/time_r.m4
+++ b/gl/m4/time_r.m4
@@ -1,10 +1,12 @@
1dnl Reentrant time functions: localtime_r, gmtime_r. 1# time_r.m4
2 2# serial 1
3dnl Copyright (C) 2003, 2006-2023 Free Software Foundation, Inc. 3dnl Copyright (C) 2003, 2006-2024 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 7
8dnl Reentrant time functions: localtime_r, gmtime_r.
9
8dnl Written by Paul Eggert. 10dnl Written by Paul Eggert.
9 11
10AC_DEFUN([gl_TIME_R], 12AC_DEFUN([gl_TIME_R],
@@ -57,9 +59,7 @@ AC_DEFUN([gl_TIME_R],
57 [gl_cv_time_r_posix=yes], 59 [gl_cv_time_r_posix=yes],
58 [gl_cv_time_r_posix=no]) 60 [gl_cv_time_r_posix=no])
59 ]) 61 ])
60 if test $gl_cv_time_r_posix = yes; then 62 if test $gl_cv_time_r_posix != yes; then
61 REPLACE_LOCALTIME_R=0
62 else
63 REPLACE_LOCALTIME_R=1 63 REPLACE_LOCALTIME_R=1
64 fi 64 fi
65 else 65 else
diff --git a/gl/m4/timegm.m4 b/gl/m4/timegm.m4
index 6079f1a3..c1ff2677 100644
--- a/gl/m4/timegm.m4
+++ b/gl/m4/timegm.m4
@@ -1,5 +1,6 @@
1# timegm.m4 serial 13 1# timegm.m4
2dnl Copyright (C) 2003, 2007, 2009-2023 Free Software Foundation, Inc. 2# serial 16
3dnl Copyright (C) 2003, 2007, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -8,8 +9,7 @@ AC_DEFUN([gl_FUNC_TIMEGM],
8[ 9[
9 AC_REQUIRE([gl_TIME_H_DEFAULTS]) 10 AC_REQUIRE([gl_TIME_H_DEFAULTS])
10 AC_REQUIRE([gl_FUNC_MKTIME_WORKS]) 11 AC_REQUIRE([gl_FUNC_MKTIME_WORKS])
11 REPLACE_TIMEGM=0 12 gl_CHECK_FUNCS_ANDROID([timegm], [[#include <time.h>]])
12 AC_CHECK_FUNCS_ONCE([timegm])
13 if test $ac_cv_func_timegm = yes; then 13 if test $ac_cv_func_timegm = yes; then
14 if test "$gl_cv_func_working_mktime" != yes; then 14 if test "$gl_cv_func_working_mktime" != yes; then
15 # Assume that timegm is buggy if mktime is. 15 # Assume that timegm is buggy if mktime is.
@@ -17,6 +17,9 @@ AC_DEFUN([gl_FUNC_TIMEGM],
17 fi 17 fi
18 else 18 else
19 HAVE_TIMEGM=0 19 HAVE_TIMEGM=0
20 case "$gl_cv_onwards_func_timegm" in
21 future*) REPLACE_TIMEGM=1 ;;
22 esac
20 fi 23 fi
21]) 24])
22 25
diff --git a/gl/m4/ungetc.m4 b/gl/m4/ungetc.m4
index 8977a346..42f7ec32 100644
--- a/gl/m4/ungetc.m4
+++ b/gl/m4/ungetc.m4
@@ -1,5 +1,6 @@
1# ungetc.m4 serial 10 1# ungetc.m4
2dnl Copyright (C) 2009-2023 Free Software Foundation, Inc. 2# serial 12
3dnl Copyright (C) 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -42,16 +43,16 @@ AC_DEFUN_ONCE([gl_FUNC_UNGETC_WORKS],
42 ]])], 43 ]])],
43 [gl_cv_func_ungetc_works=yes], [gl_cv_func_ungetc_works=no], 44 [gl_cv_func_ungetc_works=yes], [gl_cv_func_ungetc_works=no],
44 [case "$host_os" in 45 [case "$host_os" in
45 # Guess yes on glibc systems. 46 # Guess yes on glibc systems.
46 *-gnu* | gnu*) gl_cv_func_ungetc_works="guessing yes" ;; 47 *-gnu* | gnu*) gl_cv_func_ungetc_works="guessing yes" ;;
47 # Guess yes on musl systems. 48 # Guess yes on musl systems.
48 *-musl*) gl_cv_func_ungetc_works="guessing yes" ;; 49 *-musl* | midipix*) gl_cv_func_ungetc_works="guessing yes" ;;
49 # Guess yes on bionic systems. 50 # Guess yes on bionic systems.
50 *-android*) gl_cv_func_ungetc_works="guessing yes" ;; 51 *-android*) gl_cv_func_ungetc_works="guessing yes" ;;
51 # Guess yes on native Windows. 52 # Guess yes on native Windows.
52 mingw*) gl_cv_func_ungetc_works="guessing yes" ;; 53 mingw* | windows*) gl_cv_func_ungetc_works="guessing yes" ;;
53 # If we don't know, obey --enable-cross-guesses. 54 # If we don't know, obey --enable-cross-guesses.
54 *) gl_cv_func_ungetc_works="$gl_cross_guess_normal" ;; 55 *) gl_cv_func_ungetc_works="$gl_cross_guess_normal" ;;
55 esac 56 esac
56 ]) 57 ])
57 ]) 58 ])
diff --git a/gl/m4/unistd_h.m4 b/gl/m4/unistd_h.m4
index f4384027..81d1b9f6 100644
--- a/gl/m4/unistd_h.m4
+++ b/gl/m4/unistd_h.m4
@@ -1,5 +1,6 @@
1# unistd_h.m4 serial 90 1# unistd_h.m4
2dnl Copyright (C) 2006-2023 Free Software Foundation, Inc. 2# serial 95
3dnl Copyright (C) 2006-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -225,6 +226,7 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS],
225 REPLACE_COPY_FILE_RANGE=0; AC_SUBST([REPLACE_COPY_FILE_RANGE]) 226 REPLACE_COPY_FILE_RANGE=0; AC_SUBST([REPLACE_COPY_FILE_RANGE])
226 REPLACE_DUP=0; AC_SUBST([REPLACE_DUP]) 227 REPLACE_DUP=0; AC_SUBST([REPLACE_DUP])
227 REPLACE_DUP2=0; AC_SUBST([REPLACE_DUP2]) 228 REPLACE_DUP2=0; AC_SUBST([REPLACE_DUP2])
229 REPLACE_DUP3=0; AC_SUBST([REPLACE_DUP3])
228 REPLACE_EXECL=0; AC_SUBST([REPLACE_EXECL]) 230 REPLACE_EXECL=0; AC_SUBST([REPLACE_EXECL])
229 REPLACE_EXECLE=0; AC_SUBST([REPLACE_EXECLE]) 231 REPLACE_EXECLE=0; AC_SUBST([REPLACE_EXECLE])
230 REPLACE_EXECLP=0; AC_SUBST([REPLACE_EXECLP]) 232 REPLACE_EXECLP=0; AC_SUBST([REPLACE_EXECLP])
@@ -233,11 +235,14 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS],
233 REPLACE_EXECVP=0; AC_SUBST([REPLACE_EXECVP]) 235 REPLACE_EXECVP=0; AC_SUBST([REPLACE_EXECVP])
234 REPLACE_EXECVPE=0; AC_SUBST([REPLACE_EXECVPE]) 236 REPLACE_EXECVPE=0; AC_SUBST([REPLACE_EXECVPE])
235 REPLACE_FACCESSAT=0; AC_SUBST([REPLACE_FACCESSAT]) 237 REPLACE_FACCESSAT=0; AC_SUBST([REPLACE_FACCESSAT])
238 REPLACE_FCHDIR=0; AC_SUBST([REPLACE_FCHDIR])
236 REPLACE_FCHOWNAT=0; AC_SUBST([REPLACE_FCHOWNAT]) 239 REPLACE_FCHOWNAT=0; AC_SUBST([REPLACE_FCHOWNAT])
240 REPLACE_FDATASYNC=0; AC_SUBST([REPLACE_FDATASYNC])
237 REPLACE_FTRUNCATE=0; AC_SUBST([REPLACE_FTRUNCATE]) 241 REPLACE_FTRUNCATE=0; AC_SUBST([REPLACE_FTRUNCATE])
238 REPLACE_GETCWD=0; AC_SUBST([REPLACE_GETCWD]) 242 REPLACE_GETCWD=0; AC_SUBST([REPLACE_GETCWD])
239 REPLACE_GETDOMAINNAME=0; AC_SUBST([REPLACE_GETDOMAINNAME]) 243 REPLACE_GETDOMAINNAME=0; AC_SUBST([REPLACE_GETDOMAINNAME])
240 REPLACE_GETDTABLESIZE=0; AC_SUBST([REPLACE_GETDTABLESIZE]) 244 REPLACE_GETDTABLESIZE=0; AC_SUBST([REPLACE_GETDTABLESIZE])
245 REPLACE_GETENTROPY=0; AC_SUBST([REPLACE_GETENTROPY])
241 REPLACE_GETLOGIN_R=0; AC_SUBST([REPLACE_GETLOGIN_R]) 246 REPLACE_GETLOGIN_R=0; AC_SUBST([REPLACE_GETLOGIN_R])
242 REPLACE_GETGROUPS=0; AC_SUBST([REPLACE_GETGROUPS]) 247 REPLACE_GETGROUPS=0; AC_SUBST([REPLACE_GETGROUPS])
243 REPLACE_GETPAGESIZE=0; AC_SUBST([REPLACE_GETPAGESIZE]) 248 REPLACE_GETPAGESIZE=0; AC_SUBST([REPLACE_GETPAGESIZE])
@@ -248,12 +253,14 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS],
248 REPLACE_LINK=0; AC_SUBST([REPLACE_LINK]) 253 REPLACE_LINK=0; AC_SUBST([REPLACE_LINK])
249 REPLACE_LINKAT=0; AC_SUBST([REPLACE_LINKAT]) 254 REPLACE_LINKAT=0; AC_SUBST([REPLACE_LINKAT])
250 REPLACE_LSEEK=0; AC_SUBST([REPLACE_LSEEK]) 255 REPLACE_LSEEK=0; AC_SUBST([REPLACE_LSEEK])
256 REPLACE_PIPE2=0; AC_SUBST([REPLACE_PIPE2])
251 REPLACE_PREAD=0; AC_SUBST([REPLACE_PREAD]) 257 REPLACE_PREAD=0; AC_SUBST([REPLACE_PREAD])
252 REPLACE_PWRITE=0; AC_SUBST([REPLACE_PWRITE]) 258 REPLACE_PWRITE=0; AC_SUBST([REPLACE_PWRITE])
253 REPLACE_READ=0; AC_SUBST([REPLACE_READ]) 259 REPLACE_READ=0; AC_SUBST([REPLACE_READ])
254 REPLACE_READLINK=0; AC_SUBST([REPLACE_READLINK]) 260 REPLACE_READLINK=0; AC_SUBST([REPLACE_READLINK])
255 REPLACE_READLINKAT=0; AC_SUBST([REPLACE_READLINKAT]) 261 REPLACE_READLINKAT=0; AC_SUBST([REPLACE_READLINKAT])
256 REPLACE_RMDIR=0; AC_SUBST([REPLACE_RMDIR]) 262 REPLACE_RMDIR=0; AC_SUBST([REPLACE_RMDIR])
263 REPLACE_SETHOSTNAME=0; AC_SUBST([REPLACE_SETHOSTNAME])
257 REPLACE_SLEEP=0; AC_SUBST([REPLACE_SLEEP]) 264 REPLACE_SLEEP=0; AC_SUBST([REPLACE_SLEEP])
258 REPLACE_SYMLINK=0; AC_SUBST([REPLACE_SYMLINK]) 265 REPLACE_SYMLINK=0; AC_SUBST([REPLACE_SYMLINK])
259 REPLACE_SYMLINKAT=0; AC_SUBST([REPLACE_SYMLINKAT]) 266 REPLACE_SYMLINKAT=0; AC_SUBST([REPLACE_SYMLINKAT])
diff --git a/gl/m4/unlocked-io.m4 b/gl/m4/unlocked-io.m4
index 407c0bac..e96cf5f8 100644
--- a/gl/m4/unlocked-io.m4
+++ b/gl/m4/unlocked-io.m4
@@ -1,10 +1,9 @@
1# unlocked-io.m4 serial 16 1# unlocked-io.m4
2 2# serial 16
3# Copyright (C) 1998-2006, 2009-2023 Free Software Foundation, Inc. 3dnl Copyright (C) 1998-2006, 2009-2024 Free Software Foundation, Inc.
4# 4dnl This file is free software; the Free Software Foundation
5# This file is free software; the Free Software Foundation 5dnl gives unlimited permission to copy and/or distribute it,
6# gives unlimited permission to copy and/or distribute it, 6dnl with or without modifications, as long as this notice is preserved.
7# with or without modifications, as long as this notice is preserved.
8 7
9dnl From Jim Meyering. 8dnl From Jim Meyering.
10dnl 9dnl
diff --git a/gl/m4/vararrays.m4 b/gl/m4/vararrays.m4
index fd6230c2..9211f69d 100644
--- a/gl/m4/vararrays.m4
+++ b/gl/m4/vararrays.m4
@@ -1,13 +1,13 @@
1# Check for variable-length arrays. 1# vararrays.m4
2
3# serial 6 2# serial 6
3dnl Copyright (C) 2001, 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.
4 7
5# From Paul Eggert 8# Check for variable-length arrays.
6 9
7# Copyright (C) 2001, 2009-2023 Free Software Foundation, Inc. 10# From Paul Eggert
8# This file is free software; the Free Software Foundation
9# gives unlimited permission to copy and/or distribute it,
10# with or without modifications, as long as this notice is preserved.
11 11
12m4_version_prereq([2.70], [], [ 12m4_version_prereq([2.70], [], [
13 13
diff --git a/gl/m4/vasnprintf.m4 b/gl/m4/vasnprintf.m4
index 6361c843..1ea2055e 100644
--- a/gl/m4/vasnprintf.m4
+++ b/gl/m4/vasnprintf.m4
@@ -1,5 +1,6 @@
1# vasnprintf.m4 serial 38 1# vasnprintf.m4
2dnl Copyright (C) 2002-2004, 2006-2023 Free Software Foundation, Inc. 2# serial 52
3dnl Copyright (C) 2002-2004, 2006-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -29,6 +30,15 @@ AC_DEFUN([gl_REPLACE_VASNPRINTF],
29 gl_PREREQ_ASNPRINTF 30 gl_PREREQ_ASNPRINTF
30]) 31])
31 32
33AC_DEFUN([gl_FUNC_VASNWPRINTF],
34[
35 AC_LIBOBJ([printf-args])
36 gl_PREREQ_PRINTF_ARGS
37 gl_PREREQ_PRINTF_PARSE
38 gl_PREREQ_VASNWPRINTF
39 gl_PREREQ_ASNPRINTF
40])
41
32# Prerequisites of lib/printf-args.h, lib/printf-args.c. 42# Prerequisites of lib/printf-args.h, lib/printf-args.c.
33AC_DEFUN([gl_PREREQ_PRINTF_ARGS], 43AC_DEFUN([gl_PREREQ_PRINTF_ARGS],
34[ 44[
@@ -37,6 +47,7 @@ AC_DEFUN([gl_PREREQ_PRINTF_ARGS],
37]) 47])
38 48
39# Prerequisites of lib/printf-parse.h, lib/printf-parse.c. 49# Prerequisites of lib/printf-parse.h, lib/printf-parse.c.
50# Prerequisites of lib/wprintf-parse.h, lib/wprintf-parse.c.
40AC_DEFUN([gl_PREREQ_PRINTF_PARSE], 51AC_DEFUN([gl_PREREQ_PRINTF_PARSE],
41[ 52[
42 AC_REQUIRE([gl_FEATURES_H]) 53 AC_REQUIRE([gl_FEATURES_H])
@@ -50,19 +61,13 @@ AC_DEFUN([gl_PREREQ_PRINTF_PARSE],
50 AC_REQUIRE([gt_AC_TYPE_INTMAX_T]) 61 AC_REQUIRE([gt_AC_TYPE_INTMAX_T])
51]) 62])
52 63
53# Prerequisites of lib/vasnprintf.c. 64# Prerequisites of lib/vasnprintf.c if !WIDE_CHAR_VERSION.
54AC_DEFUN_ONCE([gl_PREREQ_VASNPRINTF], 65AC_DEFUN_ONCE([gl_PREREQ_VASNPRINTF],
55[ 66[
56 AC_REQUIRE([AC_FUNC_ALLOCA]) 67 AC_CHECK_FUNCS([snprintf strnlen wcrtomb])
57 AC_REQUIRE([gt_TYPE_WCHAR_T])
58 AC_REQUIRE([gt_TYPE_WINT_T])
59 AC_CHECK_FUNCS([snprintf strnlen wcslen wcsnlen mbrtowc wcrtomb])
60 dnl Use the _snprintf function only if it is declared (because on NetBSD it 68 dnl Use the _snprintf function only if it is declared (because on NetBSD it
61 dnl is defined as a weak alias of snprintf; we prefer to use the latter). 69 dnl is defined as a weak alias of snprintf; we prefer to use the latter).
62 AC_CHECK_DECLS([_snprintf], , , [[#include <stdio.h>]]) 70 AC_CHECK_DECLS([_snprintf], , , [[#include <stdio.h>]])
63 dnl Knowing DBL_EXPBIT0_WORD and DBL_EXPBIT0_BIT enables an optimization
64 dnl in the code for NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE.
65 AC_REQUIRE([gl_DOUBLE_EXPONENT_LOCATION])
66 dnl We can avoid a lot of code by assuming that snprintf's return value 71 dnl We can avoid a lot of code by assuming that snprintf's return value
67 dnl conforms to ISO C99. So check that. 72 dnl conforms to ISO C99. So check that.
68 AC_REQUIRE([gl_SNPRINTF_RETVAL_C99]) 73 AC_REQUIRE([gl_SNPRINTF_RETVAL_C99])
@@ -84,6 +89,108 @@ AC_DEFUN_ONCE([gl_PREREQ_VASNPRINTF],
84 terminated.]) 89 terminated.])
85 ;; 90 ;;
86 esac 91 esac
92 gl_PREREQ_VASNXPRINTF
93])
94
95# Prerequisites of lib/vasnwprintf.c.
96AC_DEFUN_ONCE([gl_PREREQ_VASNWPRINTF],
97[
98 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
99 AC_CHECK_FUNCS_ONCE([swprintf wcsnlen mbrtowc])
100 AC_CHECK_DECLS([_snwprintf], , , [[#include <stdio.h>]])
101 AC_CHECK_DECLS([wcsnlen], , , [[#include <wchar.h>]])
102 gl_SWPRINTF_WORKS
103 case "$gl_cv_func_swprintf_works" in
104 *yes)
105 AC_DEFINE([HAVE_WORKING_SWPRINTF], [1],
106 [Define if the swprintf function works correctly when it produces output
107 that contains null wide characters.])
108 ;;
109 esac
110 gl_MBRTOWC_C_LOCALE
111 case "$gl_cv_func_mbrtowc_C_locale_sans_EILSEQ" in
112 *yes)
113 AC_CACHE_CHECK([whether swprintf in the C locale is free of encoding errors],
114 [gl_cv_func_swprintf_C_locale_sans_EILSEQ],
115 [
116 AC_RUN_IFELSE(
117 [AC_LANG_SOURCE([[
118#ifndef __USE_MINGW_ANSI_STDIO
119# define __USE_MINGW_ANSI_STDIO 1
120#endif
121#include <stdio.h>
122#include <wchar.h>
123int main()
124{
125 int result = 0;
126 { /* This test fails on glibc 2.35, musl libc 1.2.4, FreeBSD 13.2, NetBSD 9.3,
127 OpenBSD 7.2, Cygwin 2.9.0.
128 Reported at <https://www.openwall.com/lists/musl/2023/06/12/2>. */
129 wchar_t buf[12];
130 int ret = swprintf (buf, 12, L"%c", '\377');
131 if (ret < 0)
132 result |= 1;
133 }
134 return result;
135}]])],
136 [gl_cv_func_swprintf_C_locale_sans_EILSEQ=yes],
137 [gl_cv_func_swprintf_C_locale_sans_EILSEQ=no],
138 [case "$host_os" in
139 # Guess no on glibc systems.
140 *-gnu* | gnu*) gl_cv_func_swprintf_C_locale_sans_EILSEQ="guessing yes";;
141 # Guess no on musl systems.
142 *-musl* | midipix*) gl_cv_func_swprintf_C_locale_sans_EILSEQ="guessing no";;
143 # If we don't know, obey --enable-cross-guesses.
144 *) gl_cv_func_swprintf_C_locale_sans_EILSEQ="$gl_cross_guess_normal";;
145 esac
146 ])
147 ])
148 ;;
149 esac
150 if case "$gl_cv_func_mbrtowc_C_locale_sans_EILSEQ" in
151 *yes) false ;;
152 *) true ;;
153 esac \
154 || case "$gl_cv_func_swprintf_C_locale_sans_EILSEQ" in
155 *yes) false ;;
156 *) true ;;
157 esac; then
158 AC_DEFINE([NEED_WPRINTF_DIRECTIVE_C], [1],
159 [Define if the vasnwprintf implementation needs special code for
160 the 'c' directive.])
161 fi
162 gl_SWPRINTF_DIRECTIVE_LA
163 case "$gl_cv_func_swprintf_directive_la" in
164 *yes) ;;
165 *)
166 AC_DEFINE([NEED_WPRINTF_DIRECTIVE_LA], [1],
167 [Define if the vasnwprintf implementation needs special code for
168 the 'a' directive with 'long double' arguments.])
169 ;;
170 esac
171 gl_SWPRINTF_DIRECTIVE_LC
172 case "$gl_cv_func_swprintf_directive_lc" in
173 *yes) ;;
174 *)
175 AC_DEFINE([NEED_WPRINTF_DIRECTIVE_LC], [1],
176 [Define if the vasnwprintf implementation needs special code for
177 the 'lc' directive.])
178 ;;
179 esac
180 gl_MUSL_LIBC
181 gl_PREREQ_VASNXPRINTF
182])
183
184# Common prerequisites of lib/vasnprintf.c and lib/vasnwprintf.c.
185AC_DEFUN_ONCE([gl_PREREQ_VASNXPRINTF],
186[
187 AC_REQUIRE([AC_FUNC_ALLOCA])
188 AC_REQUIRE([gt_TYPE_WCHAR_T])
189 AC_REQUIRE([gt_TYPE_WINT_T])
190 AC_CHECK_FUNCS([wcslen])
191 dnl Knowing DBL_EXPBIT0_WORD and DBL_EXPBIT0_BIT enables an optimization
192 dnl in the code for NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE.
193 AC_REQUIRE([gl_DOUBLE_EXPONENT_LOCATION])
87]) 194])
88 195
89# Extra prerequisites of lib/vasnprintf.c for supporting 'long double' 196# Extra prerequisites of lib/vasnprintf.c for supporting 'long double'
@@ -152,7 +259,22 @@ AC_DEFUN([gl_PREREQ_VASNPRINTF_DIRECTIVE_A],
152 AC_DEFINE([NEED_PRINTF_DIRECTIVE_A], [1], 259 AC_DEFINE([NEED_PRINTF_DIRECTIVE_A], [1],
153 [Define if the vasnprintf implementation needs special code for 260 [Define if the vasnprintf implementation needs special code for
154 the 'a' and 'A' directives.]) 261 the 'a' and 'A' directives.])
155 AC_CHECK_FUNCS([nl_langinfo]) 262 gl_CHECK_FUNCS_ANDROID([nl_langinfo], [[#include <langinfo.h>]])
263 ;;
264 esac
265])
266
267# Extra prerequisites of lib/vasnprintf.c for supporting the 'b' directive.
268AC_DEFUN([gl_PREREQ_VASNPRINTF_DIRECTIVE_B],
269[
270 AC_REQUIRE([gl_PRINTF_DIRECTIVE_B])
271 case "$gl_cv_func_printf_directive_b" in
272 *yes)
273 ;;
274 *)
275 AC_DEFINE([NEED_PRINTF_DIRECTIVE_B], [1],
276 [Define if the vasnprintf implementation needs special code for
277 the 'b' directive.])
156 ;; 278 ;;
157 esac 279 esac
158]) 280])
@@ -187,6 +309,21 @@ AC_DEFUN([gl_PREREQ_VASNPRINTF_DIRECTIVE_LS],
187 esac 309 esac
188]) 310])
189 311
312# Extra prerequisites of lib/vasnprintf.c for supporting the 'lc' directive.
313AC_DEFUN([gl_PREREQ_VASNPRINTF_DIRECTIVE_LC],
314[
315 AC_REQUIRE([gl_PRINTF_DIRECTIVE_LC])
316 case "$gl_cv_func_printf_directive_lc" in
317 *yes)
318 ;;
319 *)
320 AC_DEFINE([NEED_PRINTF_DIRECTIVE_LC], [1],
321 [Define if the vasnprintf implementation needs special code for
322 the 'lc' directive.])
323 ;;
324 esac
325])
326
190# Extra prerequisites of lib/vasnprintf.c for supporting the ' flag. 327# Extra prerequisites of lib/vasnprintf.c for supporting the ' flag.
191AC_DEFUN([gl_PREREQ_VASNPRINTF_FLAG_GROUPING], 328AC_DEFUN([gl_PREREQ_VASNPRINTF_FLAG_GROUPING],
192[ 329[
@@ -232,6 +369,22 @@ AC_DEFUN([gl_PREREQ_VASNPRINTF_FLAG_ZERO],
232 esac 369 esac
233]) 370])
234 371
372# Extra prerequisites of lib/vasnprintf.c for supporting the # flag with a
373# zero precision and a zero value in the 'x' and 'X' directives.
374AC_DEFUN([gl_PREREQ_VASNPRINTF_FLAG_ALT_PRECISION_ZERO],
375[
376 AC_REQUIRE([gl_PRINTF_FLAG_ALT_PRECISION_ZERO])
377 case "$gl_cv_func_printf_flag_alt_precision_zero" in
378 *yes)
379 ;;
380 *)
381 AC_DEFINE([NEED_PRINTF_FLAG_ALT_PRECISION_ZERO], [1],
382 [Define if the vasnprintf implementation needs special code for the
383 # flag with a zero precision and a zero value in the 'x' and 'X' directives.])
384 ;;
385 esac
386])
387
235# Extra prerequisites of lib/vasnprintf.c for supporting large precisions. 388# Extra prerequisites of lib/vasnprintf.c for supporting large precisions.
236AC_DEFUN([gl_PREREQ_VASNPRINTF_PRECISION], 389AC_DEFUN([gl_PREREQ_VASNPRINTF_PRECISION],
237[ 390[
@@ -276,23 +429,53 @@ AC_DEFUN([gl_PREREQ_VASNPRINTF_ENOMEM],
276]) 429])
277 430
278# Prerequisites of lib/vasnprintf.c including all extras for POSIX compliance. 431# Prerequisites of lib/vasnprintf.c including all extras for POSIX compliance.
279AC_DEFUN([gl_PREREQ_VASNPRINTF_WITH_EXTRAS], 432AC_DEFUN([gl_PREREQ_VASNPRINTF_WITH_POSIX_EXTRAS],
280[ 433[
281 AC_REQUIRE([gl_PREREQ_VASNPRINTF]) 434 AC_REQUIRE([gl_PREREQ_VASNPRINTF])
282 gl_PREREQ_VASNPRINTF_LONG_DOUBLE 435 gl_PREREQ_VASNPRINTF_LONG_DOUBLE
283 gl_PREREQ_VASNPRINTF_INFINITE_DOUBLE 436 gl_PREREQ_VASNPRINTF_INFINITE_DOUBLE
284 gl_PREREQ_VASNPRINTF_INFINITE_LONG_DOUBLE 437 gl_PREREQ_VASNPRINTF_INFINITE_LONG_DOUBLE
285 gl_PREREQ_VASNPRINTF_DIRECTIVE_A 438 gl_PREREQ_VASNPRINTF_DIRECTIVE_A
439 gl_PREREQ_VASNPRINTF_DIRECTIVE_B
286 gl_PREREQ_VASNPRINTF_DIRECTIVE_F 440 gl_PREREQ_VASNPRINTF_DIRECTIVE_F
287 gl_PREREQ_VASNPRINTF_DIRECTIVE_LS 441 gl_PREREQ_VASNPRINTF_DIRECTIVE_LS
442 gl_PREREQ_VASNPRINTF_DIRECTIVE_LC
288 gl_PREREQ_VASNPRINTF_FLAG_GROUPING 443 gl_PREREQ_VASNPRINTF_FLAG_GROUPING
289 gl_PREREQ_VASNPRINTF_FLAG_LEFTADJUST 444 gl_PREREQ_VASNPRINTF_FLAG_LEFTADJUST
290 gl_PREREQ_VASNPRINTF_FLAG_ZERO 445 gl_PREREQ_VASNPRINTF_FLAG_ZERO
446 gl_PREREQ_VASNPRINTF_FLAG_ALT_PRECISION_ZERO
291 gl_PREREQ_VASNPRINTF_PRECISION 447 gl_PREREQ_VASNPRINTF_PRECISION
292 gl_PREREQ_VASNPRINTF_ENOMEM 448 gl_PREREQ_VASNPRINTF_ENOMEM
293]) 449])
294 450
451# Extra prerequisites of lib/vasnprintf.c for supporting the 'B' directive.
452AC_DEFUN([gl_PREREQ_VASNPRINTF_DIRECTIVE_UPPERCASE_B],
453[
454 AC_REQUIRE([gl_PRINTF_DIRECTIVE_UPPERCASE_B])
455 case "$gl_cv_func_printf_directive_uppercase_b" in
456 *yes)
457 ;;
458 *)
459 AC_DEFINE([NEED_PRINTF_DIRECTIVE_UPPERCASE_B], [1],
460 [Define if the vasnprintf implementation needs special code for
461 the 'B' directive.])
462 ;;
463 esac
464])
465
466# Prerequisites of lib/vasnprintf.c including all extras for POSIX compliance
467# and GNU compatibility.
468AC_DEFUN([gl_PREREQ_VASNPRINTF_WITH_GNU_EXTRAS],
469[
470 gl_PREREQ_VASNPRINTF_WITH_POSIX_EXTRAS
471 AC_DEFINE([SUPPORT_GNU_PRINTF_DIRECTIVES], [1],
472 [Define if the vasnprintf implementation should support GNU compatible
473 printf directives.])
474 gl_PREREQ_VASNPRINTF_DIRECTIVE_UPPERCASE_B
475])
476
295# Prerequisites of lib/asnprintf.c. 477# Prerequisites of lib/asnprintf.c.
478# Prerequisites of lib/asnwprintf.c.
296AC_DEFUN([gl_PREREQ_ASNPRINTF], 479AC_DEFUN([gl_PREREQ_ASNPRINTF],
297[ 480[
298]) 481])
diff --git a/gl/m4/vasprintf.m4 b/gl/m4/vasprintf.m4
index 6e6156a7..73f7b807 100644
--- a/gl/m4/vasprintf.m4
+++ b/gl/m4/vasprintf.m4
@@ -1,5 +1,6 @@
1# vasprintf.m4 serial 6 1# vasprintf.m4
2dnl Copyright (C) 2002-2003, 2006-2007, 2009-2023 Free Software Foundation, 2# serial 6
3dnl Copyright (C) 2002-2003, 2006-2007, 2009-2024 Free Software Foundation,
3dnl Inc. 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,
diff --git a/gl/m4/visibility.m4 b/gl/m4/visibility.m4
index f0468e89..ecf09686 100644
--- a/gl/m4/visibility.m4
+++ b/gl/m4/visibility.m4
@@ -1,5 +1,6 @@
1# visibility.m4 serial 8 1# visibility.m4
2dnl Copyright (C) 2005, 2008, 2010-2023 Free Software Foundation, Inc. 2# serial 9
3dnl Copyright (C) 2005, 2008, 2010-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -31,18 +32,18 @@ AC_DEFUN([gl_VISIBILITY],
31 dnl user has put into $CC $CFLAGS $CPPFLAGS. 32 dnl user has put into $CC $CFLAGS $CPPFLAGS.
32 AC_CACHE_CHECK([whether the -Werror option is usable], 33 AC_CACHE_CHECK([whether the -Werror option is usable],
33 [gl_cv_cc_vis_werror], 34 [gl_cv_cc_vis_werror],
34 [gl_save_CFLAGS="$CFLAGS" 35 [gl_saved_CFLAGS="$CFLAGS"
35 CFLAGS="$CFLAGS -Werror" 36 CFLAGS="$CFLAGS -Werror"
36 AC_COMPILE_IFELSE( 37 AC_COMPILE_IFELSE(
37 [AC_LANG_PROGRAM([[]], [[]])], 38 [AC_LANG_PROGRAM([[]], [[]])],
38 [gl_cv_cc_vis_werror=yes], 39 [gl_cv_cc_vis_werror=yes],
39 [gl_cv_cc_vis_werror=no]) 40 [gl_cv_cc_vis_werror=no])
40 CFLAGS="$gl_save_CFLAGS" 41 CFLAGS="$gl_saved_CFLAGS"
41 ]) 42 ])
42 dnl Now check whether visibility declarations are supported. 43 dnl Now check whether visibility declarations are supported.
43 AC_CACHE_CHECK([for simple visibility declarations], 44 AC_CACHE_CHECK([for simple visibility declarations],
44 [gl_cv_cc_visibility], 45 [gl_cv_cc_visibility],
45 [gl_save_CFLAGS="$CFLAGS" 46 [gl_saved_CFLAGS="$CFLAGS"
46 CFLAGS="$CFLAGS -fvisibility=hidden" 47 CFLAGS="$CFLAGS -fvisibility=hidden"
47 dnl We use the option -Werror and a function dummyfunc, because on some 48 dnl We use the option -Werror and a function dummyfunc, because on some
48 dnl platforms (Cygwin 1.7) the use of -fvisibility triggers a warning 49 dnl platforms (Cygwin 1.7) the use of -fvisibility triggers a warning
@@ -68,7 +69,7 @@ AC_DEFUN([gl_VISIBILITY],
68 [[]])], 69 [[]])],
69 [gl_cv_cc_visibility=yes], 70 [gl_cv_cc_visibility=yes],
70 [gl_cv_cc_visibility=no]) 71 [gl_cv_cc_visibility=no])
71 CFLAGS="$gl_save_CFLAGS" 72 CFLAGS="$gl_saved_CFLAGS"
72 ]) 73 ])
73 if test $gl_cv_cc_visibility = yes; then 74 if test $gl_cv_cc_visibility = yes; then
74 CFLAG_VISIBILITY="-fvisibility=hidden" 75 CFLAG_VISIBILITY="-fvisibility=hidden"
diff --git a/gl/m4/vsnprintf.m4 b/gl/m4/vsnprintf.m4
index 7fbb11c4..9f321f3f 100644
--- a/gl/m4/vsnprintf.m4
+++ b/gl/m4/vsnprintf.m4
@@ -1,5 +1,6 @@
1# vsnprintf.m4 serial 7 1# vsnprintf.m4
2dnl Copyright (C) 2002-2004, 2007-2023 Free Software Foundation, Inc. 2# serial 7
3dnl Copyright (C) 2002-2004, 2007-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/warn-on-use.m4 b/gl/m4/warn-on-use.m4
index 10649c5c..6c8c76b8 100644
--- a/gl/m4/warn-on-use.m4
+++ b/gl/m4/warn-on-use.m4
@@ -1,5 +1,6 @@
1# warn-on-use.m4 serial 10 1# warn-on-use.m4
2dnl Copyright (C) 2010-2023 Free Software Foundation, Inc. 2# serial 11
3dnl Copyright (C) 2010-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -36,7 +37,7 @@ AC_DEFUN([gl_WARN_ON_USE_PREPARE],
36 dnl clang (e.g. strndup), reference ac_compile_for_check_decl instead 37 dnl clang (e.g. strndup), reference ac_compile_for_check_decl instead
37 dnl of ac_compile. If, for whatever reason, the override of AC_PROG_CC 38 dnl of ac_compile. If, for whatever reason, the override of AC_PROG_CC
38 dnl in zzgnulib.m4 is inactive, use the original ac_compile. 39 dnl in zzgnulib.m4 is inactive, use the original ac_compile.
39 ac_save_ac_compile="$ac_compile" 40 ac_saved_ac_compile="$ac_compile"
40 if test -n "$ac_compile_for_check_decl"; then 41 if test -n "$ac_compile_for_check_decl"; then
41 ac_compile="$ac_compile_for_check_decl" 42 ac_compile="$ac_compile_for_check_decl"
42 fi 43 fi
@@ -46,7 +47,7 @@ AC_DEFUN([gl_WARN_ON_USE_PREPARE],
46[[#undef $gl_func 47[[#undef $gl_func
47 (void) $gl_func;]])], 48 (void) $gl_func;]])],
48 [AS_VAR_SET([gl_Symbol], [yes])], [AS_VAR_SET([gl_Symbol], [no])])]) 49 [AS_VAR_SET([gl_Symbol], [yes])], [AS_VAR_SET([gl_Symbol], [no])])])
49 ac_compile="$ac_save_ac_compile" 50 ac_compile="$ac_saved_ac_compile"
50 AS_VAR_IF([gl_Symbol], [yes], 51 AS_VAR_IF([gl_Symbol], [yes],
51 [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_RAW_DECL_$gl_func]), [1]) 52 [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_RAW_DECL_$gl_func]), [1])
52 dnl Shortcut for an AC_CHECK_DECL invocation that may come later: 53 dnl Shortcut for an AC_CHECK_DECL invocation that may come later:
diff --git a/gl/m4/wchar_h.m4 b/gl/m4/wchar_h.m4
index 8ec66193..995bdc65 100644
--- a/gl/m4/wchar_h.m4
+++ b/gl/m4/wchar_h.m4
@@ -1,13 +1,13 @@
1dnl A placeholder for ISO C99 <wchar.h>, for platforms that have issues. 1# wchar_h.m4
2 2# serial 64
3dnl Copyright (C) 2007-2023 Free Software Foundation, Inc. 3dnl Copyright (C) 2007-2024 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 7
8dnl Written by Eric Blake. 8dnl A placeholder for ISO C99 <wchar.h>, for platforms that have issues.
9 9
10# wchar_h.m4 serial 55 10dnl Written by Eric Blake.
11 11
12AC_DEFUN_ONCE([gl_WCHAR_H], 12AC_DEFUN_ONCE([gl_WCHAR_H],
13[ 13[
@@ -86,8 +86,8 @@ AC_DEFUN([gl_WCHAR_H_INLINE_OK],
86 dnl z/OS when using the XPLINK object format (due to duplicate 86 dnl z/OS when using the XPLINK object format (due to duplicate
87 dnl CSECT names). Instead, temporarily redefine $ac_compile so 87 dnl CSECT names). Instead, temporarily redefine $ac_compile so
88 dnl that the object file has the latter name from the start. 88 dnl that the object file has the latter name from the start.
89 save_ac_compile="$ac_compile" 89 saved_ac_compile="$ac_compile"
90 ac_compile=`echo "$save_ac_compile" | sed s/conftest/conftest1/` 90 ac_compile=`echo "$saved_ac_compile" | sed s/conftest/conftest1/`
91 if echo '#include "conftest.c"' >conftest1.c \ 91 if echo '#include "conftest.c"' >conftest1.c \
92 && AC_TRY_EVAL([ac_compile]); then 92 && AC_TRY_EVAL([ac_compile]); then
93 AC_LANG_CONFTEST([ 93 AC_LANG_CONFTEST([
@@ -97,7 +97,7 @@ AC_DEFUN([gl_WCHAR_H_INLINE_OK],
97 int zero (void) { return 0; } 97 int zero (void) { return 0; }
98 ]])]) 98 ]])])
99 dnl See note above about renaming object files. 99 dnl See note above about renaming object files.
100 ac_compile=`echo "$save_ac_compile" | sed s/conftest/conftest2/` 100 ac_compile=`echo "$saved_ac_compile" | sed s/conftest/conftest2/`
101 if echo '#include "conftest.c"' >conftest2.c \ 101 if echo '#include "conftest.c"' >conftest2.c \
102 && AC_TRY_EVAL([ac_compile]); then 102 && AC_TRY_EVAL([ac_compile]); then
103 if $CC -o conftest$ac_exeext $CFLAGS $LDFLAGS conftest1.$ac_objext conftest2.$ac_objext $LIBS >&AS_MESSAGE_LOG_FD 2>&1; then 103 if $CC -o conftest$ac_exeext $CFLAGS $LDFLAGS conftest1.$ac_objext conftest2.$ac_objext $LIBS >&AS_MESSAGE_LOG_FD 2>&1; then
@@ -107,7 +107,7 @@ AC_DEFUN([gl_WCHAR_H_INLINE_OK],
107 fi 107 fi
108 fi 108 fi
109 fi 109 fi
110 ac_compile="$save_ac_compile" 110 ac_compile="$saved_ac_compile"
111 rm -f conftest[12].c conftest[12].$ac_objext conftest$ac_exeext 111 rm -f conftest[12].c conftest[12].$ac_objext conftest$ac_exeext
112 ;; 112 ;;
113 esac 113 esac
@@ -147,6 +147,7 @@ AC_DEFUN([gl_WCHAR_H_REQUIRE_DEFAULTS],
147 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_BTOWC]) 147 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_BTOWC])
148 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_WCTOB]) 148 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_WCTOB])
149 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSINIT]) 149 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSINIT])
150 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSZERO])
150 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBRTOWC]) 151 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBRTOWC])
151 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBRLEN]) 152 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBRLEN])
152 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSRTOWCS]) 153 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSRTOWCS])
@@ -185,6 +186,7 @@ AC_DEFUN([gl_WCHAR_H_REQUIRE_DEFAULTS],
185 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_WCSTOK]) 186 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_WCSTOK])
186 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_WCSWIDTH]) 187 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_WCSWIDTH])
187 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_WCSFTIME]) 188 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_WCSFTIME])
189 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_WGETCWD])
188 dnl Support Microsoft deprecated alias function names by default. 190 dnl Support Microsoft deprecated alias function names by default.
189 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_WCSDUP], [1]) 191 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_WCSDUP], [1])
190 ]) 192 ])
@@ -253,5 +255,10 @@ AC_DEFUN([gl_WCHAR_H_DEFAULTS],
253 REPLACE_WCWIDTH=0; AC_SUBST([REPLACE_WCWIDTH]) 255 REPLACE_WCWIDTH=0; AC_SUBST([REPLACE_WCWIDTH])
254 REPLACE_WCSWIDTH=0; AC_SUBST([REPLACE_WCSWIDTH]) 256 REPLACE_WCSWIDTH=0; AC_SUBST([REPLACE_WCSWIDTH])
255 REPLACE_WCSFTIME=0; AC_SUBST([REPLACE_WCSFTIME]) 257 REPLACE_WCSFTIME=0; AC_SUBST([REPLACE_WCSFTIME])
258 REPLACE_WCSCMP=0; AC_SUBST([REPLACE_WCSCMP])
259 REPLACE_WCSNCMP=0; AC_SUBST([REPLACE_WCSNCMP])
260 REPLACE_WCSSTR=0; AC_SUBST([REPLACE_WCSSTR])
256 REPLACE_WCSTOK=0; AC_SUBST([REPLACE_WCSTOK]) 261 REPLACE_WCSTOK=0; AC_SUBST([REPLACE_WCSTOK])
262 REPLACE_WMEMCMP=0; AC_SUBST([REPLACE_WMEMCMP])
263 REPLACE_WMEMPCPY=0; AC_SUBST([REPLACE_WMEMPCPY])
257]) 264])
diff --git a/gl/m4/wchar_t.m4 b/gl/m4/wchar_t.m4
index 50bde08a..968832cb 100644
--- a/gl/m4/wchar_t.m4
+++ b/gl/m4/wchar_t.m4
@@ -1,5 +1,6 @@
1# wchar_t.m4 serial 4 (gettext-0.18.2) 1# wchar_t.m4
2dnl Copyright (C) 2002-2003, 2008-2023 Free Software Foundation, Inc. 2# serial 4 (gettext-0.18.2)
3dnl Copyright (C) 2002-2003, 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/wcrtomb.m4 b/gl/m4/wcrtomb.m4
index d51b36e1..35dff6f0 100644
--- a/gl/m4/wcrtomb.m4
+++ b/gl/m4/wcrtomb.m4
@@ -1,5 +1,6 @@
1# wcrtomb.m4 serial 17 1# wcrtomb.m4
2dnl Copyright (C) 2008-2023 Free Software Foundation, Inc. 2# serial 19
3dnl Copyright (C) 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
@@ -82,9 +83,11 @@ int main ()
82changequote(,)dnl 83changequote(,)dnl
83 case "$host_os" in 84 case "$host_os" in
84 # Guess no on AIX 4, OSF/1, Solaris, native Windows. 85 # Guess no on AIX 4, OSF/1, Solaris, native Windows.
85 aix4* | osf* | solaris* | mingw*) gl_cv_func_wcrtomb_retval="guessing no" ;; 86 aix4* | osf* | solaris* | mingw* | windows*)
87 gl_cv_func_wcrtomb_retval="guessing no" ;;
86 # Guess yes otherwise. 88 # Guess yes otherwise.
87 *) gl_cv_func_wcrtomb_retval="guessing yes" ;; 89 *)
90 gl_cv_func_wcrtomb_retval="guessing yes" ;;
88 esac 91 esac
89changequote([,])dnl 92changequote([,])dnl
90 if test $LOCALE_FR != none || test $LOCALE_FR_UTF8 != none || test $LOCALE_JA != none || test $LOCALE_ZH_CN != none; then 93 if test $LOCALE_FR != none || test $LOCALE_FR_UTF8 != none || test $LOCALE_JA != none || test $LOCALE_ZH_CN != none; then
@@ -97,12 +100,14 @@ changequote([,])dnl
97int main () 100int main ()
98{ 101{
99 int result = 0; 102 int result = 0;
100 if (setlocale (LC_ALL, "$LOCALE_FR") != NULL) 103 if (strcmp ("$LOCALE_FR", "none") != 0
104 && setlocale (LC_ALL, "$LOCALE_FR") != NULL)
101 { 105 {
102 if (wcrtomb (NULL, 0, NULL) != 1) 106 if (wcrtomb (NULL, 0, NULL) != 1)
103 result |= 1; 107 result |= 1;
104 } 108 }
105 if (setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL) 109 if (strcmp ("$LOCALE_FR_UTF8", "none") != 0
110 && setlocale (LC_ALL, "$LOCALE_FR_UTF8") != NULL)
106 { 111 {
107 if (wcrtomb (NULL, 0, NULL) != 1) 112 if (wcrtomb (NULL, 0, NULL) != 1)
108 result |= 2; 113 result |= 2;
@@ -113,12 +118,14 @@ int main ()
113 result |= 2; 118 result |= 2;
114 } 119 }
115 } 120 }
116 if (setlocale (LC_ALL, "$LOCALE_JA") != NULL) 121 if (strcmp ("$LOCALE_JA", "none") != 0
122 && setlocale (LC_ALL, "$LOCALE_JA") != NULL)
117 { 123 {
118 if (wcrtomb (NULL, 0, NULL) != 1) 124 if (wcrtomb (NULL, 0, NULL) != 1)
119 result |= 4; 125 result |= 4;
120 } 126 }
121 if (setlocale (LC_ALL, "$LOCALE_ZH_CN") != NULL) 127 if (strcmp ("$LOCALE_ZH_CN", "none") != 0
128 && setlocale (LC_ALL, "$LOCALE_ZH_CN") != NULL)
122 { 129 {
123 if (wcrtomb (NULL, 0, NULL) != 1) 130 if (wcrtomb (NULL, 0, NULL) != 1)
124 result |= 8; 131 result |= 8;
diff --git a/gl/m4/wctype.m4 b/gl/m4/wctype.m4
new file mode 100644
index 00000000..e5d70740
--- /dev/null
+++ b/gl/m4/wctype.m4
@@ -0,0 +1,52 @@
1# wctype.m4
2# serial 6
3dnl Copyright (C) 2011-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_ONCE([gl_FUNC_WCTYPE],
9[
10 AC_REQUIRE([gl_WCTYPE_H_DEFAULTS])
11 AC_REQUIRE([gl_WCTYPE_H])
12 AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
13 HAVE_WCTYPE=$HAVE_WCTYPE_T
14 if test $HAVE_WCTYPE = 1; then
15 AC_CACHE_CHECK([whether wctype supports the "blank" and "punct" character classes],
16 [gl_cv_func_wctype_works],
17 [AC_RUN_IFELSE(
18 [AC_LANG_SOURCE([[
19 #include <ctype.h>
20 #include <wchar.h>
21 #include <wctype.h>
22 int main ()
23 {
24 /* This test fails on mingw. */
25 if (wctype ("blank") == (wctype_t)0)
26 return 1;
27 /* This test fails on MSVC 14. */
28 if ((! iswctype ('\t', wctype ("blank"))) != (! iswblank ('\t')))
29 return 2;
30 /* This test fails on Android 11. */
31 if ((! iswctype ('\`', wctype ("punct"))) != (! ispunct ('\`')))
32 return 4;
33 return 0;
34 }
35 ]])],
36 [gl_cv_func_wctype_works=yes], [gl_cv_func_wctype_works=no],
37 [case "$host_os" in
38 # Guess no on native Windows.
39 mingw* | windows*) gl_cv_func_wctype_works="guessing no" ;;
40 # Guess no on Android.
41 android*) gl_cv_func_wctype_works="guessing no" ;;
42 # Guess yes otherwise.
43 *) gl_cv_func_wctype_works="guessing yes" ;;
44 esac
45 ])
46 ])
47 case "$gl_cv_func_wctype_works" in
48 *yes) ;;
49 *) REPLACE_WCTYPE=1 ;;
50 esac
51 fi
52])
diff --git a/gl/m4/wctype_h.m4 b/gl/m4/wctype_h.m4
index 6856a735..a3b07c2a 100644
--- a/gl/m4/wctype_h.m4
+++ b/gl/m4/wctype_h.m4
@@ -1,8 +1,9 @@
1# wctype_h.m4 serial 30 1# wctype_h.m4
2# serial 33
2 3
3dnl 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.
4 5
5dnl Copyright (C) 2006-2023 Free Software Foundation, Inc. 6dnl Copyright (C) 2006-2024 Free Software Foundation, Inc.
6dnl This file is free software; the Free Software Foundation 7dnl This file is free software; the Free Software Foundation
7dnl gives unlimited permission to copy and/or distribute it, 8dnl gives unlimited permission to copy and/or distribute it,
8dnl with or without modifications, as long as this notice is preserved. 9dnl with or without modifications, as long as this notice is preserved.
@@ -178,6 +179,7 @@ AC_DEFUN([gl_WCTYPE_H_REQUIRE_DEFAULTS],
178 m4_defun(GL_MODULE_INDICATOR_PREFIX[_WCTYPE_H_MODULE_INDICATOR_DEFAULTS], [ 179 m4_defun(GL_MODULE_INDICATOR_PREFIX[_WCTYPE_H_MODULE_INDICATOR_DEFAULTS], [
179 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ISWBLANK]) 180 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ISWBLANK])
180 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ISWDIGIT]) 181 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ISWDIGIT])
182 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ISWPUNCT])
181 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ISWXDIGIT]) 183 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ISWXDIGIT])
182 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_WCTYPE]) 184 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_WCTYPE])
183 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ISWCTYPE]) 185 gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ISWCTYPE])
@@ -196,5 +198,8 @@ AC_DEFUN([gl_WCTYPE_H_DEFAULTS],
196 HAVE_WCTRANS_T=1; AC_SUBST([HAVE_WCTRANS_T]) 198 HAVE_WCTRANS_T=1; AC_SUBST([HAVE_WCTRANS_T])
197 REPLACE_ISWBLANK=0; AC_SUBST([REPLACE_ISWBLANK]) 199 REPLACE_ISWBLANK=0; AC_SUBST([REPLACE_ISWBLANK])
198 REPLACE_ISWDIGIT=0; AC_SUBST([REPLACE_ISWDIGIT]) 200 REPLACE_ISWDIGIT=0; AC_SUBST([REPLACE_ISWDIGIT])
201 REPLACE_ISWPUNCT=0; AC_SUBST([REPLACE_ISWPUNCT])
199 REPLACE_ISWXDIGIT=0; AC_SUBST([REPLACE_ISWXDIGIT]) 202 REPLACE_ISWXDIGIT=0; AC_SUBST([REPLACE_ISWXDIGIT])
203 REPLACE_WCTRANS=0; AC_SUBST([REPLACE_WCTRANS])
204 REPLACE_WCTYPE=0; AC_SUBST([REPLACE_WCTYPE])
200]) 205])
diff --git a/gl/m4/wint_t.m4 b/gl/m4/wint_t.m4
index dfd743b3..883fac28 100644
--- a/gl/m4/wint_t.m4
+++ b/gl/m4/wint_t.m4
@@ -1,5 +1,6 @@
1# wint_t.m4 serial 11 1# wint_t.m4
2dnl Copyright (C) 2003, 2007-2023 Free Software Foundation, Inc. 2# serial 11
3dnl Copyright (C) 2003, 2007-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/xalloc.m4 b/gl/m4/xalloc.m4
index fc56f59a..d44d0f08 100644
--- a/gl/m4/xalloc.m4
+++ b/gl/m4/xalloc.m4
@@ -1,5 +1,6 @@
1# xalloc.m4 serial 18 1# xalloc.m4
2dnl Copyright (C) 2002-2006, 2009-2023 Free Software Foundation, Inc. 2# serial 18
3dnl Copyright (C) 2002-2006, 2009-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/xsize.m4 b/gl/m4/xsize.m4
index 649db9c5..e5784973 100644
--- a/gl/m4/xsize.m4
+++ b/gl/m4/xsize.m4
@@ -1,5 +1,6 @@
1# xsize.m4 serial 5 1# xsize.m4
2dnl Copyright (C) 2003-2004, 2008-2023 Free Software Foundation, Inc. 2# serial 5
3dnl Copyright (C) 2003-2004, 2008-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/m4/zzgnulib.m4 b/gl/m4/zzgnulib.m4
index 362102b6..710fba4e 100644
--- a/gl/m4/zzgnulib.m4
+++ b/gl/m4/zzgnulib.m4
@@ -1,5 +1,6 @@
1# zzgnulib.m4 serial 1 1# zzgnulib.m4
2dnl Copyright (C) 2020-2023 Free Software Foundation, Inc. 2# serial 1
3dnl Copyright (C) 2020-2024 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation 4dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it, 5dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved. 6dnl with or without modifications, as long as this notice is preserved.
diff --git a/gl/malloc.c b/gl/malloc.c
index 3ade35cb..2a7867a1 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 1997-1998, 2006-2007, 2009-2024 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/malloc/dynarray-skeleton.c b/gl/malloc/dynarray-skeleton.c
index 580c278b..a95241ab 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2017-2024 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 a9a3b085..3163e278 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2017-2024 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 ebc93109..95e34e7a 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2017-2024 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 7da53931..7bdba159 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2017-2024 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
@@ -22,7 +22,7 @@
22 22
23#include <dynarray.h> 23#include <dynarray.h>
24#include <errno.h> 24#include <errno.h>
25#include <intprops.h> 25#include <stdckdint.h>
26#include <stdlib.h> 26#include <stdlib.h>
27#include <string.h> 27#include <string.h>
28 28
@@ -56,7 +56,7 @@ __libc_dynarray_emplace_enlarge (struct dynarray_header *list,
56 } 56 }
57 57
58 size_t new_size; 58 size_t new_size;
59 if (INT_MULTIPLY_WRAPV (new_allocated, element_size, &new_size)) 59 if (ckd_mul (&new_size, new_allocated, element_size))
60 return false; 60 return false;
61 void *new_array; 61 void *new_array;
62 if (list->array == scratch) 62 if (list->array == scratch)
diff --git a/gl/malloc/dynarray_finalize.c b/gl/malloc/dynarray_finalize.c
index 673595a5..52764f73 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2017-2024 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 7ecd4de6..7323f8ee 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2017-2024 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
@@ -22,7 +22,7 @@
22 22
23#include <dynarray.h> 23#include <dynarray.h>
24#include <errno.h> 24#include <errno.h>
25#include <intprops.h> 25#include <stdckdint.h>
26#include <stdlib.h> 26#include <stdlib.h>
27#include <string.h> 27#include <string.h>
28 28
@@ -42,7 +42,7 @@ __libc_dynarray_resize (struct dynarray_header *list, size_t size,
42 over-allocation here. */ 42 over-allocation here. */
43 43
44 size_t new_size_bytes; 44 size_t new_size_bytes;
45 if (INT_MULTIPLY_WRAPV (size, element_size, &new_size_bytes)) 45 if (ckd_mul (&new_size_bytes, size, element_size))
46 { 46 {
47 /* Overflow. */ 47 /* Overflow. */
48 __set_errno (ENOMEM); 48 __set_errno (ENOMEM);
diff --git a/gl/malloc/dynarray_resize_clear.c b/gl/malloc/dynarray_resize_clear.c
index bb23c522..aa17f740 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2017-2024 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 f055b1e5..e75c72df 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2003, 2006-2007, 2009-2024 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
@@ -22,6 +22,9 @@
22#include "malloca.h" 22#include "malloca.h"
23 23
24#include <stdckdint.h> 24#include <stdckdint.h>
25#if defined __CHERI_PURE_CAPABILITY__
26# include <cheri.h>
27#endif
25 28
26#include "idx.h" 29#include "idx.h"
27 30
@@ -36,10 +39,15 @@
36 allocation. 39 allocation.
37 - NULL comes from a failed heap allocation. */ 40 - NULL comes from a failed heap allocation. */
38 41
42#if defined __CHERI_PURE_CAPABILITY__
43/* Type for holding the original malloc() result. */
44typedef uintptr_t small_t;
45#else
39/* Type for holding very small pointer differences. */ 46/* Type for holding very small pointer differences. */
40typedef unsigned char small_t; 47typedef unsigned char small_t;
41/* Verify that it is wide enough. */ 48/* Verify that it is wide enough. */
42static_assert (2 * sa_alignment_max - 1 <= (small_t) -1); 49static_assert (2 * sa_alignment_max - 1 <= (small_t) -1);
50#endif
43 51
44void * 52void *
45mmalloca (size_t n) 53mmalloca (size_t n)
@@ -56,20 +64,28 @@ mmalloca (size_t n)
56 64
57 if (mem != NULL) 65 if (mem != NULL)
58 { 66 {
59 uintptr_t umem = (uintptr_t)mem, umemplus; 67 uintptr_t umem = (uintptr_t) mem;
60 /* The ckd_add avoids signed integer overflow on 68 /* The ckd_add avoids signed integer overflow on
61 theoretical platforms where UINTPTR_MAX <= INT_MAX. */ 69 theoretical platforms where UINTPTR_MAX <= INT_MAX. */
70 uintptr_t umemplus;
62 ckd_add (&umemplus, umem, sizeof (small_t) + sa_alignment_max - 1); 71 ckd_add (&umemplus, umem, sizeof (small_t) + sa_alignment_max - 1);
63 idx_t offset = ((umemplus & ~alignment2_mask) 72 idx_t offset = (umemplus - umemplus % (2 * sa_alignment_max)
64 + sa_alignment_max - umem); 73 + sa_alignment_max - umem);
65 void *vp = mem + offset; 74 void *p = mem + offset;
66 small_t *p = vp;
67 /* Here p >= mem + sizeof (small_t), 75 /* Here p >= mem + sizeof (small_t),
68 and p <= mem + sizeof (small_t) + 2 * sa_alignment_max - 1 76 and p <= mem + sizeof (small_t) + 2 * sa_alignment_max - 1
69 hence p + n <= mem + nplus. 77 hence p + n <= mem + nplus.
70 So, the memory range [p, p+n) lies in the allocated memory range 78 So, the memory range [p, p+n) lies in the allocated memory range
71 [mem, mem + nplus). */ 79 [mem, mem + nplus). */
72 p[-1] = offset; 80 small_t *sp = p;
81# if defined __CHERI_PURE_CAPABILITY__
82 sp[-1] = umem;
83 p = (char *) cheri_bounds_set ((char *) p - sizeof (small_t),
84 sizeof (small_t) + n)
85 + sizeof (small_t);
86# else
87 sp[-1] = offset;
88# endif
73 /* p ≡ sa_alignment_max mod 2*sa_alignment_max. */ 89 /* p ≡ sa_alignment_max mod 2*sa_alignment_max. */
74 return p; 90 return p;
75 } 91 }
@@ -90,15 +106,22 @@ void
90freea (void *p) 106freea (void *p)
91{ 107{
92 /* Check argument. */ 108 /* Check argument. */
93 if ((uintptr_t) p & (sa_alignment_max - 1)) 109 uintptr_t u = (uintptr_t) p;
110 if (u & (sa_alignment_max - 1))
94 { 111 {
95 /* p was not the result of a malloca() call. Invalid argument. */ 112 /* p was not the result of a malloca() call. Invalid argument. */
96 abort (); 113 abort ();
97 } 114 }
98 /* Determine whether p was a non-NULL pointer returned by mmalloca(). */ 115 /* Determine whether p was a non-NULL pointer returned by mmalloca(). */
99 if ((uintptr_t) p & sa_alignment_max) 116 if (u & sa_alignment_max)
100 { 117 {
101 void *mem = (char *) p - ((small_t *) p)[-1]; 118 char *cp = p;
119 small_t *sp = p;
120# if defined __CHERI_PURE_CAPABILITY__
121 void *mem = sp[-1];
122# else
123 void *mem = cp - sp[-1];
124# endif
102 free (mem); 125 free (mem);
103 } 126 }
104} 127}
diff --git a/gl/malloca.h b/gl/malloca.h
index 325c7277..c5208421 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2003-2007, 2009-2024 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
@@ -18,10 +18,19 @@
18#ifndef _MALLOCA_H 18#ifndef _MALLOCA_H
19#define _MALLOCA_H 19#define _MALLOCA_H
20 20
21/* This file uses _GL_ATTRIBUTE_ALLOC_SIZE, _GL_ATTRIBUTE_DEALLOC,
22 _GL_ATTRIBUTE_MALLOC, HAVE_ALLOCA. */
23#if !_GL_CONFIG_H_INCLUDED
24 #error "Please include config.h first."
25#endif
26
21#include <alloca.h> 27#include <alloca.h>
22#include <stddef.h> 28#include <stddef.h>
23#include <stdlib.h> 29#include <stdlib.h>
24#include <stdint.h> 30#include <stdint.h>
31#if defined __CHERI_PURE_CAPABILITY__
32# include <cheri.h>
33#endif
25 34
26#include "xalloc-oversized.h" 35#include "xalloc-oversized.h"
27 36
@@ -62,12 +71,24 @@ extern void freea (void *p);
62 memory allocated on the stack, that must be freed using freea() before 71 memory allocated on the stack, that must be freed using freea() before
63 the function returns. Upon failure, it returns NULL. */ 72 the function returns. Upon failure, it returns NULL. */
64#if HAVE_ALLOCA 73#if HAVE_ALLOCA
65# define malloca(N) \ 74# if defined __CHERI_PURE_CAPABILITY__
66 ((N) < 4032 - (2 * sa_alignment_max - 1) \ 75# define malloca(N) \
67 ? (void *) (((uintptr_t) (char *) alloca ((N) + 2 * sa_alignment_max - 1) \ 76 ((N) < 4032 - (2 * sa_alignment_max - 1) \
68 + (2 * sa_alignment_max - 1)) \ 77 ? cheri_bounds_set ((void *) (((uintptr_t) \
69 & ~(uintptr_t)(2 * sa_alignment_max - 1)) \ 78 (char *) \
70 : mmalloca (N)) 79 alloca ((N) + 2 * sa_alignment_max - 1) \
80 + (2 * sa_alignment_max - 1)) \
81 & ~(uintptr_t)(2 * sa_alignment_max - 1)), \
82 (N)) \
83 : mmalloca (N))
84# else
85# define malloca(N) \
86 ((N) < 4032 - (2 * sa_alignment_max - 1) \
87 ? (void *) (((uintptr_t) (char *) alloca ((N) + 2 * sa_alignment_max - 1) \
88 + (2 * sa_alignment_max - 1)) \
89 & ~(uintptr_t)(2 * sa_alignment_max - 1)) \
90 : mmalloca (N))
91# endif
71#else 92#else
72# define malloca(N) \ 93# define malloca(N) \
73 mmalloca (N) 94 mmalloca (N)
diff --git a/gl/math.c b/gl/math.c
index 67cabbcf..78da4d4a 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2012-2024 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
@@ -18,5 +18,5 @@
18#include <config.h> 18#include <config.h>
19 19
20#define _GL_MATH_INLINE _GL_EXTERN_INLINE 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 f3d58afc..96d0da44 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2002-2003, 2007-2024 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,6 +15,11 @@
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/* On Android, in C++ mode, when /usr/include/c++/v1/math.h is being included
19 and /usr/include/math.h has not yet been included, skip this file, since it
20 would lead to many syntax errors. */
21#if !(defined __ANDROID__ && defined _LIBCPP_MATH_H && !defined INFINITY)
22
18#ifndef _@GUARD_PREFIX@_MATH_H 23#ifndef _@GUARD_PREFIX@_MATH_H
19 24
20#if __GNUC__ >= 3 25#if __GNUC__ >= 3
@@ -43,14 +48,17 @@
43#ifndef _@GUARD_PREFIX@_MATH_H 48#ifndef _@GUARD_PREFIX@_MATH_H
44#define _@GUARD_PREFIX@_MATH_H 49#define _@GUARD_PREFIX@_MATH_H
45 50
51/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE, _GL_ATTRIBUTE_CONST,
52 GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */
53#if !_GL_CONFIG_H_INCLUDED
54 #error "Please include config.h first."
55#endif
56
46/* On OpenVMS, NAN, INFINITY, and HUGEVAL macros are defined in <fp.h>. */ 57/* On OpenVMS, NAN, INFINITY, and HUGEVAL macros are defined in <fp.h>. */
47#if defined __VMS && ! defined NAN 58#if defined __VMS && ! defined NAN
48# include <fp.h> 59# include <fp.h>
49#endif 60#endif
50 61
51#ifndef _GL_INLINE_HEADER_BEGIN
52 #error "Please include config.h first."
53#endif
54_GL_INLINE_HEADER_BEGIN 62_GL_INLINE_HEADER_BEGIN
55#ifndef _GL_MATH_INLINE 63#ifndef _GL_MATH_INLINE
56# define _GL_MATH_INLINE _GL_INLINE 64# define _GL_MATH_INLINE _GL_INLINE
@@ -1427,6 +1435,29 @@ _GL_WARN_ON_USE (ldexpf, "ldexpf is unportable - "
1427#endif 1435#endif
1428 1436
1429/* Return x * 2^exp. */ 1437/* Return x * 2^exp. */
1438#if @GNULIB_LDEXP@
1439# if @REPLACE_LDEXP@
1440# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1441# undef ldexp
1442# define ldexp rpl_ldexp
1443# endif
1444_GL_FUNCDECL_RPL (ldexp, double, (double x, int exp));
1445_GL_CXXALIAS_RPL (ldexp, double, (double x, int exp));
1446# else
1447/* Assume ldexp is always declared. */
1448_GL_CXXALIAS_SYS (ldexp, double, (double x, int exp));
1449# endif
1450# if __GLIBC__ >= 2
1451_GL_CXXALIASWARN1 (ldexp, double, (double x, int exp));
1452# endif
1453#elif defined GNULIB_POSIXCHECK
1454# undef ldexp
1455/* Assume ldexp is always declared. */
1456_GL_WARN_ON_USE (ldexp, "ldexp is unportable - "
1457 "use gnulib module ldexp for portability");
1458#endif
1459
1460/* Return x * 2^exp. */
1430#if @GNULIB_LDEXPL@ && @REPLACE_LDEXPL@ 1461#if @GNULIB_LDEXPL@ && @REPLACE_LDEXPL@
1431# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1462# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1432# undef ldexpl 1463# undef ldexpl
@@ -1691,7 +1722,9 @@ _GL_FUNCDECL_SYS (log2f, float, (float x));
1691# endif 1722# endif
1692_GL_CXXALIAS_SYS (log2f, float, (float x)); 1723_GL_CXXALIAS_SYS (log2f, float, (float x));
1693# endif 1724# endif
1725# if __GLIBC__ >= 2
1694_GL_CXXALIASWARN (log2f); 1726_GL_CXXALIASWARN (log2f);
1727# endif
1695#elif defined GNULIB_POSIXCHECK 1728#elif defined GNULIB_POSIXCHECK
1696# undef log2f 1729# undef log2f
1697# if HAVE_RAW_DECL_LOG2F 1730# if HAVE_RAW_DECL_LOG2F
@@ -2512,16 +2545,22 @@ _GL_WARN_REAL_FLOATING_DECL (isinf);
2512#if @GNULIB_ISNANF@ 2545#if @GNULIB_ISNANF@
2513/* Test for NaN for 'float' numbers. */ 2546/* Test for NaN for 'float' numbers. */
2514# if @HAVE_ISNANF@ 2547# if @HAVE_ISNANF@
2548# if defined __sun || defined __sgi
2549/* Solaris and IRIX have isnanf() and declare it in <ieeefp.h>. We cannot
2550 define isnanf as a macro, because that would conflict with <ieeefp.h>. */
2551_GL_EXTERN_C int isnanf (float x);
2552# else
2515/* The original <math.h> included above provides a declaration of isnan macro 2553/* The original <math.h> included above provides a declaration of isnan macro
2516 or (older) isnanf function. */ 2554 or (older) isnanf function. */
2517# if (__GNUC__ >= 4) || (__clang_major__ >= 4) 2555# if (__GNUC__ >= 4) || (__clang_major__ >= 4)
2518 /* GCC >= 4.0 and clang provide a type-generic built-in for isnan. 2556 /* GCC >= 4.0 and clang provide a type-generic built-in for isnan.
2519 GCC >= 4.0 also provides __builtin_isnanf, but clang doesn't. */ 2557 GCC >= 4.0 also provides __builtin_isnanf, but clang doesn't. */
2520# undef isnanf 2558# undef isnanf
2521# define isnanf(x) __builtin_isnan ((float)(x)) 2559# define isnanf(x) __builtin_isnan ((float)(x))
2522# elif defined isnan 2560# elif defined isnan
2523# undef isnanf 2561# undef isnanf
2524# define isnanf(x) isnan ((float)(x)) 2562# define isnanf(x) isnan ((float)(x))
2563# endif
2525# endif 2564# endif
2526# else 2565# else
2527/* Test whether X is a NaN. */ 2566/* Test whether X is a NaN. */
@@ -2536,15 +2575,21 @@ _GL_EXTERN_C int isnanf (float x);
2536 This function is a gnulib extension, unlike isnan() which applied only 2575 This function is a gnulib extension, unlike isnan() which applied only
2537 to 'double' numbers earlier but now is a type-generic macro. */ 2576 to 'double' numbers earlier but now is a type-generic macro. */
2538# if @HAVE_ISNAND@ 2577# if @HAVE_ISNAND@
2578# if defined __sun || defined __sgi
2579/* Solaris and IRIX have isnand() and declare it in <ieeefp.h>. We cannot
2580 define isnand as a macro, because that would conflict with <ieeefp.h>. */
2581_GL_EXTERN_C int isnand (double x);
2582# else
2539/* The original <math.h> included above provides a declaration of isnan 2583/* The original <math.h> included above provides a declaration of isnan
2540 macro. */ 2584 macro. */
2541# if (__GNUC__ >= 4) || (__clang_major__ >= 4) 2585# if (__GNUC__ >= 4) || (__clang_major__ >= 4)
2542 /* GCC >= 4.0 and clang provide a type-generic built-in for isnan. */ 2586 /* GCC >= 4.0 and clang provide a type-generic built-in for isnan. */
2543# undef isnand 2587# undef isnand
2544# define isnand(x) __builtin_isnan ((double)(x)) 2588# define isnand(x) __builtin_isnan ((double)(x))
2545# else 2589# else
2546# undef isnand 2590# undef isnand
2547# define isnand(x) isnan ((double)(x)) 2591# define isnand(x) isnan ((double)(x))
2592# endif
2548# endif 2593# endif
2549# else 2594# else
2550/* Test whether X is a NaN. */ 2595/* Test whether X is a NaN. */
@@ -2617,12 +2662,17 @@ _GL_EXTERN_C int rpl_isnanl (long double x) _GL_ATTRIBUTE_CONST;
2617# if defined isnan || defined GNULIB_NAMESPACE 2662# if defined isnan || defined GNULIB_NAMESPACE
2618_GL_MATH_CXX_REAL_FLOATING_DECL_1 (isnan) 2663_GL_MATH_CXX_REAL_FLOATING_DECL_1 (isnan)
2619# undef isnan 2664# undef isnan
2620# if __GNUC__ >= 6 || (defined __clang__ && !((defined __APPLE__ && defined __MACH__ && __clang_major__ < 12) || (defined __FreeBSD__ && (__clang_major__ < 7 || __clang_major__ >= 11)) || defined __OpenBSD__ || (defined _WIN32 && !defined __CYGWIN__))) 2665# if __GNUC__ >= 6 || (defined __clang__ && !((defined __APPLE__ && defined __MACH__ && __clang_major__ != 12) || (defined __FreeBSD__ && (__clang_major__ < 7 || __clang_major__ >= 11)) || defined __OpenBSD__ || (defined _WIN32 && !defined __CYGWIN__)))
2621 /* This platform's <cmath> possibly defines isnan through a set of inline 2666 /* This platform's <cmath> possibly defines isnan through a set of inline
2622 functions. */ 2667 functions. */
2623_GL_MATH_CXX_REAL_FLOATING_DECL_2 (isnan, rpl_isnan, bool) 2668_GL_MATH_CXX_REAL_FLOATING_DECL_2 (isnan, rpl_isnan, bool)
2624# define isnan rpl_isnan 2669# define isnan rpl_isnan
2625# define GNULIB_NAMESPACE_LACKS_ISNAN 1 2670# define GNULIB_NAMESPACE_LACKS_ISNAN 1
2671# elif __clang_major__ >= 14
2672 /* Neither of the two possible _GL_MATH_CXX_REAL_FLOATING_DECL_2 invocations
2673 works. Inline functions are already present in /usr/include/c++/v1/math.h,
2674 which comes from LLVM. */
2675# define GNULIB_NAMESPACE_LACKS_ISNAN 1
2626# else 2676# else
2627_GL_MATH_CXX_REAL_FLOATING_DECL_2 (isnan, isnan, bool) 2677_GL_MATH_CXX_REAL_FLOATING_DECL_2 (isnan, isnan, bool)
2628# endif 2678# endif
@@ -2657,12 +2707,13 @@ _GL_WARN_REAL_FLOATING_DECL (isnan);
2657_GL_EXTERN_C int gl_signbitf (float arg); 2707_GL_EXTERN_C int gl_signbitf (float arg);
2658_GL_EXTERN_C int gl_signbitd (double arg); 2708_GL_EXTERN_C int gl_signbitd (double arg);
2659_GL_EXTERN_C int gl_signbitl (long double arg); 2709_GL_EXTERN_C int gl_signbitl (long double arg);
2660# if (__GNUC__ >= 2 || defined __clang__) && !defined __STRICT_ANSI__ 2710# if __GNUC__ >= 2 || defined __clang__
2661# define _GL_NUM_UINT_WORDS(type) \ 2711# define _GL_NUM_UINT_WORDS(type) \
2662 ((sizeof (type) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) 2712 ((sizeof (type) + sizeof (unsigned int) - 1) / sizeof (unsigned int))
2663# if defined FLT_SIGNBIT_WORD && defined FLT_SIGNBIT_BIT && !defined gl_signbitf 2713# if defined FLT_SIGNBIT_WORD && defined FLT_SIGNBIT_BIT && !defined gl_signbitf
2664# define gl_signbitf_OPTIMIZED_MACRO 2714# define gl_signbitf_OPTIMIZED_MACRO
2665# define gl_signbitf(arg) \ 2715# define gl_signbitf(arg) \
2716 __extension__ \
2666 ({ union { float _value; \ 2717 ({ union { float _value; \
2667 unsigned int _word[_GL_NUM_UINT_WORDS (float)]; \ 2718 unsigned int _word[_GL_NUM_UINT_WORDS (float)]; \
2668 } _m; \ 2719 } _m; \
@@ -2673,6 +2724,7 @@ _GL_EXTERN_C int gl_signbitl (long double arg);
2673# if defined DBL_SIGNBIT_WORD && defined DBL_SIGNBIT_BIT && !defined gl_signbitd 2724# if defined DBL_SIGNBIT_WORD && defined DBL_SIGNBIT_BIT && !defined gl_signbitd
2674# define gl_signbitd_OPTIMIZED_MACRO 2725# define gl_signbitd_OPTIMIZED_MACRO
2675# define gl_signbitd(arg) \ 2726# define gl_signbitd(arg) \
2727 __extension__ \
2676 ({ union { double _value; \ 2728 ({ union { double _value; \
2677 unsigned int _word[_GL_NUM_UINT_WORDS (double)]; \ 2729 unsigned int _word[_GL_NUM_UINT_WORDS (double)]; \
2678 } _m; \ 2730 } _m; \
@@ -2683,6 +2735,7 @@ _GL_EXTERN_C int gl_signbitl (long double arg);
2683# if defined LDBL_SIGNBIT_WORD && defined LDBL_SIGNBIT_BIT && !defined gl_signbitl 2735# if defined LDBL_SIGNBIT_WORD && defined LDBL_SIGNBIT_BIT && !defined gl_signbitl
2684# define gl_signbitl_OPTIMIZED_MACRO 2736# define gl_signbitl_OPTIMIZED_MACRO
2685# define gl_signbitl(arg) \ 2737# define gl_signbitl(arg) \
2738 __extension__ \
2686 ({ union { long double _value; \ 2739 ({ union { long double _value; \
2687 unsigned int _word[_GL_NUM_UINT_WORDS (long double)]; \ 2740 unsigned int _word[_GL_NUM_UINT_WORDS (long double)]; \
2688 } _m; \ 2741 } _m; \
@@ -2720,8 +2773,323 @@ _GL_WARN_REAL_FLOATING_DECL (signbit);
2720# endif 2773# endif
2721#endif 2774#endif
2722 2775
2776
2777#if @GNULIB_GETPAYLOADF@
2778# if @REPLACE_GETPAYLOADF@
2779# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2780# undef getpayloadf
2781# define getpayloadf rpl_getpayloadf
2782# endif
2783_GL_FUNCDECL_RPL (getpayloadf, float, (const float *));
2784_GL_CXXALIAS_RPL (getpayloadf, float, (const float *));
2785# else
2786# if !@HAVE_GETPAYLOADF@
2787_GL_FUNCDECL_SYS (getpayloadf, float, (const float *));
2788# endif
2789_GL_CXXALIAS_SYS (getpayloadf, float, (const float *));
2790# endif
2791_GL_CXXALIASWARN (getpayloadf);
2792#elif defined GNULIB_POSIXCHECK
2793# undef getpayloadf
2794# if HAVE_RAW_DECL_GETPAYLOADF
2795_GL_WARN_ON_USE (getpayloadf, "getpayloadf is unportable - "
2796 "use gnulib module getpayloadf for portability");
2797# endif
2798#endif
2799
2800#if @GNULIB_GETPAYLOAD@
2801# if @REPLACE_GETPAYLOAD@
2802# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2803# undef getpayload
2804# define getpayload rpl_getpayload
2805# endif
2806_GL_FUNCDECL_RPL (getpayload, double, (const double *));
2807_GL_CXXALIAS_RPL (getpayload, double, (const double *));
2808# else
2809# if !@HAVE_GETPAYLOAD@
2810_GL_FUNCDECL_SYS (getpayload, double, (const double *));
2811# endif
2812_GL_CXXALIAS_SYS (getpayload, double, (const double *));
2813# endif
2814_GL_CXXALIASWARN (getpayload);
2815#elif defined GNULIB_POSIXCHECK
2816# undef getpayload
2817# if HAVE_RAW_DECL_GETPAYLOAD
2818_GL_WARN_ON_USE (getpayload, "getpayload is unportable - "
2819 "use gnulib module getpayload for portability");
2820# endif
2821#endif
2822
2823#if @GNULIB_GETPAYLOADL@
2824# if @REPLACE_GETPAYLOADL@
2825# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2826# undef getpayloadl
2827# define getpayloadl rpl_getpayloadl
2828# endif
2829_GL_FUNCDECL_RPL (getpayloadl, long double, (const long double *));
2830_GL_CXXALIAS_RPL (getpayloadl, long double, (const long double *));
2831# else
2832# if !@HAVE_GETPAYLOADL@
2833_GL_FUNCDECL_SYS (getpayloadl, long double, (const long double *));
2834# endif
2835_GL_CXXALIAS_SYS (getpayloadl, long double, (const long double *));
2836# endif
2837_GL_CXXALIASWARN (getpayloadl);
2838#elif defined GNULIB_POSIXCHECK
2839# undef getpayloadl
2840# if HAVE_RAW_DECL_GETPAYLOADL
2841_GL_WARN_ON_USE (getpayloadl, "getpayloadl is unportable - "
2842 "use gnulib module getpayloadl for portability");
2843# endif
2844#endif
2845
2846
2847#if @GNULIB_SETPAYLOADF@
2848# if !@HAVE_SETPAYLOADF@
2849_GL_FUNCDECL_SYS (setpayloadf, int, (float *, float));
2850# endif
2851_GL_CXXALIAS_SYS (setpayloadf, int, (float *, float));
2852_GL_CXXALIASWARN (setpayloadf);
2853#elif defined GNULIB_POSIXCHECK
2854# undef setpayloadf
2855# if HAVE_RAW_DECL_SETPAYLOADF
2856_GL_WARN_ON_USE (setpayloadf, "setpayloadf is unportable - "
2857 "use gnulib module setpayloadf for portability");
2858# endif
2859#endif
2860
2861#if @GNULIB_SETPAYLOAD@
2862# if !@HAVE_SETPAYLOAD@
2863_GL_FUNCDECL_SYS (setpayload, int, (double *, double));
2864# endif
2865_GL_CXXALIAS_SYS (setpayload, int, (double *, double));
2866_GL_CXXALIASWARN (setpayload);
2867#elif defined GNULIB_POSIXCHECK
2868# undef setpayload
2869# if HAVE_RAW_DECL_SETPAYLOAD
2870_GL_WARN_ON_USE (setpayload, "setpayload is unportable - "
2871 "use gnulib module setpayload for portability");
2872# endif
2873#endif
2874
2875#if @GNULIB_SETPAYLOADL@
2876# if !@HAVE_SETPAYLOADL@
2877_GL_FUNCDECL_SYS (setpayloadl, int, (long double *, long double));
2878# endif
2879_GL_CXXALIAS_SYS (setpayloadl, int, (long double *, long double));
2880_GL_CXXALIASWARN (setpayloadl);
2881#elif defined GNULIB_POSIXCHECK
2882# undef setpayloadl
2883# if HAVE_RAW_DECL_SETPAYLOADL
2884_GL_WARN_ON_USE (setpayloadl, "setpayloadl is unportable - "
2885 "use gnulib module setpayloadl for portability");
2886# endif
2887#endif
2888
2889
2890#if @GNULIB_SETPAYLOADSIGF@
2891# if !@HAVE_SETPAYLOADSIGF@
2892_GL_FUNCDECL_SYS (setpayloadsigf, int, (float *, float));
2893# endif
2894_GL_CXXALIAS_SYS (setpayloadsigf, int, (float *, float));
2895_GL_CXXALIASWARN (setpayloadsigf);
2896#elif defined GNULIB_POSIXCHECK
2897# undef setpayloadsigf
2898# if HAVE_RAW_DECL_SETPAYLOADSIGF
2899_GL_WARN_ON_USE (setpayloadsigf, "setpayloadsigf is unportable - "
2900 "use gnulib module setpayloadsigf for portability");
2901# endif
2902#endif
2903
2904#if @GNULIB_SETPAYLOADSIG@
2905# if !@HAVE_SETPAYLOADSIG@
2906_GL_FUNCDECL_SYS (setpayloadsig, int, (double *, double));
2907# endif
2908_GL_CXXALIAS_SYS (setpayloadsig, int, (double *, double));
2909_GL_CXXALIASWARN (setpayloadsig);
2910#elif defined GNULIB_POSIXCHECK
2911# undef setpayloadsig
2912# if HAVE_RAW_DECL_SETPAYLOADSIG
2913_GL_WARN_ON_USE (setpayloadsig, "setpayloadsig is unportable - "
2914 "use gnulib module setpayloadsig for portability");
2915# endif
2916#endif
2917
2918#if @GNULIB_SETPAYLOADSIGL@
2919# if !@HAVE_SETPAYLOADSIGL@
2920_GL_FUNCDECL_SYS (setpayloadsigl, int, (long double *, long double));
2921# endif
2922_GL_CXXALIAS_SYS (setpayloadsigl, int, (long double *, long double));
2923_GL_CXXALIASWARN (setpayloadsigl);
2924#elif defined GNULIB_POSIXCHECK
2925# undef setpayloadsigl
2926# if HAVE_RAW_DECL_SETPAYLOADSIGL
2927_GL_WARN_ON_USE (setpayloadsigl, "setpayloadsigl is unportable - "
2928 "use gnulib module setpayloadsigl for portability");
2929# endif
2930#endif
2931
2932
2933#if @GNULIB_TOTALORDERF@
2934# if @REPLACE_TOTALORDERF@
2935# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2936# undef totalorderf
2937# define totalorderf rpl_totalorderf
2938# endif
2939_GL_FUNCDECL_RPL (totalorderf, int, (float const *, float const *));
2940_GL_CXXALIAS_RPL (totalorderf, int, (float const *, float const *));
2941# else
2942# if !@HAVE_TOTALORDERF@
2943_GL_FUNCDECL_SYS (totalorderf, int, (float const *, float const *));
2944# endif
2945_GL_CXXALIAS_SYS (totalorderf, int, (float const *, float const *));
2946# endif
2947_GL_CXXALIASWARN (totalorderf);
2948#elif defined GNULIB_POSIXCHECK
2949# undef totalorderf
2950# if HAVE_RAW_DECL_TOTALORDERF
2951_GL_WARN_ON_USE (totalorderf, "totalorderf is unportable - "
2952 "use gnulib module totalorderf for portability");
2953# endif
2954#endif
2955
2956#if @GNULIB_TOTALORDER@
2957# if @REPLACE_TOTALORDER@
2958# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2959# undef totalorder
2960# define totalorder rpl_totalorder
2961# endif
2962_GL_FUNCDECL_RPL (totalorder, int, (double const *, double const *));
2963_GL_CXXALIAS_RPL (totalorder, int, (double const *, double const *));
2964# else
2965# if !@HAVE_TOTALORDER@
2966_GL_FUNCDECL_SYS (totalorder, int, (double const *, double const *));
2967# endif
2968_GL_CXXALIAS_SYS (totalorder, int, (double const *, double const *));
2969# endif
2970# if __GLIBC__ >= 2
2971_GL_CXXALIASWARN1 (totalorder, int, (double const *, double const *));
2972# endif
2973#elif defined GNULIB_POSIXCHECK
2974# undef totalorder
2975# if HAVE_RAW_DECL_TOTALORDER
2976_GL_WARN_ON_USE (totalorder, "totalorder is unportable - "
2977 "use gnulib module totalorder for portability");
2978# endif
2979#endif
2980
2981#if @GNULIB_TOTALORDERL@
2982# if @REPLACE_TOTALORDERL@
2983# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2984# undef totalorderl
2985# define totalorderl rpl_totalorderl
2986# endif
2987_GL_FUNCDECL_RPL (totalorderl, int,
2988 (long double const *, long double const *));
2989_GL_CXXALIAS_RPL (totalorderl, int,
2990 (long double const *, long double const *));
2991# else
2992# if !@HAVE_TOTALORDERL@
2993_GL_FUNCDECL_SYS (totalorderl, int,
2994 (long double const *, long double const *));
2995# endif
2996_GL_CXXALIAS_SYS (totalorderl, int,
2997 (long double const *, long double const *));
2998# endif
2999_GL_CXXALIASWARN (totalorderl);
3000#elif defined GNULIB_POSIXCHECK
3001# undef totalorderl
3002# if HAVE_RAW_DECL_TOTALORDERL
3003_GL_WARN_ON_USE (totalorderl, "totalorderl is unportable - "
3004 "use gnulib module totalorderl for portability");
3005# endif
3006#endif
3007
3008
3009#if @GNULIB_TOTALORDERMAGF@
3010# if @REPLACE_TOTALORDERMAGF@
3011# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
3012# undef totalordermagf
3013# define totalordermagf rpl_totalordermagf
3014# endif
3015_GL_FUNCDECL_RPL (totalordermagf, int, (float const *, float const *));
3016_GL_CXXALIAS_RPL (totalordermagf, int, (float const *, float const *));
3017# else
3018# if !@HAVE_TOTALORDERMAGF@
3019_GL_FUNCDECL_SYS (totalordermagf, int, (float const *, float const *));
3020# endif
3021_GL_CXXALIAS_SYS (totalordermagf, int, (float const *, float const *));
3022# endif
3023# if __GLIBC__ >= 2
3024_GL_CXXALIASWARN1 (totalordermagf, int, (float const *, float const *));
3025# endif
3026#elif defined GNULIB_POSIXCHECK
3027# undef totalordermagf
3028# if HAVE_RAW_DECL_TOTALORDERMAGF
3029_GL_WARN_ON_USE (totalordermagf, "totalordermagf is unportable - "
3030 "use gnulib module totalordermagf for portability");
3031# endif
3032#endif
3033
3034#if @GNULIB_TOTALORDERMAG@
3035# if @REPLACE_TOTALORDERMAG@
3036# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
3037# undef totalordermag
3038# define totalordermag rpl_totalordermag
3039# endif
3040_GL_FUNCDECL_RPL (totalordermag, int, (double const *, double const *));
3041_GL_CXXALIAS_RPL (totalordermag, int, (double const *, double const *));
3042# else
3043# if !@HAVE_TOTALORDERMAG@
3044_GL_FUNCDECL_SYS (totalordermag, int, (double const *, double const *));
3045# endif
3046_GL_CXXALIAS_SYS (totalordermag, int, (double const *, double const *));
3047# endif
3048# if __GLIBC__ >= 2
3049_GL_CXXALIASWARN1 (totalordermag, int, (double const *, double const *));
3050# endif
3051#elif defined GNULIB_POSIXCHECK
3052# undef totalordermag
3053# if HAVE_RAW_DECL_TOTALORDERMAG
3054_GL_WARN_ON_USE (totalordermag, "totalordermag is unportable - "
3055 "use gnulib module totalordermag for portability");
3056# endif
3057#endif
3058
3059#if @GNULIB_TOTALORDERMAGL@
3060# if @REPLACE_TOTALORDERMAGL@
3061# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
3062# undef totalordermagl
3063# define totalordermagl rpl_totalordermagl
3064# endif
3065_GL_FUNCDECL_RPL (totalordermagl, int,
3066 (long double const *, long double const *));
3067_GL_CXXALIAS_RPL (totalordermagl, int,
3068 (long double const *, long double const *));
3069# else
3070# if !@HAVE_TOTALORDERMAGL@
3071_GL_FUNCDECL_SYS (totalordermagl, int,
3072 (long double const *, long double const *));
3073# endif
3074_GL_CXXALIAS_SYS (totalordermagl, int,
3075 (long double const *, long double const *));
3076# endif
3077# if __GLIBC__ >= 2
3078_GL_CXXALIASWARN1 (totalordermagl, int,
3079 (long double const *, long double const *));
3080# endif
3081#elif defined GNULIB_POSIXCHECK
3082# undef totalordermagl
3083# if HAVE_RAW_DECL_TOTALORDERMAGL
3084_GL_WARN_ON_USE (totalordermagl, "totalordermagl is unportable - "
3085 "use gnulib module totalordermagl for portability");
3086# endif
3087#endif
3088
3089
2723_GL_INLINE_HEADER_END 3090_GL_INLINE_HEADER_END
2724 3091
2725#endif /* _@GUARD_PREFIX@_MATH_H */ 3092#endif /* _@GUARD_PREFIX@_MATH_H */
2726#endif /* _GL_INCLUDING_MATH_H */ 3093#endif /* _GL_INCLUDING_MATH_H */
2727#endif /* _@GUARD_PREFIX@_MATH_H */ 3094#endif /* _@GUARD_PREFIX@_MATH_H */
3095#endif
diff --git a/gl/mbrtowc-impl-utf8.h b/gl/mbrtowc-impl-utf8.h
index 4fdd65d8..3a3ba13c 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 1999-2002, 2005-2024 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 e9c04ed7..963631ca 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 1999-2002, 2005-2024 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 c1a689a2..8a1646d2 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 1999-2002, 2005-2024 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
@@ -28,7 +28,11 @@
28# include <stdint.h> 28# include <stdint.h>
29# include <stdlib.h> 29# include <stdlib.h>
30 30
31# if defined _WIN32 && !defined __CYGWIN__ 31# if AVOID_ANY_THREADS
32
33/* The option '--disable-threads' explicitly requests no locking. */
34
35# elif defined _WIN32 && !defined __CYGWIN__
32 36
33# define WIN32_LEAN_AND_MEAN /* avoid including junk */ 37# define WIN32_LEAN_AND_MEAN /* avoid including junk */
34# include <windows.h> 38# include <windows.h>
diff --git a/gl/mbsinit.c b/gl/mbsinit.c
index 6e600798..d1b8475c 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2008-2024 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
@@ -36,7 +36,7 @@
36 buffered bytes (in the range 0..3), followed by up to 3 buffered bytes. 36 buffered bytes (in the range 0..3), followed by up to 3 buffered bytes.
37 See mbrtowc.c. 37 See mbrtowc.c.
38 - In wc -> mb direction, mbstate_t contains no information. In other 38 - In wc -> mb direction, mbstate_t contains no information. In other
39 words, it is always in the initial state. */ 39 words, it is always in an initial state. */
40 40
41static_assert (sizeof (mbstate_t) >= 4); 41static_assert (sizeof (mbstate_t) >= 4);
42 42
diff --git a/gl/mbszero.c b/gl/mbszero.c
new file mode 100644
index 00000000..25af2848
--- /dev/null
+++ b/gl/mbszero.c
@@ -0,0 +1,23 @@
1/* Put an mbstate_t into an initial conversion state.
2 Copyright (C) 2023-2024 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_MBSZERO
22/* Specification and implementation. */
23#include <wchar.h>
diff --git a/gl/mbtowc-impl.h b/gl/mbtowc-impl.h
index 39b977be..92efb4a7 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2011-2024 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
@@ -30,7 +30,7 @@ mbtowc (wchar_t *pwc, const char *s, size_t n)
30 wchar_t wc; 30 wchar_t wc;
31 size_t result; 31 size_t result;
32 32
33 memset (&state, 0, sizeof (mbstate_t)); 33 mbszero (&state);
34 result = mbrtowc (&wc, s, n, &state); 34 result = mbrtowc (&wc, s, n, &state);
35 if (result == (size_t)-1 || result == (size_t)-2) 35 if (result == (size_t)-1 || result == (size_t)-2)
36 { 36 {
diff --git a/gl/mbtowc-lock.c b/gl/mbtowc-lock.c
index 6ca6e10f..9001c5af 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2019-2024 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
@@ -18,9 +18,10 @@
18 18
19#include <config.h> 19#include <config.h>
20 20
21/* The option '--disable-threads' explicitly requests no locking. */
21/* When it is known that the gl_get_mbtowc_lock function is defined 22/* When it is known that the gl_get_mbtowc_lock function is defined
22 by a dependency library, it should not be defined here. */ 23 by a dependency library, it should not be defined here. */
23#if OMIT_MBTOWC_LOCK 24#if AVOID_ANY_THREADS || OMIT_MBTOWC_LOCK
24 25
25/* This declaration is solely to ensure that after preprocessing 26/* This declaration is solely to ensure that after preprocessing
26 this file is never empty. */ 27 this file is never empty. */
@@ -37,14 +38,14 @@ typedef int dummy;
37 38
38/* Macro for exporting a symbol (function, not variable) defined in this file, 39/* Macro for exporting a symbol (function, not variable) defined in this file,
39 when compiled into a shared library. */ 40 when compiled into a shared library. */
40# ifndef DLL_EXPORTED 41# ifndef SHLIB_EXPORTED
41# if HAVE_VISIBILITY 42# if HAVE_VISIBILITY
42 /* Override the effect of the compiler option '-fvisibility=hidden'. */ 43 /* Override the effect of the compiler option '-fvisibility=hidden'. */
43# define DLL_EXPORTED __attribute__((__visibility__("default"))) 44# define SHLIB_EXPORTED __attribute__((__visibility__("default")))
44# elif defined _WIN32 || defined __CYGWIN__ 45# elif defined _WIN32 || defined __CYGWIN__
45# define DLL_EXPORTED __declspec(dllexport) 46# define SHLIB_EXPORTED __declspec(dllexport)
46# else 47# else
47# define DLL_EXPORTED 48# define SHLIB_EXPORTED
48# endif 49# endif
49# endif 50# endif
50 51
@@ -59,7 +60,7 @@ typedef int dummy;
59 because the latter is not guaranteed to be a stable ABI in the future. */ 60 because the latter is not guaranteed to be a stable ABI in the future. */
60 61
61/* Make sure the function gets exported from DLLs. */ 62/* Make sure the function gets exported from DLLs. */
62DLL_EXPORTED CRITICAL_SECTION *gl_get_mbtowc_lock (void); 63SHLIB_EXPORTED CRITICAL_SECTION *gl_get_mbtowc_lock (void);
63 64
64static glwthread_initguard_t guard = GLWTHREAD_INITGUARD_INIT; 65static glwthread_initguard_t guard = GLWTHREAD_INITGUARD_INIT;
65static CRITICAL_SECTION lock; 66static CRITICAL_SECTION lock;
@@ -96,7 +97,7 @@ gl_get_mbtowc_lock (void)
96static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 97static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
97 98
98/* Make sure the function gets exported from shared libraries. */ 99/* Make sure the function gets exported from shared libraries. */
99DLL_EXPORTED pthread_mutex_t *gl_get_mbtowc_lock (void); 100SHLIB_EXPORTED pthread_mutex_t *gl_get_mbtowc_lock (void);
100 101
101/* Returns the internal lock used by mbrtowc and mbrtoc32. */ 102/* Returns the internal lock used by mbrtowc and mbrtoc32. */
102pthread_mutex_t * 103pthread_mutex_t *
@@ -123,7 +124,7 @@ atomic_init (void)
123} 124}
124 125
125/* Make sure the function gets exported from shared libraries. */ 126/* Make sure the function gets exported from shared libraries. */
126DLL_EXPORTED mtx_t *gl_get_mbtowc_lock (void); 127SHLIB_EXPORTED mtx_t *gl_get_mbtowc_lock (void);
127 128
128/* Returns the internal lock used by mbrtowc and mbrtoc32. */ 129/* Returns the internal lock used by mbrtowc and mbrtoc32. */
129mtx_t * 130mtx_t *
diff --git a/gl/mbtowc-lock.h b/gl/mbtowc-lock.h
index 2dc22ace..10f7dc7c 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2019-2024 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
@@ -21,7 +21,7 @@
21static inline int 21static inline int
22mbtowc_unlocked (wchar_t *pwc, const char *p, size_t m) 22mbtowc_unlocked (wchar_t *pwc, const char *p, size_t m)
23{ 23{
24 /* Put the hidden internal state of mbtowc into its initial state. 24 /* Put the hidden internal state of mbtowc into an initial state.
25 This is needed at least with glibc, uClibc, and MSVC CRT. 25 This is needed at least with glibc, uClibc, and MSVC CRT.
26 See <https://sourceware.org/bugzilla/show_bug.cgi?id=9674>. */ 26 See <https://sourceware.org/bugzilla/show_bug.cgi?id=9674>. */
27 mbtowc (NULL, NULL, 0); 27 mbtowc (NULL, NULL, 0);
@@ -32,7 +32,7 @@ mbtowc_unlocked (wchar_t *pwc, const char *p, size_t m)
32/* Prohibit renaming this symbol. */ 32/* Prohibit renaming this symbol. */
33#undef gl_get_mbtowc_lock 33#undef gl_get_mbtowc_lock
34 34
35#if GNULIB_MBRTOWC_SINGLE_THREAD 35#if AVOID_ANY_THREADS || GNULIB_MBRTOWC_SINGLE_THREAD
36 36
37/* All uses of this function are in a single thread. No locking needed. */ 37/* All uses of this function are in a single thread. No locking needed. */
38 38
diff --git a/gl/mbtowc.c b/gl/mbtowc.c
index 8d9b06d2..31a2d635 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2011-2024 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 8e955793..67687a8f 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-2023 1/* Copyright (C) 1991, 1993, 1996-1997, 1999-2000, 2003-2004, 2006, 2008-2024
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 97690f2c..0295d7e6 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-2023 Free Software Foundation, Inc. 3# Copyright (C) 2009-2024 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 1fbfc661..f3df58b0 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-2023 Free Software 2 Copyright (C) 1995, 1998, 2001, 2003, 2005, 2009-2024 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
@@ -23,6 +23,11 @@
23 MIN, MAX macro redefinitions on some systems; the workaround is to 23 MIN, MAX macro redefinitions on some systems; the workaround is to
24 #include this file as the last one among the #include list. */ 24 #include this file as the last one among the #include list. */
25 25
26/* This file uses HAVE_MINMAX_IN_LIMITS_H, HAVE_MINMAX_IN_SYS_PARAM_H. */
27#if !_GL_CONFIG_H_INCLUDED
28 #error "Please include config.h first."
29#endif
30
26/* Before we define the following symbols we get the <limits.h> file 31/* Before we define the following symbols we get the <limits.h> file
27 since otherwise we get redefinitions on some systems if <limits.h> is 32 since otherwise we get redefinitions on some systems if <limits.h> is
28 included after this file. Likewise for <sys/param.h>. 33 included after this file. Likewise for <sys/param.h>.
diff --git a/gl/mktime-internal.h b/gl/mktime-internal.h
index 709c36bd..0693aaf1 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-2023 Free Software Foundation, Inc. 2 Copyright 2016-2024 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
diff --git a/gl/mktime.c b/gl/mktime.c
index 94a4320e..c704f415 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 1993-2024 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
@@ -46,6 +46,7 @@
46#include <errno.h> 46#include <errno.h>
47#include <limits.h> 47#include <limits.h>
48#include <stdbool.h> 48#include <stdbool.h>
49#include <stdckdint.h>
49#include <stdlib.h> 50#include <stdlib.h>
50#include <string.h> 51#include <string.h>
51 52
@@ -379,7 +380,7 @@ __mktime_internal (struct tm *tp,
379 /* Invert CONVERT by probing. First assume the same offset as last 380 /* Invert CONVERT by probing. First assume the same offset as last
380 time. */ 381 time. */
381 382
382 INT_SUBTRACT_WRAPV (0, off, &negative_offset_guess); 383 ckd_sub (&negative_offset_guess, 0, off);
383 long_int t0 = ydhms_diff (year, yday, hour, min, sec, 384 long_int t0 = ydhms_diff (year, yday, hour, min, sec,
384 EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0, 385 EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0,
385 negative_offset_guess); 386 negative_offset_guess);
@@ -465,7 +466,7 @@ __mktime_internal (struct tm *tp,
465 for (direction = -1; direction <= 1; direction += 2) 466 for (direction = -1; direction <= 1; direction += 2)
466 { 467 {
467 long_int ot; 468 long_int ot;
468 if (! INT_ADD_WRAPV (t, delta * direction, &ot)) 469 if (! ckd_add (&ot, t, delta * direction))
469 { 470 {
470 struct tm otm; 471 struct tm otm;
471 if (! ranged_convert (convert, &ot, &otm)) 472 if (! ranged_convert (convert, &ot, &otm))
@@ -503,8 +504,8 @@ __mktime_internal (struct tm *tp,
503 /* Set *OFFSET to the low-order bits of T - T0 - NEGATIVE_OFFSET_GUESS. 504 /* Set *OFFSET to the low-order bits of T - T0 - NEGATIVE_OFFSET_GUESS.
504 This is just a heuristic to speed up the next mktime call, and 505 This is just a heuristic to speed up the next mktime call, and
505 correctness is unaffected if integer overflow occurs here. */ 506 correctness is unaffected if integer overflow occurs here. */
506 INT_SUBTRACT_WRAPV (t, t0, offset); 507 ckd_sub (offset, t, t0);
507 INT_SUBTRACT_WRAPV (*offset, negative_offset_guess, offset); 508 ckd_sub (offset, *offset, negative_offset_guess);
508 509
509 if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec) 510 if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec)
510 { 511 {
@@ -513,7 +514,7 @@ __mktime_internal (struct tm *tp,
513 long_int sec_adjustment = sec == 0 && tm.tm_sec == 60; 514 long_int sec_adjustment = sec == 0 && tm.tm_sec == 60;
514 sec_adjustment -= sec; 515 sec_adjustment -= sec;
515 sec_adjustment += sec_requested; 516 sec_adjustment += sec_requested;
516 if (INT_ADD_WRAPV (t, sec_adjustment, &t) 517 if (ckd_add (&t, t, sec_adjustment)
517 || ! (mktime_min <= t && t <= mktime_max)) 518 || ! (mktime_min <= t && t <= mktime_max))
518 { 519 {
519 __set_errno (EOVERFLOW); 520 __set_errno (EOVERFLOW);
diff --git a/gl/mountlist.c b/gl/mountlist.c
index 6d384812..06300d6b 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 1991-1992, 1997-2024 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
@@ -154,11 +154,18 @@
154 154
155/* The results of opendir() in this file are not used with dirfd and fchdir, 155/* The results of opendir() in this file are not used with dirfd and fchdir,
156 therefore save some unnecessary work in fchdir.c. */ 156 therefore save some unnecessary work in fchdir.c. */
157#ifdef GNULIB_defined_opendir 157#ifdef GNULIB_defined_DIR
158# undef DIR
158# undef opendir 159# undef opendir
159#endif
160#ifdef GNULIB_defined_closedir
161# undef closedir 160# undef closedir
161# undef readdir
162#else
163# ifdef GNULIB_defined_opendir
164# undef opendir
165# endif
166# ifdef GNULIB_defined_closedir
167# undef closedir
168# endif
162#endif 169#endif
163 170
164#define ME_DUMMY_0(Fs_name, Fs_type) \ 171#define ME_DUMMY_0(Fs_name, Fs_type) \
@@ -185,11 +192,11 @@
185 we grant an exception to any with "bind" in its list of mount options. 192 we grant an exception to any with "bind" in its list of mount options.
186 I.e., those are *not* dummy entries. */ 193 I.e., those are *not* dummy entries. */
187#ifdef MOUNTED_GETMNTENT1 194#ifdef MOUNTED_GETMNTENT1
188# define ME_DUMMY(Fs_name, Fs_type, Bind) \ 195# define ME_DUMMY(Fs_name, Fs_type, Bind) \
189 (ME_DUMMY_0 (Fs_name, Fs_type) \ 196 (ME_DUMMY_0 (Fs_name, Fs_type) \
190 || (strcmp (Fs_type, "none") == 0 && !Bind)) 197 || (strcmp (Fs_type, "none") == 0 && !Bind))
191#else 198#else
192# define ME_DUMMY(Fs_name, Fs_type) \ 199# define ME_DUMMY(Fs_name, Fs_type) \
193 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0) 200 (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
194#endif 201#endif
195 202
diff --git a/gl/mountlist.h b/gl/mountlist.h
index aed7f887..9728e38b 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-2023 Free Software 3 Copyright (C) 1991-1992, 1998, 2000-2005, 2009-2024 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
@@ -17,9 +17,19 @@
17 along with this program. If not, see <https://www.gnu.org/licenses/>. */ 17 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 18
19#ifndef MOUNTLIST_H_ 19#ifndef MOUNTLIST_H_
20# define MOUNTLIST_H_ 20#define MOUNTLIST_H_
21
22/* This file uses _GL_ATTRIBUTE_MALLOC. */
23#if !_GL_CONFIG_H_INCLUDED
24# error "Please include config.h first."
25#endif
26
27#include <sys/types.h>
28
29#ifdef __cplusplus
30extern "C" {
31#endif
21 32
22# include <sys/types.h>
23 33
24/* A mount table entry. */ 34/* A mount table entry. */
25struct mount_entry 35struct mount_entry
@@ -40,4 +50,9 @@ struct mount_entry *read_file_system_list (bool need_fs_type)
40 _GL_ATTRIBUTE_MALLOC; 50 _GL_ATTRIBUTE_MALLOC;
41void free_mount_entry (struct mount_entry *entry); 51void free_mount_entry (struct mount_entry *entry);
42 52
53
54#ifdef __cplusplus
55}
56#endif
57
43#endif 58#endif
diff --git a/gl/msvc-inval.c b/gl/msvc-inval.c
index c5149a8f..da3fc86a 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2011-2024 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 ed00461f..7aee6e5d 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2011-2024 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
@@ -52,6 +52,11 @@
52 AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [SANE_LIBRARY_HANDLING]) 52 AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [SANE_LIBRARY_HANDLING])
53 */ 53 */
54 54
55/* This file uses HAVE_MSVC_INVALID_PARAMETER_HANDLER. */
56#if !_GL_CONFIG_H_INCLUDED
57 #error "Please include config.h first."
58#endif
59
55#define DEFAULT_HANDLING 0 60#define DEFAULT_HANDLING 0
56#define HAIRY_LIBRARY_HANDLING 1 61#define HAIRY_LIBRARY_HANDLING 1
57#define SANE_LIBRARY_HANDLING 2 62#define SANE_LIBRARY_HANDLING 2
diff --git a/gl/msvc-nothrow.c b/gl/msvc-nothrow.c
index f729fe66..06b35a61 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2011-2024 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 82d3f6a2..121773d1 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2011-2024 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
@@ -25,11 +25,20 @@
25 This file defines wrappers that turn such an invalid parameter notification 25 This file defines wrappers that turn such an invalid parameter notification
26 into an error code. */ 26 into an error code. */
27 27
28/* This file uses HAVE_MSVC_INVALID_PARAMETER_HANDLER. */
29#if !_GL_CONFIG_H_INCLUDED
30 #error "Please include config.h first."
31#endif
32
28#if defined _WIN32 && ! defined __CYGWIN__ 33#if defined _WIN32 && ! defined __CYGWIN__
29 34
30/* Get original declaration of _get_osfhandle. */ 35/* Get original declaration of _get_osfhandle. */
31# include <io.h> 36# include <io.h>
32 37
38# ifdef __cplusplus
39extern "C" {
40# endif
41
33# if HAVE_MSVC_INVALID_PARAMETER_HANDLER 42# if HAVE_MSVC_INVALID_PARAMETER_HANDLER
34 43
35/* Override _get_osfhandle. */ 44/* Override _get_osfhandle. */
@@ -38,6 +47,10 @@ extern intptr_t _gl_nothrow_get_osfhandle (int fd);
38 47
39# endif 48# endif
40 49
50# ifdef __cplusplus
51}
52# endif
53
41#endif 54#endif
42 55
43#endif /* _MSVC_NOTHROW_H */ 56#endif /* _MSVC_NOTHROW_H */
diff --git a/gl/netdb.in.h b/gl/netdb.in.h
index 9549cd73..43409b2f 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2008-2024 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
@@ -36,6 +36,11 @@
36#ifndef _@GUARD_PREFIX@_NETDB_H 36#ifndef _@GUARD_PREFIX@_NETDB_H
37#define _@GUARD_PREFIX@_NETDB_H 37#define _@GUARD_PREFIX@_NETDB_H
38 38
39/* This file uses GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */
40#if !_GL_CONFIG_H_INCLUDED
41 #error "Please include config.h first."
42#endif
43
39/* Get <netdb.h> definitions such as 'socklen_t' on IRIX 6.5 and OSF/1 4.0 and 44/* Get <netdb.h> definitions such as 'socklen_t' on IRIX 6.5 and OSF/1 4.0 and
40 'struct hostent' on MinGW. */ 45 'struct hostent' on MinGW. */
41#include <sys/socket.h> 46#include <sys/socket.h>
diff --git a/gl/netinet_in.in.h b/gl/netinet_in.in.h
index f88923a3..4e9f6f2d 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2007-2024 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 e5cdcd3e..5a248ed8 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2019-2024 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
@@ -18,9 +18,10 @@
18 18
19#include <config.h> 19#include <config.h>
20 20
21/* The option '--disable-threads' explicitly requests no locking. */
21/* When it is known that the gl_get_nl_langinfo_lock function is defined 22/* When it is known that the gl_get_nl_langinfo_lock function is defined
22 by a dependency library, it should not be defined here. */ 23 by a dependency library, it should not be defined here. */
23#if OMIT_NL_LANGINFO_LOCK 24#if AVOID_ANY_THREADS || OMIT_NL_LANGINFO_LOCK
24 25
25/* This declaration is solely to ensure that after preprocessing 26/* This declaration is solely to ensure that after preprocessing
26 this file is never empty. */ 27 this file is never empty. */
@@ -37,14 +38,14 @@ typedef int dummy;
37 38
38/* Macro for exporting a symbol (function, not variable) defined in this file, 39/* Macro for exporting a symbol (function, not variable) defined in this file,
39 when compiled into a shared library. */ 40 when compiled into a shared library. */
40# ifndef DLL_EXPORTED 41# ifndef SHLIB_EXPORTED
41# if HAVE_VISIBILITY 42# if HAVE_VISIBILITY
42 /* Override the effect of the compiler option '-fvisibility=hidden'. */ 43 /* Override the effect of the compiler option '-fvisibility=hidden'. */
43# define DLL_EXPORTED __attribute__((__visibility__("default"))) 44# define SHLIB_EXPORTED __attribute__((__visibility__("default")))
44# elif defined _WIN32 || defined __CYGWIN__ 45# elif defined _WIN32 || defined __CYGWIN__
45# define DLL_EXPORTED __declspec(dllexport) 46# define SHLIB_EXPORTED __declspec(dllexport)
46# else 47# else
47# define DLL_EXPORTED 48# define SHLIB_EXPORTED
48# endif 49# endif
49# endif 50# endif
50 51
@@ -59,7 +60,7 @@ typedef int dummy;
59 because the latter is not guaranteed to be a stable ABI in the future. */ 60 because the latter is not guaranteed to be a stable ABI in the future. */
60 61
61/* Make sure the function gets exported from DLLs. */ 62/* Make sure the function gets exported from DLLs. */
62DLL_EXPORTED CRITICAL_SECTION *gl_get_nl_langinfo_lock (void); 63SHLIB_EXPORTED CRITICAL_SECTION *gl_get_nl_langinfo_lock (void);
63 64
64static glwthread_initguard_t guard = GLWTHREAD_INITGUARD_INIT; 65static glwthread_initguard_t guard = GLWTHREAD_INITGUARD_INIT;
65static CRITICAL_SECTION lock; 66static CRITICAL_SECTION lock;
@@ -96,7 +97,7 @@ gl_get_nl_langinfo_lock (void)
96static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 97static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
97 98
98/* Make sure the function gets exported from shared libraries. */ 99/* Make sure the function gets exported from shared libraries. */
99DLL_EXPORTED pthread_mutex_t *gl_get_nl_langinfo_lock (void); 100SHLIB_EXPORTED pthread_mutex_t *gl_get_nl_langinfo_lock (void);
100 101
101/* Returns the internal lock used by nl_langinfo. */ 102/* Returns the internal lock used by nl_langinfo. */
102pthread_mutex_t * 103pthread_mutex_t *
@@ -123,7 +124,7 @@ atomic_init (void)
123} 124}
124 125
125/* Make sure the function gets exported from shared libraries. */ 126/* Make sure the function gets exported from shared libraries. */
126DLL_EXPORTED mtx_t *gl_get_nl_langinfo_lock (void); 127SHLIB_EXPORTED mtx_t *gl_get_nl_langinfo_lock (void);
127 128
128/* Returns the internal lock used by nl_langinfo. */ 129/* Returns the internal lock used by nl_langinfo. */
129mtx_t * 130mtx_t *
diff --git a/gl/nl_langinfo.c b/gl/nl_langinfo.c
index 131166fd..64ff93b0 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2007-2024 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
@@ -30,7 +30,12 @@
30#endif 30#endif
31 31
32#if REPLACE_NL_LANGINFO && !NL_LANGINFO_MTSAFE 32#if REPLACE_NL_LANGINFO && !NL_LANGINFO_MTSAFE
33# if defined _WIN32 && !defined __CYGWIN__ 33
34# if AVOID_ANY_THREADS
35
36/* The option '--disable-threads' explicitly requests no locking. */
37
38# elif defined _WIN32 && !defined __CYGWIN__
34 39
35# define WIN32_LEAN_AND_MEAN /* avoid including junk */ 40# define WIN32_LEAN_AND_MEAN /* avoid including junk */
36# include <windows.h> 41# include <windows.h>
@@ -51,6 +56,7 @@
51# include <threads.h> 56# include <threads.h>
52 57
53# endif 58# endif
59
54#endif 60#endif
55 61
56/* nl_langinfo() must be multithread-safe. To achieve this without using 62/* nl_langinfo() must be multithread-safe. To achieve this without using
@@ -70,6 +76,8 @@
70static char * 76static char *
71ctype_codeset (void) 77ctype_codeset (void)
72{ 78{
79 /* This function is only used on platforms which don't have uselocale().
80 Therefore we don't need to look at the per-thread locale first, here. */
73 static char result[2 + 10 + 1]; 81 static char result[2 + 10 + 1];
74 char buf[2 + 10 + 1]; 82 char buf[2 + 10 + 1];
75 char locale[SETLOCALE_NULL_MAX]; 83 char locale[SETLOCALE_NULL_MAX];
@@ -184,7 +192,12 @@ nl_langinfo_unlocked (nl_item item)
184/* Prohibit renaming this symbol. */ 192/* Prohibit renaming this symbol. */
185# undef gl_get_nl_langinfo_lock 193# undef gl_get_nl_langinfo_lock
186 194
187# if defined _WIN32 && !defined __CYGWIN__ 195# if AVOID_ANY_THREADS
196
197/* The option '--disable-threads' explicitly requests no locking. */
198# define nl_langinfo_with_lock nl_langinfo_unlocked
199
200# elif defined _WIN32 && !defined __CYGWIN__
188 201
189extern __declspec(dllimport) CRITICAL_SECTION *gl_get_nl_langinfo_lock (void); 202extern __declspec(dllimport) CRITICAL_SECTION *gl_get_nl_langinfo_lock (void);
190 203
@@ -449,7 +462,7 @@ nl_langinfo (nl_item item)
449 { 462 {
450 static char const months[][sizeof "September"] = { 463 static char const months[][sizeof "September"] = {
451 "January", "February", "March", "April", "May", "June", "July", 464 "January", "February", "March", "April", "May", "June", "July",
452 "September", "October", "November", "December" 465 "August", "September", "October", "November", "December"
453 }; 466 };
454 case MON_1: 467 case MON_1:
455 case MON_2: 468 case MON_2:
@@ -513,7 +526,7 @@ nl_langinfo (nl_item item)
513 static char result[12][30]; 526 static char result[12][30];
514 static char const abmonths[][sizeof "Jan"] = { 527 static char const abmonths[][sizeof "Jan"] = {
515 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", 528 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
516 "Sep", "Oct", "Nov", "Dec" 529 "Aug", "Sep", "Oct", "Nov", "Dec"
517 }; 530 };
518 tmm.tm_mon = item - ABMON_1; 531 tmm.tm_mon = item - ABMON_1;
519 if (!strftime (buf, sizeof result[0], "%b", &tmm)) 532 if (!strftime (buf, sizeof result[0], "%b", &tmm))
diff --git a/gl/open.c b/gl/open.c
index 7ec8fdc3..e690c9ea 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2007-2024 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
@@ -38,9 +38,13 @@ orig_open (const char *filename, int flags, mode_t mode)
38} 38}
39 39
40/* Specification. */ 40/* Specification. */
41#ifdef __osf__
41/* Write "fcntl.h" here, not <fcntl.h>, otherwise OSF/1 5.1 DTK cc eliminates 42/* Write "fcntl.h" here, not <fcntl.h>, otherwise OSF/1 5.1 DTK cc eliminates
42 this include because of the preliminary #include <fcntl.h> above. */ 43 this include because of the preliminary #include <fcntl.h> above. */
43#include "fcntl.h" 44# include "fcntl.h"
45#else
46# include <fcntl.h>
47#endif
44 48
45#include "cloexec.h" 49#include "cloexec.h"
46 50
diff --git a/gl/pathmax.h b/gl/pathmax.h
index 0dd8f3bc..d6512c6f 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-2023 Free Software 2 Copyright (C) 1992, 1999, 2001, 2003, 2005, 2009-2024 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
@@ -39,6 +39,11 @@
39 #endif 39 #endif
40 */ 40 */
41 41
42/* This file uses HAVE_SYS_PARAM_H. */
43# if !_GL_CONFIG_H_INCLUDED
44# error "Please include config.h first."
45# endif
46
42# include <unistd.h> 47# include <unistd.h>
43 48
44# include <limits.h> 49# include <limits.h>
diff --git a/gl/printf-args.c b/gl/printf-args.c
index 5e14f654..eb0d2cdc 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-2023 Free Software 2 Copyright (C) 1999, 2002-2003, 2005-2007, 2009-2024 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
@@ -29,6 +29,9 @@
29# include "printf-args.h" 29# include "printf-args.h"
30#endif 30#endif
31 31
32/* Get INT_WIDTH. */
33#include <limits.h>
34
32#ifdef STATIC 35#ifdef STATIC
33STATIC 36STATIC
34#endif 37#endif
@@ -71,6 +74,102 @@ PRINTF_FETCHARGS (va_list args, arguments *a)
71 case TYPE_ULONGLONGINT: 74 case TYPE_ULONGLONGINT:
72 ap->a.a_ulonglongint = va_arg (args, unsigned long long int); 75 ap->a.a_ulonglongint = va_arg (args, unsigned long long int);
73 break; 76 break;
77 case TYPE_INT8_T:
78 #if INT8_WIDTH < INT_WIDTH
79 ap->a.a_int8_t = va_arg (args, /* int8_t */ int);
80 #else
81 ap->a.a_int8_t = va_arg (args, int8_t);
82 #endif
83 break;
84 case TYPE_UINT8_T:
85 #if UINT8_WIDTH < INT_WIDTH
86 ap->a.a_uint8_t = va_arg (args, /* uint8_t */ int);
87 #else
88 ap->a.a_uint8_t = va_arg (args, uint8_t);
89 #endif
90 break;
91 case TYPE_INT16_T:
92 #if INT16_WIDTH < INT_WIDTH
93 ap->a.a_int16_t = va_arg (args, /* int16_t */ int);
94 #else
95 ap->a.a_int16_t = va_arg (args, int16_t);
96 #endif
97 break;
98 case TYPE_UINT16_T:
99 #if UINT16_WIDTH < INT_WIDTH
100 ap->a.a_uint16_t = va_arg (args, /* uint16_t */ int);
101 #else
102 ap->a.a_uint16_t = va_arg (args, uint16_t);
103 #endif
104 break;
105 case TYPE_INT32_T:
106 #if INT32_WIDTH < INT_WIDTH
107 ap->a.a_int32_t = va_arg (args, /* int32_t */ int);
108 #else
109 ap->a.a_int32_t = va_arg (args, int32_t);
110 #endif
111 break;
112 case TYPE_UINT32_T:
113 #if UINT32_WIDTH < INT_WIDTH
114 ap->a.a_uint32_t = va_arg (args, /* uint32_t */ int);
115 #else
116 ap->a.a_uint32_t = va_arg (args, uint32_t);
117 #endif
118 break;
119 case TYPE_INT64_T:
120 ap->a.a_int64_t = va_arg (args, int64_t);
121 break;
122 case TYPE_UINT64_T:
123 ap->a.a_uint64_t = va_arg (args, uint64_t);
124 break;
125 case TYPE_INT_FAST8_T:
126 #if INT_FAST8_WIDTH < INT_WIDTH
127 ap->a.a_int_fast8_t = va_arg (args, /* int_fast8_t */ int);
128 #else
129 ap->a.a_int_fast8_t = va_arg (args, int_fast8_t);
130 #endif
131 break;
132 case TYPE_UINT_FAST8_T:
133 #if UINT_FAST8_WIDTH < INT_WIDTH
134 ap->a.a_uint_fast8_t = va_arg (args, /* uint_fast8_t */ int);
135 #else
136 ap->a.a_uint_fast8_t = va_arg (args, uint_fast8_t);
137 #endif
138 break;
139 case TYPE_INT_FAST16_T:
140 #if INT_FAST16_WIDTH < INT_WIDTH
141 ap->a.a_int_fast16_t = va_arg (args, /* int_fast16_t */ int);
142 #else
143 ap->a.a_int_fast16_t = va_arg (args, int_fast16_t);
144 #endif
145 break;
146 case TYPE_UINT_FAST16_T:
147 #if UINT_FAST16_WIDTH < INT_WIDTH
148 ap->a.a_uint_fast16_t = va_arg (args, /* uint_fast16_t */ int);
149 #else
150 ap->a.a_uint_fast16_t = va_arg (args, uint_fast16_t);
151 #endif
152 break;
153 case TYPE_INT_FAST32_T:
154 #if INT_FAST32_WIDTH < INT_WIDTH
155 ap->a.a_int_fast32_t = va_arg (args, /* int_fast32_t */ int);
156 #else
157 ap->a.a_int_fast32_t = va_arg (args, int_fast32_t);
158 #endif
159 break;
160 case TYPE_UINT_FAST32_T:
161 #if UINT_FAST32_WIDTH < INT_WIDTH
162 ap->a.a_uint_fast32_t = va_arg (args, /* uint_fast32_t */ int);
163 #else
164 ap->a.a_uint_fast32_t = va_arg (args, uint_fast32_t);
165 #endif
166 break;
167 case TYPE_INT_FAST64_T:
168 ap->a.a_int_fast64_t = va_arg (args, int_fast64_t);
169 break;
170 case TYPE_UINT_FAST64_T:
171 ap->a.a_uint_fast64_t = va_arg (args, uint_fast64_t);
172 break;
74 case TYPE_DOUBLE: 173 case TYPE_DOUBLE:
75 ap->a.a_double = va_arg (args, double); 174 ap->a.a_double = va_arg (args, double);
76 break; 175 break;
@@ -136,6 +235,30 @@ PRINTF_FETCHARGS (va_list args, arguments *a)
136 case TYPE_COUNT_LONGLONGINT_POINTER: 235 case TYPE_COUNT_LONGLONGINT_POINTER:
137 ap->a.a_count_longlongint_pointer = va_arg (args, long long int *); 236 ap->a.a_count_longlongint_pointer = va_arg (args, long long int *);
138 break; 237 break;
238 case TYPE_COUNT_INT8_T_POINTER:
239 ap->a.a_count_int8_t_pointer = va_arg (args, int8_t *);
240 break;
241 case TYPE_COUNT_INT16_T_POINTER:
242 ap->a.a_count_int16_t_pointer = va_arg (args, int16_t *);
243 break;
244 case TYPE_COUNT_INT32_T_POINTER:
245 ap->a.a_count_int32_t_pointer = va_arg (args, int32_t *);
246 break;
247 case TYPE_COUNT_INT64_T_POINTER:
248 ap->a.a_count_int64_t_pointer = va_arg (args, int64_t *);
249 break;
250 case TYPE_COUNT_INT_FAST8_T_POINTER:
251 ap->a.a_count_int_fast8_t_pointer = va_arg (args, int_fast8_t *);
252 break;
253 case TYPE_COUNT_INT_FAST16_T_POINTER:
254 ap->a.a_count_int_fast16_t_pointer = va_arg (args, int_fast16_t *);
255 break;
256 case TYPE_COUNT_INT_FAST32_T_POINTER:
257 ap->a.a_count_int_fast32_t_pointer = va_arg (args, int_fast32_t *);
258 break;
259 case TYPE_COUNT_INT_FAST64_T_POINTER:
260 ap->a.a_count_int_fast64_t_pointer = va_arg (args, int_fast64_t *);
261 break;
139#if ENABLE_UNISTDIO 262#if ENABLE_UNISTDIO
140 /* The unistdio extensions. */ 263 /* The unistdio extensions. */
141 case TYPE_U8_STRING: 264 case TYPE_U8_STRING:
diff --git a/gl/printf-args.h b/gl/printf-args.h
index f303cb19..9b80bb39 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-2023 Free Software 2 Copyright (C) 1999, 2002-2003, 2006-2007, 2011-2024 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
@@ -41,6 +41,9 @@
41# include <wchar.h> 41# include <wchar.h>
42#endif 42#endif
43 43
44/* Get intN_t, uintN_t, intN_fast_t, uintN_fast_t. */
45#include <stdint.h>
46
44/* Get va_list. */ 47/* Get va_list. */
45#include <stdarg.h> 48#include <stdarg.h>
46 49
@@ -59,6 +62,26 @@ typedef enum
59 TYPE_ULONGINT, 62 TYPE_ULONGINT,
60 TYPE_LONGLONGINT, 63 TYPE_LONGLONGINT,
61 TYPE_ULONGLONGINT, 64 TYPE_ULONGLONGINT,
65 /* According to ISO C 23 § 7.23.6.1, "all exact-width integer types",
66 "all minimum-width integer types", and "all fastest minimum-width integer
67 types" defined in <stdint.h> should be supported. But for portability
68 between platforms, we support only those with N = 8, 16, 32, 64. */
69 TYPE_INT8_T,
70 TYPE_UINT8_T,
71 TYPE_INT16_T,
72 TYPE_UINT16_T,
73 TYPE_INT32_T,
74 TYPE_UINT32_T,
75 TYPE_INT64_T,
76 TYPE_UINT64_T,
77 TYPE_INT_FAST8_T,
78 TYPE_UINT_FAST8_T,
79 TYPE_INT_FAST16_T,
80 TYPE_UINT_FAST16_T,
81 TYPE_INT_FAST32_T,
82 TYPE_UINT_FAST32_T,
83 TYPE_INT_FAST64_T,
84 TYPE_UINT_FAST64_T,
62 TYPE_DOUBLE, 85 TYPE_DOUBLE,
63 TYPE_LONGDOUBLE, 86 TYPE_LONGDOUBLE,
64 TYPE_CHAR, 87 TYPE_CHAR,
@@ -74,7 +97,15 @@ typedef enum
74 TYPE_COUNT_SHORT_POINTER, 97 TYPE_COUNT_SHORT_POINTER,
75 TYPE_COUNT_INT_POINTER, 98 TYPE_COUNT_INT_POINTER,
76 TYPE_COUNT_LONGINT_POINTER, 99 TYPE_COUNT_LONGINT_POINTER,
77 TYPE_COUNT_LONGLONGINT_POINTER 100 TYPE_COUNT_LONGLONGINT_POINTER,
101 TYPE_COUNT_INT8_T_POINTER,
102 TYPE_COUNT_INT16_T_POINTER,
103 TYPE_COUNT_INT32_T_POINTER,
104 TYPE_COUNT_INT64_T_POINTER,
105 TYPE_COUNT_INT_FAST8_T_POINTER,
106 TYPE_COUNT_INT_FAST16_T_POINTER,
107 TYPE_COUNT_INT_FAST32_T_POINTER,
108 TYPE_COUNT_INT_FAST64_T_POINTER
78#if ENABLE_UNISTDIO 109#if ENABLE_UNISTDIO
79 /* The unistdio extensions. */ 110 /* The unistdio extensions. */
80, TYPE_U8_STRING 111, TYPE_U8_STRING
@@ -99,7 +130,23 @@ typedef struct
99 unsigned long int a_ulongint; 130 unsigned long int a_ulongint;
100 long long int a_longlongint; 131 long long int a_longlongint;
101 unsigned long long int a_ulonglongint; 132 unsigned long long int a_ulonglongint;
102 float a_float; 133 int8_t a_int8_t;
134 uint8_t a_uint8_t;
135 int16_t a_int16_t;
136 uint16_t a_uint16_t;
137 int32_t a_int32_t;
138 uint32_t a_uint32_t;
139 int64_t a_int64_t;
140 uint64_t a_uint64_t;
141 int_fast8_t a_int_fast8_t;
142 uint_fast8_t a_uint_fast8_t;
143 int_fast16_t a_int_fast16_t;
144 uint_fast16_t a_uint_fast16_t;
145 int_fast32_t a_int_fast32_t;
146 uint_fast32_t a_uint_fast32_t;
147 int_fast64_t a_int_fast64_t;
148 uint_fast64_t a_uint_fast64_t;
149 float a_float; /* unused */
103 double a_double; 150 double a_double;
104 long double a_longdouble; 151 long double a_longdouble;
105 int a_char; 152 int a_char;
@@ -116,6 +163,14 @@ typedef struct
116 int * a_count_int_pointer; 163 int * a_count_int_pointer;
117 long int * a_count_longint_pointer; 164 long int * a_count_longint_pointer;
118 long long int * a_count_longlongint_pointer; 165 long long int * a_count_longlongint_pointer;
166 int8_t * a_count_int8_t_pointer;
167 int16_t * a_count_int16_t_pointer;
168 int32_t * a_count_int32_t_pointer;
169 int64_t * a_count_int64_t_pointer;
170 int_fast8_t * a_count_int_fast8_t_pointer;
171 int_fast16_t * a_count_int_fast16_t_pointer;
172 int_fast32_t * a_count_int_fast32_t_pointer;
173 int_fast64_t * a_count_int_fast64_t_pointer;
119#if ENABLE_UNISTDIO 174#if ENABLE_UNISTDIO
120 /* The unistdio extensions. */ 175 /* The unistdio extensions. */
121 const uint8_t * a_u8_string; 176 const uint8_t * a_u8_string;
diff --git a/gl/printf-parse.c b/gl/printf-parse.c
index 3040749a..a33e27a0 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 1999-2000, 2002-2003, 2006-2024 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
@@ -326,226 +326,320 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
326 arg_type type; 326 arg_type type;
327 327
328 /* Parse argument type/size specifiers. */ 328 /* Parse argument type/size specifiers. */
329 { 329 /* Relevant for the conversion characters d, i. */
330 int flags = 0; 330 arg_type signed_type = TYPE_INT;
331 331 /* Relevant for the conversion characters b, o, u, x, X. */
332 for (;;) 332 arg_type unsigned_type = TYPE_UINT;
333 { 333 /* Relevant for the conversion characters n. */
334 if (*cp == 'h') 334 arg_type pointer_type = TYPE_COUNT_INT_POINTER;
335 { 335 /* Relevant for the conversion characters a, A, e, E, f, F, g, G. */
336 flags |= (1 << (flags & 1)); 336 arg_type floatingpoint_type = TYPE_DOUBLE;
337 cp++; 337
338 } 338 if (*cp == 'h')
339 else if (*cp == 'L') 339 {
340 { 340 if (cp[1] == 'h')
341 flags |= 4; 341 {
342 cp++; 342 signed_type = TYPE_SCHAR;
343 } 343 unsigned_type = TYPE_UCHAR;
344 else if (*cp == 'l') 344 pointer_type = TYPE_COUNT_SCHAR_POINTER;
345 { 345 cp += 2;
346 flags += 8; 346 }
347 cp++; 347 else
348 } 348 {
349 else if (*cp == 'j') 349 signed_type = TYPE_SHORT;
350 { 350 unsigned_type = TYPE_USHORT;
351 if (sizeof (intmax_t) > sizeof (long)) 351 pointer_type = TYPE_COUNT_SHORT_POINTER;
352 { 352 cp++;
353 /* intmax_t = long long */ 353 }
354 flags += 16; 354 }
355 } 355 else if (*cp == 'l')
356 else if (sizeof (intmax_t) > sizeof (int)) 356 {
357 { 357 if (cp[1] == 'l')
358 /* intmax_t = long */ 358 {
359 flags += 8; 359 signed_type = TYPE_LONGLONGINT;
360 } 360 unsigned_type = TYPE_ULONGLONGINT;
361 cp++; 361 pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
362 } 362 /* For backward compatibility only. */
363 else if (*cp == 'z' || *cp == 'Z') 363 floatingpoint_type = TYPE_LONGDOUBLE;
364 { 364 cp += 2;
365 /* 'z' is standardized in ISO C 99, but glibc uses 'Z' 365 }
366 because the warning facility in gcc-2.95.2 understands 366 else
367 only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */ 367 {
368 if (sizeof (size_t) > sizeof (long)) 368 signed_type = TYPE_LONGINT;
369 { 369 unsigned_type = TYPE_ULONGINT;
370 /* size_t = long long */ 370 pointer_type = TYPE_COUNT_LONGINT_POINTER;
371 flags += 16; 371 cp++;
372 } 372 }
373 else if (sizeof (size_t) > sizeof (int)) 373 }
374 { 374 else if (*cp == 'j')
375 /* size_t = long */ 375 {
376 flags += 8; 376 if (sizeof (intmax_t) > sizeof (long))
377 } 377 {
378 cp++; 378 /* intmax_t = long long */
379 } 379 signed_type = TYPE_LONGLONGINT;
380 else if (*cp == 't') 380 unsigned_type = TYPE_ULONGLONGINT;
381 { 381 pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
382 if (sizeof (ptrdiff_t) > sizeof (long)) 382 /* For backward compatibility only. */
383 { 383 floatingpoint_type = TYPE_LONGDOUBLE;
384 /* ptrdiff_t = long long */ 384 }
385 flags += 16; 385 else if (sizeof (intmax_t) > sizeof (int))
386 } 386 {
387 else if (sizeof (ptrdiff_t) > sizeof (int)) 387 /* intmax_t = long */
388 { 388 signed_type = TYPE_LONGINT;
389 /* ptrdiff_t = long */ 389 unsigned_type = TYPE_ULONGINT;
390 flags += 8; 390 pointer_type = TYPE_COUNT_LONGINT_POINTER;
391 } 391 }
392 cp++; 392 cp++;
393 } 393 }
394 else if (*cp == 'z' || *cp == 'Z')
395 {
396 /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
397 because the warning facility in gcc-2.95.2 understands
398 only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */
399 if (sizeof (size_t) > sizeof (long))
400 {
401 /* size_t = unsigned long long */
402 signed_type = TYPE_LONGLONGINT;
403 unsigned_type = TYPE_ULONGLONGINT;
404 pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
405 /* For backward compatibility only. */
406 floatingpoint_type = TYPE_LONGDOUBLE;
407 }
408 else if (sizeof (size_t) > sizeof (int))
409 {
410 /* size_t = unsigned long */
411 signed_type = TYPE_LONGINT;
412 unsigned_type = TYPE_ULONGINT;
413 pointer_type = TYPE_COUNT_LONGINT_POINTER;
414 }
415 cp++;
416 }
417 else if (*cp == 't')
418 {
419 if (sizeof (ptrdiff_t) > sizeof (long))
420 {
421 /* ptrdiff_t = long long */
422 signed_type = TYPE_LONGLONGINT;
423 unsigned_type = TYPE_ULONGLONGINT;
424 pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
425 /* For backward compatibility only. */
426 floatingpoint_type = TYPE_LONGDOUBLE;
427 }
428 else if (sizeof (ptrdiff_t) > sizeof (int))
429 {
430 /* ptrdiff_t = long */
431 signed_type = TYPE_LONGINT;
432 unsigned_type = TYPE_ULONGINT;
433 pointer_type = TYPE_COUNT_LONGINT_POINTER;
434 }
435 cp++;
436 }
437 else if (*cp == 'w')
438 {
439 /* wN and wfN are standardized in ISO C 23. */
440 if (cp[1] == 'f')
441 {
442 if (cp[2] == '8')
443 {
444 signed_type = TYPE_INT_FAST8_T;
445 unsigned_type = TYPE_UINT_FAST8_T;
446 pointer_type = TYPE_COUNT_INT_FAST8_T_POINTER;
447 cp += 3;
448 }
449 else if (cp[2] == '1' && cp[3] == '6')
450 {
451 signed_type = TYPE_INT_FAST16_T;
452 unsigned_type = TYPE_UINT_FAST16_T;
453 pointer_type = TYPE_COUNT_INT_FAST16_T_POINTER;
454 cp += 4;
455 }
456 else if (cp[2] == '3' && cp[3] == '2')
457 {
458 signed_type = TYPE_INT_FAST32_T;
459 unsigned_type = TYPE_UINT_FAST32_T;
460 pointer_type = TYPE_COUNT_INT_FAST32_T_POINTER;
461 cp += 4;
462 }
463 else if (cp[2] == '6' && cp[3] == '4')
464 {
465 signed_type = TYPE_INT_FAST64_T;
466 unsigned_type = TYPE_UINT_FAST64_T;
467 pointer_type = TYPE_COUNT_INT_FAST64_T_POINTER;
468 cp += 4;
469 }
470 }
471 else
472 {
473 if (cp[1] == '8')
474 {
475 signed_type = TYPE_INT8_T;
476 unsigned_type = TYPE_UINT8_T;
477 pointer_type = TYPE_COUNT_INT8_T_POINTER;
478 cp += 2;
479 }
480 else if (cp[1] == '1' && cp[2] == '6')
481 {
482 signed_type = TYPE_INT16_T;
483 unsigned_type = TYPE_UINT16_T;
484 pointer_type = TYPE_COUNT_INT16_T_POINTER;
485 cp += 3;
486 }
487 else if (cp[1] == '3' && cp[2] == '2')
488 {
489 signed_type = TYPE_INT32_T;
490 unsigned_type = TYPE_UINT32_T;
491 pointer_type = TYPE_COUNT_INT32_T_POINTER;
492 cp += 3;
493 }
494 else if (cp[1] == '6' && cp[2] == '4')
495 {
496 signed_type = TYPE_INT64_T;
497 unsigned_type = TYPE_UINT64_T;
498 pointer_type = TYPE_COUNT_INT64_T_POINTER;
499 cp += 3;
500 }
501 }
502 }
503 else if (*cp == 'L')
504 {
505 signed_type = TYPE_LONGLONGINT;
506 unsigned_type = TYPE_ULONGLONGINT;
507 pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
508 floatingpoint_type = TYPE_LONGDOUBLE;
509 cp++;
510 }
394#if defined __APPLE__ && defined __MACH__ 511#if defined __APPLE__ && defined __MACH__
395 /* On Mac OS X 10.3, PRIdMAX is defined as "qd". 512 /* On Mac OS X 10.3, PRIdMAX is defined as "qd".
396 We cannot change it to "lld" because PRIdMAX must also 513 We cannot change it to "lld" because PRIdMAX must also
397 be understood by the system's printf routines. */ 514 be understood by the system's printf routines. */
398 else if (*cp == 'q') 515 else if (*cp == 'q')
399 { 516 {
400 if (64 / 8 > sizeof (long)) 517 if (64 / 8 > sizeof (long))
401 { 518 {
402 /* int64_t = long long */ 519 /* int64_t = long long */
403 flags += 16; 520 signed_type = TYPE_LONGLONGINT;
404 } 521 unsigned_type = TYPE_ULONGLONGINT;
405 else 522 pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
406 { 523 /* For backward compatibility only. */
407 /* int64_t = long */ 524 floatingpoint_type = TYPE_LONGDOUBLE;
408 flags += 8; 525 }
409 } 526 else
410 cp++; 527 {
411 } 528 /* int64_t = long */
529 signed_type = TYPE_LONGINT;
530 unsigned_type = TYPE_ULONGINT;
531 pointer_type = TYPE_COUNT_LONGINT_POINTER;
532 }
533 cp++;
534 }
412#endif 535#endif
413#if defined _WIN32 && ! defined __CYGWIN__ 536#if defined _WIN32 && ! defined __CYGWIN__
414 /* On native Windows, PRIdMAX is defined as "I64d". 537 /* On native Windows, PRIdMAX is defined as "I64d".
415 We cannot change it to "lld" because PRIdMAX must also 538 We cannot change it to "lld" because PRIdMAX must also
416 be understood by the system's printf routines. */ 539 be understood by the system's printf routines. */
417 else if (*cp == 'I' && cp[1] == '6' && cp[2] == '4') 540 else if (*cp == 'I' && cp[1] == '6' && cp[2] == '4')
418 { 541 {
419 if (64 / 8 > sizeof (long)) 542 if (64 / 8 > sizeof (long))
420 { 543 {
421 /* __int64 = long long */ 544 /* __int64_t = long long */
422 flags += 16; 545 signed_type = TYPE_LONGLONGINT;
423 } 546 unsigned_type = TYPE_ULONGLONGINT;
424 else 547 pointer_type = TYPE_COUNT_LONGLONGINT_POINTER;
425 { 548 /* For backward compatibility only. */
426 /* __int64 = long */ 549 floatingpoint_type = TYPE_LONGDOUBLE;
427 flags += 8; 550 }
428 } 551 else
429 cp += 3; 552 {
430 } 553 /* __int64_t = long */
554 signed_type = TYPE_LONGINT;
555 unsigned_type = TYPE_ULONGINT;
556 pointer_type = TYPE_COUNT_LONGINT_POINTER;
557 }
558 cp += 3;
559 }
431#endif 560#endif
432 else 561 (void) pointer_type;
433 break;
434 }
435 562
436 /* Read the conversion character. */ 563 /* Read the conversion character. */
437 c = *cp++; 564 c = *cp++;
438 switch (c) 565 switch (c)
439 { 566 {
440 case 'd': case 'i': 567 case 'd': case 'i':
441 /* If 'long long' is larger than 'long': */ 568 type = signed_type;
442 if (flags >= 16 || (flags & 4)) 569 break;
443 type = TYPE_LONGLONGINT; 570 case 'b': case 'o': case 'u': case 'x': case 'X':
444 else 571 #if SUPPORT_GNU_PRINTF_DIRECTIVES \
445 /* If 'long long' is the same as 'long', we parse "lld" into 572 || (__GLIBC__ + (__GLIBC_MINOR__ >= 35) > 2)
446 TYPE_LONGINT. */ 573 case 'B':
447 if (flags >= 8) 574 #endif
448 type = TYPE_LONGINT; 575 type = unsigned_type;
449 else if (flags & 2) 576 break;
450 type = TYPE_SCHAR; 577 case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
451 else if (flags & 1) 578 case 'a': case 'A':
452 type = TYPE_SHORT; 579 type = floatingpoint_type;
453 else 580 break;
454 type = TYPE_INT; 581 case 'c':
455 break; 582 if (signed_type == TYPE_LONGINT
456 case 'o': case 'u': case 'x': case 'X': 583 /* For backward compatibility only. */
457 /* If 'unsigned long long' is larger than 'unsigned long': */ 584 || signed_type == TYPE_LONGLONGINT)
458 if (flags >= 16 || (flags & 4))
459 type = TYPE_ULONGLONGINT;
460 else
461 /* If 'unsigned long long' is the same as 'unsigned long', we
462 parse "llu" into TYPE_ULONGINT. */
463 if (flags >= 8)
464 type = TYPE_ULONGINT;
465 else if (flags & 2)
466 type = TYPE_UCHAR;
467 else if (flags & 1)
468 type = TYPE_USHORT;
469 else
470 type = TYPE_UINT;
471 break;
472 case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
473 case 'a': case 'A':
474 if (flags >= 16 || (flags & 4))
475 type = TYPE_LONGDOUBLE;
476 else
477 type = TYPE_DOUBLE;
478 break;
479 case 'c':
480 if (flags >= 8)
481#if HAVE_WINT_T 585#if HAVE_WINT_T
482 type = TYPE_WIDE_CHAR; 586 type = TYPE_WIDE_CHAR;
483#else 587#else
484 goto error; 588 goto error;
485#endif 589#endif
486 else 590 else
487 type = TYPE_CHAR; 591 type = TYPE_CHAR;
488 break; 592 break;
489#if HAVE_WINT_T 593#if HAVE_WINT_T
490 case 'C': 594 case 'C':
491 type = TYPE_WIDE_CHAR; 595 type = TYPE_WIDE_CHAR;
492 c = 'c'; 596 c = 'c';
493 break; 597 break;
494#endif 598#endif
495 case 's': 599 case 's':
496 if (flags >= 8) 600 if (signed_type == TYPE_LONGINT
601 /* For backward compatibility only. */
602 || signed_type == TYPE_LONGLONGINT)
497#if HAVE_WCHAR_T 603#if HAVE_WCHAR_T
498 type = TYPE_WIDE_STRING; 604 type = TYPE_WIDE_STRING;
499#else 605#else
500 goto error; 606 goto error;
501#endif 607#endif
502 else 608 else
503 type = TYPE_STRING; 609 type = TYPE_STRING;
504 break; 610 break;
505#if HAVE_WCHAR_T 611#if HAVE_WCHAR_T
506 case 'S': 612 case 'S':
507 type = TYPE_WIDE_STRING; 613 type = TYPE_WIDE_STRING;
508 c = 's'; 614 c = 's';
509 break; 615 break;
616#endif
617 case 'p':
618 type = TYPE_POINTER;
619 break;
620#if NEED_PRINTF_WITH_N_DIRECTIVE
621 case 'n':
622 type = pointer_type;
623 break;
510#endif 624#endif
511 case 'p':
512 type = TYPE_POINTER;
513 break;
514 case 'n':
515 /* If 'long long' is larger than 'long': */
516 if (flags >= 16 || (flags & 4))
517 type = TYPE_COUNT_LONGLONGINT_POINTER;
518 else
519 /* If 'long long' is the same as 'long', we parse "lln" into
520 TYPE_COUNT_LONGINT_POINTER. */
521 if (flags >= 8)
522 type = TYPE_COUNT_LONGINT_POINTER;
523 else if (flags & 2)
524 type = TYPE_COUNT_SCHAR_POINTER;
525 else if (flags & 1)
526 type = TYPE_COUNT_SHORT_POINTER;
527 else
528 type = TYPE_COUNT_INT_POINTER;
529 break;
530#if ENABLE_UNISTDIO 625#if ENABLE_UNISTDIO
531 /* The unistdio extensions. */ 626 /* The unistdio extensions. */
532 case 'U': 627 case 'U':
533 if (flags >= 16) 628 if (signed_type == TYPE_LONGLONGINT)
534 type = TYPE_U32_STRING; 629 type = TYPE_U32_STRING;
535 else if (flags >= 8) 630 else if (signed_type == TYPE_LONGINT)
536 type = TYPE_U16_STRING; 631 type = TYPE_U16_STRING;
537 else 632 else
538 type = TYPE_U8_STRING; 633 type = TYPE_U8_STRING;
539 break; 634 break;
540#endif 635#endif
541 case '%': 636 case '%':
542 type = TYPE_NONE; 637 type = TYPE_NONE;
543 break; 638 break;
544 default: 639 default:
545 /* Unknown conversion character. */ 640 /* Unknown conversion character. */
546 goto error; 641 goto error;
547 } 642 }
548 }
549 643
550 if (type != TYPE_NONE) 644 if (type != TYPE_NONE)
551 { 645 {
diff --git a/gl/printf-parse.h b/gl/printf-parse.h
index 1f86e32c..949b8754 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-2023 Free Software 2 Copyright (C) 1999, 2002-2003, 2005, 2007, 2010-2024 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
@@ -61,7 +61,7 @@ typedef struct
61 const char* precision_start; 61 const char* precision_start;
62 const char* precision_end; 62 const char* precision_end;
63 size_t precision_arg_index; 63 size_t precision_arg_index;
64 char conversion; /* d i o u x X f F e E g G a A c s p n U % but not C S */ 64 char conversion; /* d i b B o u x X f F e E g G a A c s p n U % but not C S */
65 size_t arg_index; 65 size_t arg_index;
66} 66}
67char_directive; 67char_directive;
@@ -91,7 +91,7 @@ typedef struct
91 const uint8_t* precision_start; 91 const uint8_t* precision_start;
92 const uint8_t* precision_end; 92 const uint8_t* precision_end;
93 size_t precision_arg_index; 93 size_t precision_arg_index;
94 uint8_t conversion; /* d i o u x X f F e E g G a A c s p n U % but not C S */ 94 uint8_t conversion; /* d i b B o u x X f F e E g G a A c s p n U % but not C S */
95 size_t arg_index; 95 size_t arg_index;
96} 96}
97u8_directive; 97u8_directive;
@@ -119,7 +119,7 @@ typedef struct
119 const uint16_t* precision_start; 119 const uint16_t* precision_start;
120 const uint16_t* precision_end; 120 const uint16_t* precision_end;
121 size_t precision_arg_index; 121 size_t precision_arg_index;
122 uint16_t conversion; /* d i o u x X f F e E g G a A c s p n U % but not C S */ 122 uint16_t conversion; /* d i b B o u x X f F e E g G a A c s p n U % but not C S */
123 size_t arg_index; 123 size_t arg_index;
124} 124}
125u16_directive; 125u16_directive;
@@ -147,7 +147,7 @@ typedef struct
147 const uint32_t* precision_start; 147 const uint32_t* precision_start;
148 const uint32_t* precision_end; 148 const uint32_t* precision_end;
149 size_t precision_arg_index; 149 size_t precision_arg_index;
150 uint32_t conversion; /* d i o u x X f F e E g G a A c s p n U % but not C S */ 150 uint32_t conversion; /* d i b B o u x X f F e E g G a A c s p n U % but not C S */
151 size_t arg_index; 151 size_t arg_index;
152} 152}
153u32_directive; 153u32_directive;
diff --git a/gl/realloc.c b/gl/realloc.c
index 1063eb09..05731396 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-2023 Free Software 3 Copyright (C) 1997, 2003-2004, 2006-2007, 2009-2024 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/reallocarray.c b/gl/reallocarray.c
index 8c99250f..09711a0e 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2017-2024 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/regcomp.c b/gl/regcomp.c
index 89478396..696cf813 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2002-2024 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
@@ -905,7 +905,7 @@ init_word_char (re_dfa_t *dfa)
905 bitset_word_t bits3 = 0x07fffffe; 905 bitset_word_t bits3 = 0x07fffffe;
906 if (BITSET_WORD_BITS == 64) 906 if (BITSET_WORD_BITS == 64)
907 { 907 {
908 /* Pacify gcc -Woverflow on 32-bit platformns. */ 908 /* Pacify gcc -Woverflow on 32-bit platforms. */
909 dfa->word_char[0] = bits1 << 31 << 1 | bits0; 909 dfa->word_char[0] = bits1 << 31 << 1 | bits0;
910 dfa->word_char[1] = bits3 << 31 << 1 | bits2; 910 dfa->word_char[1] = bits3 << 31 << 1 | bits2;
911 i = 2; 911 i = 2;
diff --git a/gl/regex.c b/gl/regex.c
index 3beb0deb..4b1a6ed6 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2002-2024 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
@@ -26,10 +26,6 @@
26# pragma GCC diagnostic ignored "-Wsuggest-attribute=pure" 26# pragma GCC diagnostic ignored "-Wsuggest-attribute=pure"
27# pragma GCC diagnostic ignored "-Wvla" 27# pragma GCC diagnostic ignored "-Wvla"
28# endif 28# endif
29# if __GNUC_PREREQ (4, 3)
30# pragma GCC diagnostic ignored "-Wold-style-definition"
31# pragma GCC diagnostic ignored "-Wtype-limits"
32# endif
33#endif 29#endif
34 30
35/* Make sure no one compiles this code with a C++ compiler. */ 31/* Make sure no one compiles this code with a C++ compiler. */
diff --git a/gl/regex.h b/gl/regex.h
index 9ef0252f..ccf40ceb 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 1985, 1989-2024 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
diff --git a/gl/regex_internal.c b/gl/regex_internal.c
index 998a19b7..8cd096eb 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2002-2024 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_internal.h b/gl/regex_internal.h
index 149ec2e8..6165cb17 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2002-2024 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
@@ -29,6 +29,7 @@
29#include <locale.h> 29#include <locale.h>
30#include <wchar.h> 30#include <wchar.h>
31#include <wctype.h> 31#include <wctype.h>
32#include <stdckdint.h>
32#include <stdint.h> 33#include <stdint.h>
33 34
34#ifndef _LIBC 35#ifndef _LIBC
@@ -150,9 +151,6 @@
150 as some non-GCC platforms lack them, an issue when this code is 151 as some non-GCC platforms lack them, an issue when this code is
151 used in Gnulib. */ 152 used in Gnulib. */
152 153
153#ifndef SSIZE_MAX
154# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
155#endif
156#ifndef ULONG_WIDTH 154#ifndef ULONG_WIDTH
157# define ULONG_WIDTH REGEX_UINTEGER_WIDTH (ULONG_MAX) 155# define ULONG_WIDTH REGEX_UINTEGER_WIDTH (ULONG_MAX)
158/* The number of usable bits in an unsigned integer type with maximum 156/* The number of usable bits in an unsigned integer type with maximum
@@ -822,7 +820,7 @@ re_string_elem_size_at (const re_string_t *pstr, Idx idx)
822} 820}
823 821
824#ifdef _LIBC 822#ifdef _LIBC
825# if __GNUC__ >= 7 823# if __glibc_has_attribute (__fallthrough__)
826# define FALLTHROUGH __attribute__ ((__fallthrough__)) 824# define FALLTHROUGH __attribute__ ((__fallthrough__))
827# else 825# else
828# define FALLTHROUGH ((void) 0) 826# define FALLTHROUGH ((void) 0)
diff --git a/gl/regexec.c b/gl/regexec.c
index 13e0349e..9f065dfa 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2002-2024 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
@@ -324,7 +324,7 @@ re_search_2_stub (struct re_pattern_buffer *bufp, const char *string1,
324 char *s = NULL; 324 char *s = NULL;
325 325
326 if (__glibc_unlikely ((length1 < 0 || length2 < 0 || stop < 0 326 if (__glibc_unlikely ((length1 < 0 || length2 < 0 || stop < 0
327 || INT_ADD_WRAPV (length1, length2, &len)))) 327 || ckd_add (&len, length1, length2))))
328 return -2; 328 return -2;
329 329
330 /* Concatenate the strings. */ 330 /* Concatenate the strings. */
diff --git a/gl/setenv.c b/gl/setenv.c
index f0b88996..9e2e9e2f 100644
--- a/gl/setenv.c
+++ b/gl/setenv.c
@@ -1,4 +1,4 @@
1/* Copyright (C) 1992, 1995-2003, 2005-2023 Free Software Foundation, Inc. 1/* Copyright (C) 1992, 1995-2003, 2005-2024 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
@@ -82,6 +82,7 @@ typedef int (*compar_fn_t) (const void *, const void *);
82static void *known_values; 82static void *known_values;
83 83
84# define KNOWN_VALUE(Str) \ 84# define KNOWN_VALUE(Str) \
85 __extension__ \
85 ({ \ 86 ({ \
86 void *value = tfind (Str, &known_values, (compar_fn_t) strcmp); \ 87 void *value = tfind (Str, &known_values, (compar_fn_t) strcmp); \
87 value != NULL ? *(char **) value : NULL; \ 88 value != NULL ? *(char **) value : NULL; \
@@ -375,6 +376,11 @@ rpl_setenv (const char *name, const char *value, int replace)
375 int saved_errno; 376 int saved_errno;
376 size_t len = strlen (value); 377 size_t len = strlen (value);
377 tmp = malloca (len + 2); 378 tmp = malloca (len + 2);
379 if (tmp == NULL)
380 {
381 errno = ENOMEM;
382 return -1;
383 }
378 /* Since leading '=' is eaten, double it up. */ 384 /* Since leading '=' is eaten, double it up. */
379 *tmp = '='; 385 *tmp = '=';
380 memcpy (tmp + 1, value, len + 1); 386 memcpy (tmp + 1, value, len + 1);
diff --git a/gl/setlocale-lock.c b/gl/setlocale-lock.c
index b70ba09b..192489c4 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2019-2024 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
@@ -18,9 +18,10 @@
18 18
19#include <config.h> 19#include <config.h>
20 20
21/* The option '--disable-threads' explicitly requests no locking. */
21/* When it is known that the gl_get_setlocale_null_lock function is defined 22/* When it is known that the gl_get_setlocale_null_lock function is defined
22 by a dependency library, it should not be defined here. */ 23 by a dependency library, it should not be defined here. */
23#if OMIT_SETLOCALE_LOCK 24#if AVOID_ANY_THREADS || OMIT_SETLOCALE_LOCK
24 25
25/* This declaration is solely to ensure that after preprocessing 26/* This declaration is solely to ensure that after preprocessing
26 this file is never empty. */ 27 this file is never empty. */
@@ -37,14 +38,14 @@ typedef int dummy;
37 38
38/* Macro for exporting a symbol (function, not variable) defined in this file, 39/* Macro for exporting a symbol (function, not variable) defined in this file,
39 when compiled into a shared library. */ 40 when compiled into a shared library. */
40# ifndef DLL_EXPORTED 41# ifndef SHLIB_EXPORTED
41# if HAVE_VISIBILITY 42# if HAVE_VISIBILITY
42 /* Override the effect of the compiler option '-fvisibility=hidden'. */ 43 /* Override the effect of the compiler option '-fvisibility=hidden'. */
43# define DLL_EXPORTED __attribute__((__visibility__("default"))) 44# define SHLIB_EXPORTED __attribute__((__visibility__("default")))
44# elif defined _WIN32 || defined __CYGWIN__ 45# elif defined _WIN32 || defined __CYGWIN__
45# define DLL_EXPORTED __declspec(dllexport) 46# define SHLIB_EXPORTED __declspec(dllexport)
46# else 47# else
47# define DLL_EXPORTED 48# define SHLIB_EXPORTED
48# endif 49# endif
49# endif 50# endif
50 51
@@ -59,7 +60,7 @@ typedef int dummy;
59 because the latter is not guaranteed to be a stable ABI in the future. */ 60 because the latter is not guaranteed to be a stable ABI in the future. */
60 61
61/* Make sure the function gets exported from DLLs. */ 62/* Make sure the function gets exported from DLLs. */
62DLL_EXPORTED CRITICAL_SECTION *gl_get_setlocale_null_lock (void); 63SHLIB_EXPORTED CRITICAL_SECTION *gl_get_setlocale_null_lock (void);
63 64
64static glwthread_initguard_t guard = GLWTHREAD_INITGUARD_INIT; 65static glwthread_initguard_t guard = GLWTHREAD_INITGUARD_INIT;
65static CRITICAL_SECTION lock; 66static CRITICAL_SECTION lock;
@@ -96,7 +97,7 @@ gl_get_setlocale_null_lock (void)
96static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 97static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
97 98
98/* Make sure the function gets exported from shared libraries. */ 99/* Make sure the function gets exported from shared libraries. */
99DLL_EXPORTED pthread_mutex_t *gl_get_setlocale_null_lock (void); 100SHLIB_EXPORTED pthread_mutex_t *gl_get_setlocale_null_lock (void);
100 101
101/* Returns the internal lock used by setlocale_null_r. */ 102/* Returns the internal lock used by setlocale_null_r. */
102pthread_mutex_t * 103pthread_mutex_t *
@@ -123,7 +124,7 @@ atomic_init (void)
123} 124}
124 125
125/* Make sure the function gets exported from shared libraries. */ 126/* Make sure the function gets exported from shared libraries. */
126DLL_EXPORTED mtx_t *gl_get_setlocale_null_lock (void); 127SHLIB_EXPORTED mtx_t *gl_get_setlocale_null_lock (void);
127 128
128/* Returns the internal lock used by setlocale_null_r. */ 129/* Returns the internal lock used by setlocale_null_r. */
129mtx_t * 130mtx_t *
diff --git a/gl/setlocale_null-unlocked.c b/gl/setlocale_null-unlocked.c
new file mode 100644
index 00000000..0a86f0df
--- /dev/null
+++ b/gl/setlocale_null-unlocked.c
@@ -0,0 +1,149 @@
1/* Query the name of the current global locale, without locking.
2 Copyright (C) 2019-2024 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 "setlocale_null.h"
23
24#include <errno.h>
25#include <locale.h>
26#include <string.h>
27#if defined _WIN32 && !defined __CYGWIN__
28# include <wchar.h>
29#endif
30
31/* Use the system's setlocale() function, not the gnulib override, here. */
32#undef setlocale
33
34const char *
35setlocale_null_unlocked (int category)
36{
37 const char *result = setlocale (category, NULL);
38
39#ifdef __ANDROID__
40 if (result == NULL)
41 switch (category)
42 {
43 case LC_CTYPE:
44 case LC_NUMERIC:
45 case LC_TIME:
46 case LC_COLLATE:
47 case LC_MONETARY:
48 case LC_MESSAGES:
49 case LC_ALL:
50 case LC_PAPER:
51 case LC_NAME:
52 case LC_ADDRESS:
53 case LC_TELEPHONE:
54 case LC_MEASUREMENT:
55 result = "C";
56 break;
57 default:
58 break;
59 }
60#endif
61
62 return result;
63}
64
65int
66setlocale_null_r_unlocked (int category, char *buf, size_t bufsize)
67{
68#if defined _WIN32 && !defined __CYGWIN__ && defined _MSC_VER
69 /* On native Windows, nowadays, the setlocale() implementation is based
70 on _wsetlocale() and uses malloc() for the result. We are better off
71 using _wsetlocale() directly. */
72 const wchar_t *result = _wsetlocale (category, NULL);
73
74 if (result == NULL)
75 {
76 /* CATEGORY is invalid. */
77 if (bufsize > 0)
78 /* Return an empty string in BUF.
79 This is a convenience for callers that don't want to write explicit
80 code for handling EINVAL. */
81 buf[0] = '\0';
82 return EINVAL;
83 }
84 else
85 {
86 size_t length = wcslen (result);
87 if (length < bufsize)
88 {
89 size_t i;
90
91 /* Convert wchar_t[] -> char[], assuming plain ASCII. */
92 for (i = 0; i <= length; i++)
93 buf[i] = result[i];
94
95 return 0;
96 }
97 else
98 {
99 if (bufsize > 0)
100 {
101 /* Return a truncated result in BUF.
102 This is a convenience for callers that don't want to write
103 explicit code for handling ERANGE. */
104 size_t i;
105
106 /* Convert wchar_t[] -> char[], assuming plain ASCII. */
107 for (i = 0; i < bufsize; i++)
108 buf[i] = result[i];
109 buf[bufsize - 1] = '\0';
110 }
111 return ERANGE;
112 }
113 }
114#else
115 const char *result = setlocale_null_unlocked (category);
116
117 if (result == NULL)
118 {
119 /* CATEGORY is invalid. */
120 if (bufsize > 0)
121 /* Return an empty string in BUF.
122 This is a convenience for callers that don't want to write explicit
123 code for handling EINVAL. */
124 buf[0] = '\0';
125 return EINVAL;
126 }
127 else
128 {
129 size_t length = strlen (result);
130 if (length < bufsize)
131 {
132 memcpy (buf, result, length + 1);
133 return 0;
134 }
135 else
136 {
137 if (bufsize > 0)
138 {
139 /* Return a truncated result in BUF.
140 This is a convenience for callers that don't want to write
141 explicit code for handling ERANGE. */
142 memcpy (buf, result, bufsize - 1);
143 buf[bufsize - 1] = '\0';
144 }
145 return ERANGE;
146 }
147 }
148#endif
149}
diff --git a/gl/setlocale_null.c b/gl/setlocale_null.c
index 6ac563db..5ecf413d 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2019-2024 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,12 +25,14 @@
25#include <locale.h> 25#include <locale.h>
26#include <stdlib.h> 26#include <stdlib.h>
27#include <string.h> 27#include <string.h>
28#if defined _WIN32 && !defined __CYGWIN__
29# include <wchar.h>
30#endif
31 28
32#if !(SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE) 29#if !(SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE)
33# if defined _WIN32 && !defined __CYGWIN__ 30
31# if AVOID_ANY_THREADS
32
33/* The option '--disable-threads' explicitly requests no locking. */
34
35# elif defined _WIN32 && !defined __CYGWIN__
34 36
35# define WIN32_LEAN_AND_MEAN /* avoid including junk */ 37# define WIN32_LEAN_AND_MEAN /* avoid including junk */
36# include <windows.h> 38# include <windows.h>
@@ -51,154 +53,40 @@
51# include <threads.h> 53# include <threads.h>
52 54
53# endif 55# endif
54#endif
55 56
56/* Use the system's setlocale() function, not the gnulib override, here. */
57#undef setlocale
58
59static const char *
60setlocale_null_androidfix (int category)
61{
62 const char *result = setlocale (category, NULL);
63
64#ifdef __ANDROID__
65 if (result == NULL)
66 switch (category)
67 {
68 case LC_CTYPE:
69 case LC_NUMERIC:
70 case LC_TIME:
71 case LC_COLLATE:
72 case LC_MONETARY:
73 case LC_MESSAGES:
74 case LC_ALL:
75 case LC_PAPER:
76 case LC_NAME:
77 case LC_ADDRESS:
78 case LC_TELEPHONE:
79 case LC_MEASUREMENT:
80 result = "C";
81 break;
82 default:
83 break;
84 }
85#endif 57#endif
86 58
87 return result; 59#if !(SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE) /* musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin < 3.4.6 */
88}
89
90static int
91setlocale_null_unlocked (int category, char *buf, size_t bufsize)
92{
93#if defined _WIN32 && !defined __CYGWIN__ && defined _MSC_VER
94 /* On native Windows, nowadays, the setlocale() implementation is based
95 on _wsetlocale() and uses malloc() for the result. We are better off
96 using _wsetlocale() directly. */
97 const wchar_t *result = _wsetlocale (category, NULL);
98
99 if (result == NULL)
100 {
101 /* CATEGORY is invalid. */
102 if (bufsize > 0)
103 /* Return an empty string in BUF.
104 This is a convenience for callers that don't want to write explicit
105 code for handling EINVAL. */
106 buf[0] = '\0';
107 return EINVAL;
108 }
109 else
110 {
111 size_t length = wcslen (result);
112 if (length < bufsize)
113 {
114 size_t i;
115
116 /* Convert wchar_t[] -> char[], assuming plain ASCII. */
117 for (i = 0; i <= length; i++)
118 buf[i] = result[i];
119 60
120 return 0; 61/* Use a lock, so that no two threads can invoke setlocale_null_r_unlocked
121 }
122 else
123 {
124 if (bufsize > 0)
125 {
126 /* Return a truncated result in BUF.
127 This is a convenience for callers that don't want to write
128 explicit code for handling ERANGE. */
129 size_t i;
130
131 /* Convert wchar_t[] -> char[], assuming plain ASCII. */
132 for (i = 0; i < bufsize; i++)
133 buf[i] = result[i];
134 buf[bufsize - 1] = '\0';
135 }
136 return ERANGE;
137 }
138 }
139#else
140 const char *result = setlocale_null_androidfix (category);
141
142 if (result == NULL)
143 {
144 /* CATEGORY is invalid. */
145 if (bufsize > 0)
146 /* Return an empty string in BUF.
147 This is a convenience for callers that don't want to write explicit
148 code for handling EINVAL. */
149 buf[0] = '\0';
150 return EINVAL;
151 }
152 else
153 {
154 size_t length = strlen (result);
155 if (length < bufsize)
156 {
157 memcpy (buf, result, length + 1);
158 return 0;
159 }
160 else
161 {
162 if (bufsize > 0)
163 {
164 /* Return a truncated result in BUF.
165 This is a convenience for callers that don't want to write
166 explicit code for handling ERANGE. */
167 memcpy (buf, result, bufsize - 1);
168 buf[bufsize - 1] = '\0';
169 }
170 return ERANGE;
171 }
172 }
173#endif
174}
175
176#if !(SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE) /* musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin */
177
178/* Use a lock, so that no two threads can invoke setlocale_null_unlocked
179 at the same time. */ 62 at the same time. */
180 63
181/* Prohibit renaming this symbol. */ 64/* Prohibit renaming this symbol. */
182# undef gl_get_setlocale_null_lock 65# undef gl_get_setlocale_null_lock
183 66
184# if defined _WIN32 && !defined __CYGWIN__ 67# if AVOID_ANY_THREADS
68
69/* The option '--disable-threads' explicitly requests no locking. */
70# define setlocale_null_r_with_lock setlocale_null_r_unlocked
71
72# elif defined _WIN32 && !defined __CYGWIN__
185 73
186extern __declspec(dllimport) CRITICAL_SECTION *gl_get_setlocale_null_lock (void); 74extern __declspec(dllimport) CRITICAL_SECTION *gl_get_setlocale_null_lock (void);
187 75
188static int 76static int
189setlocale_null_with_lock (int category, char *buf, size_t bufsize) 77setlocale_null_r_with_lock (int category, char *buf, size_t bufsize)
190{ 78{
191 CRITICAL_SECTION *lock = gl_get_setlocale_null_lock (); 79 CRITICAL_SECTION *lock = gl_get_setlocale_null_lock ();
192 int ret; 80 int ret;
193 81
194 EnterCriticalSection (lock); 82 EnterCriticalSection (lock);
195 ret = setlocale_null_unlocked (category, buf, bufsize); 83 ret = setlocale_null_r_unlocked (category, buf, bufsize);
196 LeaveCriticalSection (lock); 84 LeaveCriticalSection (lock);
197 85
198 return ret; 86 return ret;
199} 87}
200 88
201# elif HAVE_PTHREAD_API /* musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin */ 89# elif HAVE_PTHREAD_API /* musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin < 3.4.6 */
202 90
203extern 91extern
204# if defined _WIN32 || defined __CYGWIN__ 92# if defined _WIN32 || defined __CYGWIN__
@@ -223,7 +111,7 @@ extern
223# endif 111# endif
224 112
225static int 113static int
226setlocale_null_with_lock (int category, char *buf, size_t bufsize) 114setlocale_null_r_with_lock (int category, char *buf, size_t bufsize)
227{ 115{
228 if (pthread_in_use()) 116 if (pthread_in_use())
229 { 117 {
@@ -232,14 +120,14 @@ setlocale_null_with_lock (int category, char *buf, size_t bufsize)
232 120
233 if (pthread_mutex_lock (lock)) 121 if (pthread_mutex_lock (lock))
234 abort (); 122 abort ();
235 ret = setlocale_null_unlocked (category, buf, bufsize); 123 ret = setlocale_null_r_unlocked (category, buf, bufsize);
236 if (pthread_mutex_unlock (lock)) 124 if (pthread_mutex_unlock (lock))
237 abort (); 125 abort ();
238 126
239 return ret; 127 return ret;
240 } 128 }
241 else 129 else
242 return setlocale_null_unlocked (category, buf, bufsize); 130 return setlocale_null_r_unlocked (category, buf, bufsize);
243} 131}
244 132
245# elif HAVE_THREADS_H 133# elif HAVE_THREADS_H
@@ -247,14 +135,14 @@ setlocale_null_with_lock (int category, char *buf, size_t bufsize)
247extern mtx_t *gl_get_setlocale_null_lock (void); 135extern mtx_t *gl_get_setlocale_null_lock (void);
248 136
249static int 137static int
250setlocale_null_with_lock (int category, char *buf, size_t bufsize) 138setlocale_null_r_with_lock (int category, char *buf, size_t bufsize)
251{ 139{
252 mtx_t *lock = gl_get_setlocale_null_lock (); 140 mtx_t *lock = gl_get_setlocale_null_lock ();
253 int ret; 141 int ret;
254 142
255 if (mtx_lock (lock) != thrd_success) 143 if (mtx_lock (lock) != thrd_success)
256 abort (); 144 abort ();
257 ret = setlocale_null_unlocked (category, buf, bufsize); 145 ret = setlocale_null_r_unlocked (category, buf, bufsize);
258 if (mtx_unlock (lock) != thrd_success) 146 if (mtx_unlock (lock) != thrd_success)
259 abort (); 147 abort ();
260 148
@@ -271,27 +159,27 @@ setlocale_null_r (int category, char *buf, size_t bufsize)
271#if SETLOCALE_NULL_ALL_MTSAFE 159#if SETLOCALE_NULL_ALL_MTSAFE
272# if SETLOCALE_NULL_ONE_MTSAFE 160# if SETLOCALE_NULL_ONE_MTSAFE
273 161
274 return setlocale_null_unlocked (category, buf, bufsize); 162 return setlocale_null_r_unlocked (category, buf, bufsize);
275 163
276# else 164# else
277 165
278 if (category == LC_ALL) 166 if (category == LC_ALL)
279 return setlocale_null_unlocked (category, buf, bufsize); 167 return setlocale_null_r_unlocked (category, buf, bufsize);
280 else 168 else
281 return setlocale_null_with_lock (category, buf, bufsize); 169 return setlocale_null_r_with_lock (category, buf, bufsize);
282 170
283# endif 171# endif
284#else 172#else
285# if SETLOCALE_NULL_ONE_MTSAFE 173# if SETLOCALE_NULL_ONE_MTSAFE
286 174
287 if (category == LC_ALL) 175 if (category == LC_ALL)
288 return setlocale_null_with_lock (category, buf, bufsize); 176 return setlocale_null_r_with_lock (category, buf, bufsize);
289 else 177 else
290 return setlocale_null_unlocked (category, buf, bufsize); 178 return setlocale_null_r_unlocked (category, buf, bufsize);
291 179
292# else 180# else
293 181
294 return setlocale_null_with_lock (category, buf, bufsize); 182 return setlocale_null_r_with_lock (category, buf, bufsize);
295 183
296# endif 184# endif
297#endif 185#endif
@@ -301,7 +189,7 @@ const char *
301setlocale_null (int category) 189setlocale_null (int category)
302{ 190{
303#if SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE 191#if SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE
304 return setlocale_null_androidfix (category); 192 return setlocale_null_unlocked (category);
305#else 193#else
306 194
307 /* This call must be multithread-safe. To achieve this without using 195 /* This call must be multithread-safe. To achieve this without using
@@ -317,7 +205,7 @@ setlocale_null (int category)
317 if (category == LC_ALL) 205 if (category == LC_ALL)
318 { 206 {
319# if SETLOCALE_NULL_ALL_MTSAFE 207# if SETLOCALE_NULL_ALL_MTSAFE
320 return setlocale_null_androidfix (LC_ALL); 208 return setlocale_null_unlocked (LC_ALL);
321# else 209# else
322 char buf[SETLOCALE_NULL_ALL_MAX]; 210 char buf[SETLOCALE_NULL_ALL_MAX];
323 static char resultbuf[SETLOCALE_NULL_ALL_MAX]; 211 static char resultbuf[SETLOCALE_NULL_ALL_MAX];
@@ -331,7 +219,7 @@ setlocale_null (int category)
331 else 219 else
332 { 220 {
333# if SETLOCALE_NULL_ONE_MTSAFE 221# if SETLOCALE_NULL_ONE_MTSAFE
334 return setlocale_null_androidfix (category); 222 return setlocale_null_unlocked (category);
335# else 223# else
336 enum 224 enum
337 { 225 {
diff --git a/gl/setlocale_null.h b/gl/setlocale_null.h
index c740fa0f..966c53cf 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2019-2024 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
@@ -44,6 +44,34 @@ extern "C" {
44 55+5*58. */ 44 55+5*58. */
45#define SETLOCALE_NULL_ALL_MAX (148+12*256+1) 45#define SETLOCALE_NULL_ALL_MAX (148+12*256+1)
46 46
47/* setlocale_null_r_unlocked (CATEGORY, BUF, BUFSIZE) is like
48 setlocale (CATEGORY, NULL), except that
49 - it returns the resulting locale category name or locale name in the
50 user-supplied buffer BUF, which must be BUFSIZE bytes long.
51 The recommended minimum buffer size is
52 - SETLOCALE_NULL_MAX for CATEGORY != LC_ALL, and
53 - SETLOCALE_NULL_ALL_MAX for CATEGORY == LC_ALL.
54 The return value is an error code: 0 if the call is successful, EINVAL if
55 CATEGORY is invalid, or ERANGE if BUFSIZE is smaller than the length needed
56 size (including the trailing NUL byte). In the latter case, a truncated
57 result is returned in BUF, but still NUL-terminated if BUFSIZE > 0.
58 This call is guaranteed to be multithread-safe only if
59 - CATEGORY != LC_ALL and SETLOCALE_NULL_ONE_MTSAFE is true, or
60 - CATEGORY == LC_ALL and SETLOCALE_NULL_ALL_MTSAFE is true,
61 and the other threads must not make other setlocale invocations (since
62 changing the global locale has side effects on all threads). */
63extern int setlocale_null_r_unlocked (int category, char *buf, size_t bufsize)
64 _GL_ARG_NONNULL ((2));
65
66/* setlocale_null_unlocked (CATEGORY) is like setlocale (CATEGORY, NULL).
67 The return value is NULL if CATEGORY is invalid.
68 This call is guaranteed to be multithread-safe only if
69 - CATEGORY != LC_ALL and SETLOCALE_NULL_ONE_MTSAFE is true, or
70 - CATEGORY == LC_ALL and SETLOCALE_NULL_ALL_MTSAFE is true,
71 and the other threads must not make other setlocale invocations (since
72 changing the global locale has side effects on all threads). */
73extern const char *setlocale_null_unlocked (int category);
74
47/* setlocale_null_r (CATEGORY, BUF, BUFSIZE) is like setlocale (CATEGORY, NULL), 75/* setlocale_null_r (CATEGORY, BUF, BUFSIZE) is like setlocale (CATEGORY, NULL),
48 except that 76 except that
49 - it is guaranteed to be multithread-safe, 77 - it is guaranteed to be multithread-safe,
diff --git a/gl/sha256-stream.c b/gl/sha256-stream.c
index 0e83380a..08d24b7b 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-2023 Free Software Foundation, Inc. 4 Copyright (C) 2005-2006, 2008-2024 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.c b/gl/sha256.c
index e5fea02b..fe7c5446 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-2023 Free Software Foundation, Inc. 4 Copyright (C) 2005-2006, 2008-2024 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 2879477e..a9d7abb8 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2005-2006, 2008-2024 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
@@ -18,6 +18,11 @@
18#ifndef SHA256_H 18#ifndef SHA256_H
19# define SHA256_H 1 19# define SHA256_H 1
20 20
21/* This file uses HAVE_OPENSSL_SHA256. */
22# if !_GL_CONFIG_H_INCLUDED
23# error "Please include config.h first."
24# endif
25
21# include <stdio.h> 26# include <stdio.h>
22# include <stdint.h> 27# include <stdint.h>
23 28
@@ -25,7 +30,21 @@
25# ifndef OPENSSL_API_COMPAT 30# ifndef OPENSSL_API_COMPAT
26# define OPENSSL_API_COMPAT 0x10101000L /* FIXME: Use OpenSSL 1.1+ API. */ 31# define OPENSSL_API_COMPAT 0x10101000L /* FIXME: Use OpenSSL 1.1+ API. */
27# endif 32# endif
28# include <openssl/sha.h> 33/* If <openssl/macros.h> would give a compile-time error, don't use OpenSSL. */
34# include <openssl/opensslv.h>
35# if OPENSSL_VERSION_MAJOR >= 3
36# include <openssl/configuration.h>
37# if (OPENSSL_CONFIGURED_API \
38 < (OPENSSL_API_COMPAT < 0x900000L ? OPENSSL_API_COMPAT : \
39 ((OPENSSL_API_COMPAT >> 28) & 0xF) * 10000 \
40 + ((OPENSSL_API_COMPAT >> 20) & 0xFF) * 100 \
41 + ((OPENSSL_API_COMPAT >> 12) & 0xFF)))
42# undef HAVE_OPENSSL_SHA256
43# endif
44# endif
45# if HAVE_OPENSSL_SHA256
46# include <openssl/sha.h>
47# endif
29# endif 48# endif
30 49
31# ifdef __cplusplus 50# ifdef __cplusplus
diff --git a/gl/size_max.h b/gl/size_max.h
index 48af0250..bd2eb43e 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2005-2006, 2009-2024 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
@@ -18,6 +18,11 @@
18#ifndef GNULIB_SIZE_MAX_H 18#ifndef GNULIB_SIZE_MAX_H
19#define GNULIB_SIZE_MAX_H 19#define GNULIB_SIZE_MAX_H
20 20
21/* This file uses HAVE_STDINT_H. */
22#if !_GL_CONFIG_H_INCLUDED
23 #error "Please include config.h first."
24#endif
25
21/* Get SIZE_MAX declaration on systems like Solaris 7/8/9. */ 26/* Get SIZE_MAX declaration on systems like Solaris 7/8/9. */
22# include <limits.h> 27# include <limits.h>
23/* Get SIZE_MAX declaration on systems like glibc 2. */ 28/* Get SIZE_MAX declaration on systems like glibc 2. */
diff --git a/gl/snprintf.c b/gl/snprintf.c
index cdff3149..c1b93562 100644
--- a/gl/snprintf.c
+++ b/gl/snprintf.c
@@ -1,5 +1,5 @@
1/* Formatted output to strings. 1/* Formatted output to strings.
2 Copyright (C) 2004, 2006-2023 Free Software Foundation, Inc. 2 Copyright (C) 2004, 2006-2024 Free Software Foundation, Inc.
3 Written by Simon Josefsson and Paul Eggert. 3 Written by Simon Josefsson and Paul Eggert.
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/sockets.c b/gl/sockets.c
index ca99db8b..92beb7d3 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2008-2024 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 a0b1601d..55077ae9 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2008-2024 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,6 +20,15 @@
20#ifndef SOCKETS_H 20#ifndef SOCKETS_H
21#define SOCKETS_H 1 21#define SOCKETS_H 1
22 22
23/* This file uses _GL_ATTRIBUTE_CONST. */
24#if !_GL_CONFIG_H_INCLUDED
25 #error "Please include config.h first."
26#endif
27
28#ifdef __cplusplus
29extern "C" {
30#endif
31
23#define SOCKETS_1_0 0x0001 32#define SOCKETS_1_0 0x0001
24#define SOCKETS_1_1 0x0101 33#define SOCKETS_1_1 0x0101
25#define SOCKETS_2_0 0x0002 34#define SOCKETS_2_0 0x0002
@@ -38,6 +47,11 @@ int gl_sockets_cleanup (void)
38#endif 47#endif
39 ; 48 ;
40 49
50#ifdef __cplusplus
51}
52#endif
53
54
41/* This function is useful it you create a socket using gnulib's 55/* This function is useful it you create a socket using gnulib's
42 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
43 other library that only accepts sockets. */ 57 other library that only accepts sockets. */
diff --git a/gl/stat-time.c b/gl/stat-time.c
index bc282232..1ab01f53 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2012-2024 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 92aa1e64..3cd8478f 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2005, 2007, 2009-2024 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,15 +20,18 @@
20#ifndef STAT_TIME_H 20#ifndef STAT_TIME_H
21#define STAT_TIME_H 1 21#define STAT_TIME_H 1
22 22
23/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE, _GL_UNUSED,
24 _GL_ATTRIBUTE_PURE, HAVE_STRUCT_STAT_*. */
25#if !_GL_CONFIG_H_INCLUDED
26 #error "Please include config.h first."
27#endif
28
23#include <errno.h> 29#include <errno.h>
24#include <stdckdint.h> 30#include <stdckdint.h>
25#include <stddef.h> 31#include <stddef.h>
26#include <sys/stat.h> 32#include <sys/stat.h>
27#include <time.h> 33#include <time.h>
28 34
29#ifndef _GL_INLINE_HEADER_BEGIN
30 #error "Please include config.h first."
31#endif
32_GL_INLINE_HEADER_BEGIN 35_GL_INLINE_HEADER_BEGIN
33#ifndef _GL_STAT_TIME_INLINE 36#ifndef _GL_STAT_TIME_INLINE
34# define _GL_STAT_TIME_INLINE _GL_INLINE 37# define _GL_STAT_TIME_INLINE _GL_INLINE
@@ -49,11 +52,13 @@ extern "C" {
49#if _GL_WINDOWS_STAT_TIMESPEC || defined HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC 52#if _GL_WINDOWS_STAT_TIMESPEC || defined HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
50# if _GL_WINDOWS_STAT_TIMESPEC || defined TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC 53# if _GL_WINDOWS_STAT_TIMESPEC || defined TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC
51# define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim) 54# define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim)
55# define STAT_TIMESPEC_OFFSETOF(st_xtim) offsetof (struct stat, st_xtim)
52# else 56# else
53# define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.tv_nsec) 57# define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim.tv_nsec)
54# endif 58# endif
55#elif defined HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC 59#elif defined HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC
56# define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim##espec) 60# define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim##espec)
61# define STAT_TIMESPEC_OFFSETOF(st_xtim) offsetof (struct stat, st_xtim##espec)
57#elif defined HAVE_STRUCT_STAT_ST_ATIMENSEC 62#elif defined HAVE_STRUCT_STAT_ST_ATIMENSEC
58# define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim##ensec) 63# define STAT_TIMESPEC_NS(st, st_xtim) ((st)->st_xtim##ensec)
59#elif defined HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC 64#elif defined HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC
@@ -119,10 +124,8 @@ get_stat_atime (struct stat const *st)
119#ifdef STAT_TIMESPEC 124#ifdef STAT_TIMESPEC
120 return STAT_TIMESPEC (st, st_atim); 125 return STAT_TIMESPEC (st, st_atim);
121#else 126#else
122 struct timespec t; 127 return (struct timespec) { .tv_sec = st->st_atime,
123 t.tv_sec = st->st_atime; 128 .tv_nsec = get_stat_atime_ns (st) };
124 t.tv_nsec = get_stat_atime_ns (st);
125 return t;
126#endif 129#endif
127} 130}
128 131
@@ -133,10 +136,8 @@ get_stat_ctime (struct stat const *st)
133#ifdef STAT_TIMESPEC 136#ifdef STAT_TIMESPEC
134 return STAT_TIMESPEC (st, st_ctim); 137 return STAT_TIMESPEC (st, st_ctim);
135#else 138#else
136 struct timespec t; 139 return (struct timespec) { .tv_sec = st->st_ctime,
137 t.tv_sec = st->st_ctime; 140 .tv_nsec = get_stat_ctime_ns (st) };
138 t.tv_nsec = get_stat_ctime_ns (st);
139 return t;
140#endif 141#endif
141} 142}
142 143
@@ -147,10 +148,8 @@ get_stat_mtime (struct stat const *st)
147#ifdef STAT_TIMESPEC 148#ifdef STAT_TIMESPEC
148 return STAT_TIMESPEC (st, st_mtim); 149 return STAT_TIMESPEC (st, st_mtim);
149#else 150#else
150 struct timespec t; 151 return (struct timespec) { .tv_sec = st->st_mtime,
151 t.tv_sec = st->st_mtime; 152 .tv_nsec = get_stat_mtime_ns (st) };
152 t.tv_nsec = get_stat_mtime_ns (st);
153 return t;
154#endif 153#endif
155} 154}
156 155
@@ -165,8 +164,8 @@ get_stat_birthtime (_GL_UNUSED struct stat const *st)
165 || defined HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC) 164 || defined HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC)
166 t = STAT_TIMESPEC (st, st_birthtim); 165 t = STAT_TIMESPEC (st, st_birthtim);
167#elif defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC 166#elif defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC
168 t.tv_sec = st->st_birthtime; 167 t = (struct timespec) { .tv_sec = st->st_birthtime,
169 t.tv_nsec = st->st_birthtimensec; 168 .tv_nsec = st->st_birthtimensec };
170#elif defined _WIN32 && ! defined __CYGWIN__ 169#elif defined _WIN32 && ! defined __CYGWIN__
171 /* Native Windows platforms (but not Cygwin) put the "file creation 170 /* Native Windows platforms (but not Cygwin) put the "file creation
172 time" in st_ctime (!). See 171 time" in st_ctime (!). See
@@ -174,13 +173,11 @@ get_stat_birthtime (_GL_UNUSED struct stat const *st)
174# if _GL_WINDOWS_STAT_TIMESPEC 173# if _GL_WINDOWS_STAT_TIMESPEC
175 t = st->st_ctim; 174 t = st->st_ctim;
176# else 175# else
177 t.tv_sec = st->st_ctime; 176 t = (struct timespec) { .tv_sec = st->st_ctime };
178 t.tv_nsec = 0;
179# endif 177# endif
180#else 178#else
181 /* Birth time is not supported. */ 179 /* Birth time is not supported. */
182 t.tv_sec = -1; 180 t = (struct timespec) { .tv_sec = -1, .tv_nsec = -1 };
183 t.tv_nsec = -1;
184#endif 181#endif
185 182
186#if (defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC \ 183#if (defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC \
@@ -192,30 +189,28 @@ get_stat_birthtime (_GL_UNUSED struct stat const *st)
192 sometimes returns junk in the birth time fields; work around this 189 sometimes returns junk in the birth time fields; work around this
193 bug if it is detected. */ 190 bug if it is detected. */
194 if (! (t.tv_sec && 0 <= t.tv_nsec && t.tv_nsec < 1000000000)) 191 if (! (t.tv_sec && 0 <= t.tv_nsec && t.tv_nsec < 1000000000))
195 { 192 t = (struct timespec) { .tv_sec = -1, .tv_nsec = -1 };
196 t.tv_sec = -1;
197 t.tv_nsec = -1;
198 }
199#endif 193#endif
200 194
201 return t; 195 return t;
202} 196}
203 197
204/* If a stat-like function returned RESULT, normalize the timestamps 198/* If a stat-like function returned RESULT, normalize the timestamps
205 in *ST, in case this platform suffers from the Solaris 11 bug where 199 in *ST, if this platform suffers from a macOS and Solaris bug where
206 tv_nsec might be negative. Return the adjusted RESULT, setting 200 tv_nsec might be negative. Return the adjusted RESULT, setting
207 errno to EOVERFLOW if normalization overflowed. This function 201 errno to EOVERFLOW if normalization overflowed. This function
208 is intended to be private to this .h file. */ 202 is intended to be private to this .h file. */
209_GL_STAT_TIME_INLINE int 203_GL_STAT_TIME_INLINE int
210stat_time_normalize (int result, _GL_UNUSED struct stat *st) 204stat_time_normalize (int result, _GL_UNUSED struct stat *st)
211{ 205{
212#if defined __sun && defined STAT_TIMESPEC 206#if (((defined __APPLE__ && defined __MACH__) || defined __sun) \
207 && defined STAT_TIMESPEC_OFFSETOF)
213 if (result == 0) 208 if (result == 0)
214 { 209 {
215 long int timespec_hz = 1000000000; 210 long int timespec_hz = 1000000000;
216 short int const ts_off[] = { offsetof (struct stat, st_atim), 211 short int const ts_off[] = { STAT_TIMESPEC_OFFSETOF (st_atim),
217 offsetof (struct stat, st_mtim), 212 STAT_TIMESPEC_OFFSETOF (st_mtim),
218 offsetof (struct stat, st_ctim) }; 213 STAT_TIMESPEC_OFFSETOF (st_ctim) };
219 int i; 214 int i;
220 for (i = 0; i < sizeof ts_off / sizeof *ts_off; i++) 215 for (i = 0; i < sizeof ts_off / sizeof *ts_off; i++)
221 { 216 {
@@ -229,8 +224,7 @@ stat_time_normalize (int result, _GL_UNUSED struct stat *st)
229 } 224 }
230 ts->tv_nsec = r; 225 ts->tv_nsec = r;
231 /* Overflow is possible, as Solaris 11 stat can yield 226 /* Overflow is possible, as Solaris 11 stat can yield
232 tv_sec == TYPE_MINIMUM (time_t) && tv_nsec == -1000000000. 227 tv_sec == TYPE_MINIMUM (time_t) && tv_nsec == -1000000000. */
233 INT_ADD_WRAPV is OK, since time_t is signed on Solaris. */
234 if (ckd_add (&ts->tv_sec, q, ts->tv_sec)) 228 if (ckd_add (&ts->tv_sec, q, ts->tv_sec))
235 { 229 {
236 errno = EOVERFLOW; 230 errno = EOVERFLOW;
diff --git a/gl/stat-w32.c b/gl/stat-w32.c
index 2f011975..ddd6f598 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2017-2024 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 c6738749..392faed1 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2017-2024 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 7987e265..ecf9f9bb 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2009-2024 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/stdalign.in.h b/gl/stdalign.in.h
deleted file mode 100644
index 7f9dbb46..00000000
--- a/gl/stdalign.in.h
+++ /dev/null
@@ -1,137 +0,0 @@
1/* A substitute for ISO C11 <stdalign.h>.
2
3 Copyright 2011-2023 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 and Bruno Haible. */
19
20#ifndef _GL_STDALIGN_H
21#define _GL_STDALIGN_H
22
23/* ISO C11 <stdalign.h> for platforms that lack it.
24
25 References:
26 ISO C11 (latest free draft
27 <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf>)
28 sections 6.5.3.4, 6.7.5, 7.15.
29 C++11 (latest free draft
30 <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf>)
31 section 18.10. */
32
33/* alignof (TYPE), also known as _Alignof (TYPE), yields the alignment
34 requirement of a structure member (i.e., slot or field) that is of
35 type TYPE, as an integer constant expression.
36
37 This differs from GCC's and clang's __alignof__ operator, which can
38 yield a better-performing alignment for an object of that type. For
39 example, on x86 with GCC and on Linux/x86 with clang,
40 __alignof__ (double) and __alignof__ (long long) are 8, whereas
41 alignof (double) and alignof (long long) are 4 unless the option
42 '-malign-double' is used.
43
44 The result cannot be used as a value for an 'enum' constant, if you
45 want to be portable to HP-UX 10.20 cc and AIX 3.2.5 xlc. */
46
47/* FreeBSD 9.1 <sys/cdefs.h>, included by <stddef.h> and lots of other
48 standard headers, defines conflicting implementations of _Alignas
49 and _Alignof that are no better than ours; override them. */
50#undef _Alignas
51#undef _Alignof
52
53/* GCC releases before GCC 4.9 had a bug in _Alignof. See GCC bug 52023
54 <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52023>.
55 clang versions < 8.0.0 have the same bug. */
56#if (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112 \
57 || (defined __GNUC__ && __GNUC__ < 4 + (__GNUC_MINOR__ < 9) \
58 && !defined __clang__) \
59 || (defined __clang__ && __clang_major__ < 8))
60# ifdef __cplusplus
61# if (201103 <= __cplusplus || defined _MSC_VER)
62# define _Alignof(type) alignof (type)
63# else
64 template <class __t> struct __alignof_helper { char __a; __t __b; };
65# define _Alignof(type) offsetof (__alignof_helper<type>, __b)
66# define _GL_STDALIGN_NEEDS_STDDEF 1
67# endif
68# else
69# if (defined __GNUC__ && 4 <= __GNUC__) || defined __clang__
70# define _Alignof(type) __builtin_offsetof (struct { char __a; type __b; }, __b)
71# else
72# define _Alignof(type) offsetof (struct { char __a; type __b; }, __b)
73# define _GL_STDALIGN_NEEDS_STDDEF 1
74# endif
75# endif
76#endif
77#if ! (defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER))
78# define alignof _Alignof
79#endif
80#define __alignof_is_defined 1
81
82/* alignas (A), also known as _Alignas (A), aligns a variable or type
83 to the alignment A, where A is an integer constant expression. For
84 example:
85
86 int alignas (8) foo;
87 struct s { int a; int alignas (8) bar; };
88
89 aligns the address of FOO and the offset of BAR to be multiples of 8.
90
91 A should be a power of two that is at least the type's alignment
92 and at most the implementation's alignment limit. This limit is
93 2**28 on typical GNUish hosts, and 2**13 on MSVC. To be portable
94 to MSVC through at least version 10.0, A should be an integer
95 constant, as MSVC does not support expressions such as 1 << 3.
96 To be portable to Sun C 5.11, do not align auto variables to
97 anything stricter than their default alignment.
98
99 The following C11 requirements are not supported here:
100
101 - If A is zero, alignas has no effect.
102 - alignas can be used multiple times; the strictest one wins.
103 - alignas (TYPE) is equivalent to alignas (alignof (TYPE)).
104
105 */
106
107#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112
108# if defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER)
109# define _Alignas(a) alignas (a)
110# elif (!defined __attribute__ \
111 && ((defined __APPLE__ && defined __MACH__ \
112 ? 4 < __GNUC__ + (1 <= __GNUC_MINOR__) \
113 : __GNUC__ && !defined __ibmxl__) \
114 || (4 <= __clang_major__) \
115 || (__ia64 && (61200 <= __HP_cc || 61200 <= __HP_aCC)) \
116 || __ICC || 0x590 <= __SUNPRO_C || 0x0600 <= __xlC__))
117# define _Alignas(a) __attribute__ ((__aligned__ (a)))
118# elif 1300 <= _MSC_VER
119# define _Alignas(a) __declspec (align (a))
120# endif
121#endif
122#if ((defined _Alignas \
123 && !(defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER))) \
124 || (defined __STDC_VERSION__ && 201112 <= __STDC_VERSION__))
125# define alignas _Alignas
126#endif
127#if (defined alignas \
128 || (defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER)))
129# define __alignas_is_defined 1
130#endif
131
132/* Include <stddef.h> if needed for offsetof. */
133#if _GL_STDALIGN_NEEDS_STDDEF
134# include <stddef.h>
135#endif
136
137#endif /* _GL_STDALIGN_H */
diff --git a/gl/stdckdint.in.h b/gl/stdckdint.in.h
index 71bab5f0..91848806 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-2023 Free Software Foundation, Inc. 3 Copyright 2022-2024 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
diff --git a/gl/stddef.in.h b/gl/stddef.in.h
index 6eadcc3d..fa8998d9 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2009-2024 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
@@ -18,7 +18,7 @@
18/* Written by Eric Blake. */ 18/* Written by Eric Blake. */
19 19
20/* 20/*
21 * POSIX 2008 <stddef.h> for platforms that have issues. 21 * POSIX 2008 and ISO C 23 <stddef.h> for platforms that have issues.
22 * <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stddef.h.html> 22 * <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stddef.h.html>
23 */ 23 */
24 24
@@ -37,9 +37,9 @@
37 remember if special invocation has ever been used to obtain wint_t, 37 remember if special invocation has ever been used to obtain wint_t,
38 in which case we need to clean up NULL yet again. */ 38 in which case we need to clean up NULL yet again. */
39 39
40# if !(defined _@GUARD_PREFIX@_STDDEF_H && defined _GL_STDDEF_WINT_T) 40# if !(defined _@GUARD_PREFIX@_STDDEF_H && defined _@GUARD_PREFIX@_STDDEF_WINT_T)
41# ifdef __need_wint_t 41# ifdef __need_wint_t
42# define _GL_STDDEF_WINT_T 42# define _@GUARD_PREFIX@_STDDEF_WINT_T
43# endif 43# endif
44# @INCLUDE_NEXT@ @NEXT_STDDEF_H@ 44# @INCLUDE_NEXT@ @NEXT_STDDEF_H@
45 /* On TinyCC, make sure that the macros that indicate the special invocation 45 /* On TinyCC, make sure that the macros that indicate the special invocation
@@ -58,7 +58,7 @@
58 58
59/* On AIX 7.2, with xlc in 64-bit mode, <stddef.h> defines max_align_t to a 59/* On AIX 7.2, with xlc in 64-bit mode, <stddef.h> defines max_align_t to a
60 type with alignment 4, but 'long' has alignment 8. */ 60 type with alignment 4, but 'long' has alignment 8. */
61# if defined _AIX && defined __LP64__ 61# if defined _AIX && defined __LP64__ && !@HAVE_MAX_ALIGN_T@
62# if !GNULIB_defined_max_align_t 62# if !GNULIB_defined_max_align_t
63# ifdef _MAX_ALIGN_T 63# ifdef _MAX_ALIGN_T
64/* /usr/include/stddef.h has already defined max_align_t. Override it. */ 64/* /usr/include/stddef.h has already defined max_align_t. Override it. */
@@ -69,6 +69,7 @@ typedef long rpl_max_align_t;
69typedef long max_align_t; 69typedef long max_align_t;
70# define _MAX_ALIGN_T 70# define _MAX_ALIGN_T
71# endif 71# endif
72# define __CLANG_MAX_ALIGN_T_DEFINED
72# define GNULIB_defined_max_align_t 1 73# define GNULIB_defined_max_align_t 1
73# endif 74# endif
74# endif 75# endif
@@ -79,7 +80,7 @@ typedef long max_align_t;
79 80
80/* On NetBSD 5.0, the definition of NULL lacks proper parentheses. */ 81/* On NetBSD 5.0, the definition of NULL lacks proper parentheses. */
81# if (@REPLACE_NULL@ \ 82# if (@REPLACE_NULL@ \
82 && (!defined _@GUARD_PREFIX@_STDDEF_H || defined _GL_STDDEF_WINT_T)) 83 && (!defined _@GUARD_PREFIX@_STDDEF_H || defined _@GUARD_PREFIX@_STDDEF_WINT_T))
83# undef NULL 84# undef NULL
84# ifdef __cplusplus 85# ifdef __cplusplus
85 /* ISO C++ says that the macro NULL must expand to an integer constant 86 /* ISO C++ says that the macro NULL must expand to an integer constant
@@ -100,6 +101,33 @@ typedef long max_align_t;
100# ifndef _@GUARD_PREFIX@_STDDEF_H 101# ifndef _@GUARD_PREFIX@_STDDEF_H
101# define _@GUARD_PREFIX@_STDDEF_H 102# define _@GUARD_PREFIX@_STDDEF_H
102 103
104/* This file uses _Noreturn, _GL_ATTRIBUTE_NOTHROW. */
105#if !_GL_CONFIG_H_INCLUDED
106 #error "Please include config.h first."
107#endif
108
109/* _GL_ATTRIBUTE_NOTHROW declares that the function does not throw exceptions.
110 */
111#ifndef _GL_ATTRIBUTE_NOTHROW
112# if defined __cplusplus
113# if (__GNUC__ + (__GNUC_MINOR__ >= 8) > 2) || __clang_major >= 4
114# if __cplusplus >= 201103L
115# define _GL_ATTRIBUTE_NOTHROW noexcept (true)
116# else
117# define _GL_ATTRIBUTE_NOTHROW throw ()
118# endif
119# else
120# define _GL_ATTRIBUTE_NOTHROW
121# endif
122# else
123# if (__GNUC__ + (__GNUC_MINOR__ >= 3) > 3) || defined __clang__
124# define _GL_ATTRIBUTE_NOTHROW __attribute__ ((__nothrow__))
125# else
126# define _GL_ATTRIBUTE_NOTHROW
127# endif
128# endif
129#endif
130
103/* Some platforms lack wchar_t. */ 131/* Some platforms lack wchar_t. */
104#if !@HAVE_WCHAR_T@ 132#if !@HAVE_WCHAR_T@
105# define wchar_t int 133# define wchar_t int
@@ -137,11 +165,49 @@ typedef union
137 long int __i _GL_STDDEF_ALIGNAS (long int); 165 long int __i _GL_STDDEF_ALIGNAS (long int);
138} rpl_max_align_t; 166} rpl_max_align_t;
139# define max_align_t rpl_max_align_t 167# define max_align_t rpl_max_align_t
168# define __CLANG_MAX_ALIGN_T_DEFINED
140# define GNULIB_defined_max_align_t 1 169# define GNULIB_defined_max_align_t 1
141# endif 170# endif
142# endif 171# endif
143#endif 172#endif
144 173
174/* ISO C 23 § 7.21.1 The unreachable macro */
175#ifndef unreachable
176
177/* Code borrowed from verify.h. */
178# ifndef _GL_HAS_BUILTIN_UNREACHABLE
179# if defined __clang_major__ && __clang_major__ < 5
180# define _GL_HAS_BUILTIN_UNREACHABLE 0
181# elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__)
182# define _GL_HAS_BUILTIN_UNREACHABLE 1
183# elif defined __has_builtin
184# define _GL_HAS_BUILTIN_UNREACHABLE __has_builtin (__builtin_unreachable)
185# else
186# define _GL_HAS_BUILTIN_UNREACHABLE 0
187# endif
188# endif
189
190# if _GL_HAS_BUILTIN_UNREACHABLE
191# define unreachable() __builtin_unreachable ()
192# elif 1200 <= _MSC_VER
193# define unreachable() __assume (0)
194# else
195/* Declare abort(), without including <stdlib.h>. */
196extern
197# if defined __cplusplus
198"C"
199# endif
200_Noreturn
201void abort (void)
202# if defined __cplusplus && (__GLIBC__ >= 2)
203_GL_ATTRIBUTE_NOTHROW
204# endif
205;
206# define unreachable() abort ()
207# endif
208
209#endif
210
145# endif /* _@GUARD_PREFIX@_STDDEF_H */ 211# endif /* _@GUARD_PREFIX@_STDDEF_H */
146# endif /* _@GUARD_PREFIX@_STDDEF_H */ 212# endif /* _@GUARD_PREFIX@_STDDEF_H */
147#endif /* __need_XXX */ 213#endif /* __need_XXX */
diff --git a/gl/stdint.in.h b/gl/stdint.in.h
index 5ddc644b..fea7483b 100644
--- a/gl/stdint.in.h
+++ b/gl/stdint.in.h
@@ -1,4 +1,4 @@
1/* Copyright (C) 2001-2002, 2004-2023 Free Software Foundation, Inc. 1/* Copyright (C) 2001-2002, 2004-2024 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
@@ -306,6 +306,8 @@ typedef gl_uint_fast32_t gl_uint_fast16_t;
306 uintptr_t to avoid conflicting declarations of system functions like 306 uintptr_t to avoid conflicting declarations of system functions like
307 _findclose in <io.h>. */ 307 _findclose in <io.h>. */
308# if !((defined __KLIBC__ && defined _INTPTR_T_DECLARED) \ 308# if !((defined __KLIBC__ && defined _INTPTR_T_DECLARED) \
309 || (defined __INTPTR_WIDTH__ \
310 && __INTPTR_WIDTH__ != (defined _WIN64 ? LLONG_WIDTH : LONG_WIDTH)) \
309 || defined __MINGW32__) 311 || defined __MINGW32__)
310# undef intptr_t 312# undef intptr_t
311# undef uintptr_t 313# undef uintptr_t
diff --git a/gl/stdio-impl.h b/gl/stdio-impl.h
index 46608bed..63ebf7c6 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2007-2008, 2010-2024 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/stdio-read.c b/gl/stdio-read.c
index 6e2984c5..253b8aa4 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2008-2024 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 9cf36cca..ca6aa00c 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2008-2024 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/stdio.in.h b/gl/stdio.in.h
index 59cbea3d..35b9f748 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2004, 2007-2024 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,6 +36,18 @@
36 36
37#ifndef _@GUARD_PREFIX@_STDIO_H 37#ifndef _@GUARD_PREFIX@_STDIO_H
38 38
39/* Suppress macOS deprecation warnings for sprintf and vsprintf. */
40#if (defined __APPLE__ && defined __MACH__) && !defined _POSIX_C_SOURCE
41# ifdef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
42# include <AvailabilityMacros.h>
43# endif
44# if (defined MAC_OS_X_VERSION_MIN_REQUIRED \
45 && 130000 <= MAC_OS_X_VERSION_MIN_REQUIRED)
46# define _POSIX_C_SOURCE 200809L
47# define _GL_DEFINED__POSIX_C_SOURCE
48# endif
49#endif
50
39#define _GL_ALREADY_INCLUDING_STDIO_H 51#define _GL_ALREADY_INCLUDING_STDIO_H
40 52
41/* The include_next requires a split double-inclusion guard. */ 53/* The include_next requires a split double-inclusion guard. */
@@ -43,9 +55,21 @@
43 55
44#undef _GL_ALREADY_INCLUDING_STDIO_H 56#undef _GL_ALREADY_INCLUDING_STDIO_H
45 57
58#ifdef _GL_DEFINED__POSIX_C_SOURCE
59# undef _GL_DEFINED__POSIX_C_SOURCE
60# undef _POSIX_C_SOURCE
61#endif
62
46#ifndef _@GUARD_PREFIX@_STDIO_H 63#ifndef _@GUARD_PREFIX@_STDIO_H
47#define _@GUARD_PREFIX@_STDIO_H 64#define _@GUARD_PREFIX@_STDIO_H
48 65
66/* This file uses _GL_ATTRIBUTE_DEALLOC, _GL_ATTRIBUTE_FORMAT,
67 _GL_ATTRIBUTE_MALLOC, _GL_ATTRIBUTE_NOTHROW, GNULIB_POSIXCHECK,
68 HAVE_RAW_DECL_*. */
69#if !_GL_CONFIG_H_INCLUDED
70 #error "Please include config.h first."
71#endif
72
49/* Get va_list. Needed on many systems, including glibc 2.8. */ 73/* Get va_list. Needed on many systems, including glibc 2.8. */
50#include <stdarg.h> 74#include <stdarg.h>
51 75
@@ -116,6 +140,38 @@
116# endif 140# endif
117#endif 141#endif
118 142
143/* _GL_ATTRIBUTE_MALLOC declares that the function returns a pointer to freshly
144 allocated memory. */
145#ifndef _GL_ATTRIBUTE_MALLOC
146# if __GNUC__ >= 3 || defined __clang__
147# define _GL_ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
148# else
149# define _GL_ATTRIBUTE_MALLOC
150# endif
151#endif
152
153/* _GL_ATTRIBUTE_NOTHROW declares that the function does not throw exceptions.
154 */
155#ifndef _GL_ATTRIBUTE_NOTHROW
156# if defined __cplusplus
157# if (__GNUC__ + (__GNUC_MINOR__ >= 8) > 2) || __clang_major >= 4
158# if __cplusplus >= 201103L
159# define _GL_ATTRIBUTE_NOTHROW noexcept (true)
160# else
161# define _GL_ATTRIBUTE_NOTHROW throw ()
162# endif
163# else
164# define _GL_ATTRIBUTE_NOTHROW
165# endif
166# else
167# if (__GNUC__ + (__GNUC_MINOR__ >= 3) > 3) || defined __clang__
168# define _GL_ATTRIBUTE_NOTHROW __attribute__ ((__nothrow__))
169# else
170# define _GL_ATTRIBUTE_NOTHROW
171# endif
172# endif
173#endif
174
119/* An __attribute__ __format__ specifier for a function that takes a format 175/* An __attribute__ __format__ specifier for a function that takes a format
120 string and arguments, where the format string directives are the ones 176 string and arguments, where the format string directives are the ones
121 standardized by ISO C99 and POSIX. 177 standardized by ISO C99 and POSIX.
@@ -193,6 +249,36 @@
193# undef putc_unlocked 249# undef putc_unlocked
194#endif 250#endif
195 251
252
253/* Maximum number of characters produced by printing a NaN value. */
254#ifndef _PRINTF_NAN_LEN_MAX
255# if defined __FreeBSD__ || defined __DragonFly__ \
256 || defined __NetBSD__ \
257 || (defined __APPLE__ && defined __MACH__)
258/* On BSD systems, a NaN value prints as just "nan", without a sign. */
259# define _PRINTF_NAN_LEN_MAX 3
260# elif (__GLIBC__ >= 2) || MUSL_LIBC || defined __OpenBSD__ || defined __sun || defined __CYGWIN__
261/* glibc, musl libc, OpenBSD, Solaris libc, and Cygwin produce "[-]nan". */
262# define _PRINTF_NAN_LEN_MAX 4
263# elif defined _AIX
264/* AIX produces "[-]NaNQ". */
265# define _PRINTF_NAN_LEN_MAX 5
266# elif defined _WIN32 && !defined __CYGWIN__
267/* On native Windows, the output can be:
268 - with MSVC ucrt: "[-]nan" or "[-]nan(ind)" or "[-]nan(snan)",
269 - with mingw: "[-]1.#IND" or "[-]1.#QNAN". */
270# define _PRINTF_NAN_LEN_MAX 10
271# elif defined __sgi
272/* On IRIX, the output typically is "[-]nan0xNNNNNNNN" with 8 hexadecimal
273 digits. */
274# define _PRINTF_NAN_LEN_MAX 14
275# else
276/* We don't know, but 32 should be a safe maximum. */
277# define _PRINTF_NAN_LEN_MAX 32
278# endif
279#endif
280
281
196#if @GNULIB_DPRINTF@ 282#if @GNULIB_DPRINTF@
197# if @REPLACE_DPRINTF@ 283# if @REPLACE_DPRINTF@
198# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 284# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -210,7 +296,9 @@ _GL_FUNCDECL_SYS (dprintf, int, (int fd, const char *restrict format, ...)
210# endif 296# endif
211_GL_CXXALIAS_SYS (dprintf, int, (int fd, const char *restrict format, ...)); 297_GL_CXXALIAS_SYS (dprintf, int, (int fd, const char *restrict format, ...));
212# endif 298# endif
299# if __GLIBC__ >= 2
213_GL_CXXALIASWARN (dprintf); 300_GL_CXXALIASWARN (dprintf);
301# endif
214#elif defined GNULIB_POSIXCHECK 302#elif defined GNULIB_POSIXCHECK
215# undef dprintf 303# undef dprintf
216# if HAVE_RAW_DECL_DPRINTF 304# if HAVE_RAW_DECL_DPRINTF
@@ -273,7 +361,8 @@ _GL_CXXALIASWARN (fcloseall);
273# endif 361# endif
274_GL_FUNCDECL_RPL (fdopen, FILE *, 362_GL_FUNCDECL_RPL (fdopen, FILE *,
275 (int fd, const char *mode) 363 (int fd, const char *mode)
276 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1)); 364 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1)
365 _GL_ATTRIBUTE_MALLOC);
277_GL_CXXALIAS_RPL (fdopen, FILE *, (int fd, const char *mode)); 366_GL_CXXALIAS_RPL (fdopen, FILE *, (int fd, const char *mode));
278# elif defined _WIN32 && !defined __CYGWIN__ 367# elif defined _WIN32 && !defined __CYGWIN__
279# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 368# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -284,9 +373,18 @@ _GL_CXXALIAS_MDA (fdopen, FILE *, (int fd, const char *mode));
284# else 373# else
285# if __GNUC__ >= 11 374# if __GNUC__ >= 11
286/* For -Wmismatched-dealloc: Associate fdopen with fclose or rpl_fclose. */ 375/* For -Wmismatched-dealloc: Associate fdopen with fclose or rpl_fclose. */
376# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
287_GL_FUNCDECL_SYS (fdopen, FILE *, 377_GL_FUNCDECL_SYS (fdopen, FILE *,
288 (int fd, const char *mode) 378 (int fd, const char *mode)
289 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1)); 379 _GL_ATTRIBUTE_NOTHROW
380 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1)
381 _GL_ATTRIBUTE_MALLOC);
382# else
383_GL_FUNCDECL_SYS (fdopen, FILE *,
384 (int fd, const char *mode)
385 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1)
386 _GL_ATTRIBUTE_MALLOC);
387# endif
290# endif 388# endif
291_GL_CXXALIAS_SYS (fdopen, FILE *, (int fd, const char *mode)); 389_GL_CXXALIAS_SYS (fdopen, FILE *, (int fd, const char *mode));
292# endif 390# endif
@@ -294,9 +392,18 @@ _GL_CXXALIASWARN (fdopen);
294#else 392#else
295# if @GNULIB_FCLOSE@ && __GNUC__ >= 11 && !defined fdopen 393# if @GNULIB_FCLOSE@ && __GNUC__ >= 11 && !defined fdopen
296/* For -Wmismatched-dealloc: Associate fdopen with fclose or rpl_fclose. */ 394/* For -Wmismatched-dealloc: Associate fdopen with fclose or rpl_fclose. */
395# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
396_GL_FUNCDECL_SYS (fdopen, FILE *,
397 (int fd, const char *mode)
398 _GL_ATTRIBUTE_NOTHROW
399 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1)
400 _GL_ATTRIBUTE_MALLOC);
401# else
297_GL_FUNCDECL_SYS (fdopen, FILE *, 402_GL_FUNCDECL_SYS (fdopen, FILE *,
298 (int fd, const char *mode) 403 (int fd, const char *mode)
299 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1)); 404 _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1)
405 _GL_ATTRIBUTE_MALLOC);
406# endif
300# endif 407# endif
301# if defined GNULIB_POSIXCHECK 408# if defined GNULIB_POSIXCHECK
302# undef fdopen 409# undef fdopen
@@ -407,7 +514,8 @@ _GL_CXXALIASWARN (fileno);
407# endif 514# endif
408_GL_FUNCDECL_RPL (fopen, FILE *, 515_GL_FUNCDECL_RPL (fopen, FILE *,
409 (const char *restrict filename, const char *restrict mode) 516 (const char *restrict filename, const char *restrict mode)
410 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1)); 517 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1)
518 _GL_ATTRIBUTE_MALLOC);
411_GL_CXXALIAS_RPL (fopen, FILE *, 519_GL_CXXALIAS_RPL (fopen, FILE *,
412 (const char *restrict filename, const char *restrict mode)); 520 (const char *restrict filename, const char *restrict mode));
413# else 521# else
@@ -799,14 +907,14 @@ _GL_CXXALIAS_SYS (fwrite, size_t,
799 && !defined __cplusplus) 907 && !defined __cplusplus)
800# undef fwrite 908# undef fwrite
801# undef fwrite_unlocked 909# undef fwrite_unlocked
802extern size_t __REDIRECT (rpl_fwrite, 910_GL_EXTERN_C size_t __REDIRECT (rpl_fwrite,
803 (const void *__restrict, size_t, size_t, 911 (const void *__restrict, size_t, size_t,
804 FILE *__restrict), 912 FILE *__restrict),
805 fwrite); 913 fwrite);
806extern size_t __REDIRECT (rpl_fwrite_unlocked, 914_GL_EXTERN_C size_t __REDIRECT (rpl_fwrite_unlocked,
807 (const void *__restrict, size_t, size_t, 915 (const void *__restrict, size_t, size_t,
808 FILE *__restrict), 916 FILE *__restrict),
809 fwrite_unlocked); 917 fwrite_unlocked);
810# define fwrite rpl_fwrite 918# define fwrite rpl_fwrite
811# define fwrite_unlocked rpl_fwrite_unlocked 919# define fwrite_unlocked rpl_fwrite_unlocked
812# endif 920# endif
@@ -882,7 +990,9 @@ _GL_CXXALIAS_SYS (getdelim, ssize_t,
882 int delimiter, 990 int delimiter,
883 FILE *restrict stream)); 991 FILE *restrict stream));
884# endif 992# endif
993# if __GLIBC__ >= 2
885_GL_CXXALIASWARN (getdelim); 994_GL_CXXALIASWARN (getdelim);
995# endif
886#elif defined GNULIB_POSIXCHECK 996#elif defined GNULIB_POSIXCHECK
887# undef getdelim 997# undef getdelim
888# if HAVE_RAW_DECL_GETDELIM 998# if HAVE_RAW_DECL_GETDELIM
@@ -921,7 +1031,7 @@ _GL_CXXALIAS_SYS (getline, ssize_t,
921 (char **restrict lineptr, size_t *restrict linesize, 1031 (char **restrict lineptr, size_t *restrict linesize,
922 FILE *restrict stream)); 1032 FILE *restrict stream));
923# endif 1033# endif
924# if @HAVE_DECL_GETLINE@ 1034# if __GLIBC__ >= 2 && @HAVE_DECL_GETLINE@
925_GL_CXXALIASWARN (getline); 1035_GL_CXXALIASWARN (getline);
926# endif 1036# endif
927#elif defined GNULIB_POSIXCHECK 1037#elif defined GNULIB_POSIXCHECK
@@ -951,9 +1061,17 @@ _GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead");
951# endif 1061# endif
952_GL_CXXALIAS_MDA (getw, int, (FILE *restrict stream)); 1062_GL_CXXALIAS_MDA (getw, int, (FILE *restrict stream));
953# else 1063# else
1064# if @HAVE_DECL_GETW@
1065# if defined __APPLE__ && defined __MACH__
1066/* The presence of the declaration depends on _POSIX_C_SOURCE. */
1067_GL_FUNCDECL_SYS (getw, int, (FILE *restrict stream));
1068# endif
954_GL_CXXALIAS_SYS (getw, int, (FILE *restrict stream)); 1069_GL_CXXALIAS_SYS (getw, int, (FILE *restrict stream));
1070# endif
955# endif 1071# endif
1072# if __GLIBC__ >= 2
956_GL_CXXALIASWARN (getw); 1073_GL_CXXALIASWARN (getw);
1074# endif
957#endif 1075#endif
958 1076
959#if @GNULIB_OBSTACK_PRINTF@ || @GNULIB_OBSTACK_PRINTF_POSIX@ 1077#if @GNULIB_OBSTACK_PRINTF@ || @GNULIB_OBSTACK_PRINTF_POSIX@
@@ -1052,13 +1170,15 @@ _GL_WARN_ON_USE (perror, "perror is not always POSIX compliant - "
1052# endif 1170# endif
1053_GL_FUNCDECL_RPL (popen, FILE *, 1171_GL_FUNCDECL_RPL (popen, FILE *,
1054 (const char *cmd, const char *mode) 1172 (const char *cmd, const char *mode)
1055 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (pclose, 1)); 1173 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (pclose, 1)
1174 _GL_ATTRIBUTE_MALLOC);
1056_GL_CXXALIAS_RPL (popen, FILE *, (const char *cmd, const char *mode)); 1175_GL_CXXALIAS_RPL (popen, FILE *, (const char *cmd, const char *mode));
1057# else 1176# else
1058# if !@HAVE_POPEN@ || __GNUC__ >= 11 1177# if !@HAVE_POPEN@ || __GNUC__ >= 11
1059_GL_FUNCDECL_SYS (popen, FILE *, 1178_GL_FUNCDECL_SYS (popen, FILE *,
1060 (const char *cmd, const char *mode) 1179 (const char *cmd, const char *mode)
1061 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (pclose, 1)); 1180 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (pclose, 1)
1181 _GL_ATTRIBUTE_MALLOC);
1062# endif 1182# endif
1063_GL_CXXALIAS_SYS (popen, FILE *, (const char *cmd, const char *mode)); 1183_GL_CXXALIAS_SYS (popen, FILE *, (const char *cmd, const char *mode));
1064# endif 1184# endif
@@ -1068,7 +1188,8 @@ _GL_CXXALIASWARN (popen);
1068/* For -Wmismatched-dealloc: Associate popen with pclose or rpl_pclose. */ 1188/* For -Wmismatched-dealloc: Associate popen with pclose or rpl_pclose. */
1069_GL_FUNCDECL_SYS (popen, FILE *, 1189_GL_FUNCDECL_SYS (popen, FILE *,
1070 (const char *cmd, const char *mode) 1190 (const char *cmd, const char *mode)
1071 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (pclose, 1)); 1191 _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (pclose, 1)
1192 _GL_ATTRIBUTE_MALLOC);
1072# endif 1193# endif
1073# if defined GNULIB_POSIXCHECK 1194# if defined GNULIB_POSIXCHECK
1074# undef popen 1195# undef popen
@@ -1190,9 +1311,17 @@ _GL_CXXALIASWARN (puts);
1190# endif 1311# endif
1191_GL_CXXALIAS_MDA (putw, int, (int w, FILE *restrict stream)); 1312_GL_CXXALIAS_MDA (putw, int, (int w, FILE *restrict stream));
1192# else 1313# else
1314# if @HAVE_DECL_PUTW@
1315# if defined __APPLE__ && defined __MACH__
1316/* The presence of the declaration depends on _POSIX_C_SOURCE. */
1317_GL_FUNCDECL_SYS (putw, int, (int w, FILE *restrict stream));
1318# endif
1193_GL_CXXALIAS_SYS (putw, int, (int w, FILE *restrict stream)); 1319_GL_CXXALIAS_SYS (putw, int, (int w, FILE *restrict stream));
1320# endif
1194# endif 1321# endif
1322# if __GLIBC__ >= 2
1195_GL_CXXALIASWARN (putw); 1323_GL_CXXALIASWARN (putw);
1324# endif
1196#endif 1325#endif
1197 1326
1198#if @GNULIB_REMOVE@ 1327#if @GNULIB_REMOVE@
@@ -1398,13 +1527,15 @@ _GL_CXXALIASWARN (tempnam);
1398# define tmpfile rpl_tmpfile 1527# define tmpfile rpl_tmpfile
1399# endif 1528# endif
1400_GL_FUNCDECL_RPL (tmpfile, FILE *, (void) 1529_GL_FUNCDECL_RPL (tmpfile, FILE *, (void)
1401 _GL_ATTRIBUTE_DEALLOC (fclose, 1)); 1530 _GL_ATTRIBUTE_DEALLOC (fclose, 1)
1531 _GL_ATTRIBUTE_MALLOC);
1402_GL_CXXALIAS_RPL (tmpfile, FILE *, (void)); 1532_GL_CXXALIAS_RPL (tmpfile, FILE *, (void));
1403# else 1533# else
1404# if __GNUC__ >= 11 1534# if __GNUC__ >= 11
1405/* For -Wmismatched-dealloc: Associate tmpfile with fclose or rpl_fclose. */ 1535/* For -Wmismatched-dealloc: Associate tmpfile with fclose or rpl_fclose. */
1406_GL_FUNCDECL_SYS (tmpfile, FILE *, (void) 1536_GL_FUNCDECL_SYS (tmpfile, FILE *, (void)
1407 _GL_ATTRIBUTE_DEALLOC (fclose, 1)); 1537 _GL_ATTRIBUTE_DEALLOC (fclose, 1)
1538 _GL_ATTRIBUTE_MALLOC);
1408# endif 1539# endif
1409_GL_CXXALIAS_SYS (tmpfile, FILE *, (void)); 1540_GL_CXXALIAS_SYS (tmpfile, FILE *, (void));
1410# endif 1541# endif
@@ -1415,7 +1546,8 @@ _GL_CXXALIASWARN (tmpfile);
1415# if @GNULIB_FCLOSE@ && __GNUC__ >= 11 && !defined tmpfile 1546# if @GNULIB_FCLOSE@ && __GNUC__ >= 11 && !defined tmpfile
1416/* For -Wmismatched-dealloc: Associate tmpfile with fclose or rpl_fclose. */ 1547/* For -Wmismatched-dealloc: Associate tmpfile with fclose or rpl_fclose. */
1417_GL_FUNCDECL_SYS (tmpfile, FILE *, (void) 1548_GL_FUNCDECL_SYS (tmpfile, FILE *, (void)
1418 _GL_ATTRIBUTE_DEALLOC (fclose, 1)); 1549 _GL_ATTRIBUTE_DEALLOC (fclose, 1)
1550 _GL_ATTRIBUTE_MALLOC);
1419# endif 1551# endif
1420# if defined GNULIB_POSIXCHECK 1552# if defined GNULIB_POSIXCHECK
1421# undef tmpfile 1553# undef tmpfile
diff --git a/gl/stdlib.in.h b/gl/stdlib.in.h
index b79e5f70..e74e7c18 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 1995, 2001-2004, 2006-2024 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,6 +37,13 @@
37#ifndef _@GUARD_PREFIX@_STDLIB_H 37#ifndef _@GUARD_PREFIX@_STDLIB_H
38#define _@GUARD_PREFIX@_STDLIB_H 38#define _@GUARD_PREFIX@_STDLIB_H
39 39
40/* This file uses _Noreturn, _GL_ATTRIBUTE_DEALLOC, _GL_ATTRIBUTE_MALLOC,
41 _GL_ATTRIBUTE_NOTHROW, _GL_ATTRIBUTE_PURE, GNULIB_POSIXCHECK,
42 HAVE_RAW_DECL_*. */
43#if !_GL_CONFIG_H_INCLUDED
44 #error "Please include config.h first."
45#endif
46
40/* NetBSD 5.0 mis-defines NULL. */ 47/* NetBSD 5.0 mis-defines NULL. */
41#include <stddef.h> 48#include <stddef.h>
42 49
@@ -67,9 +74,7 @@
67# include <random.h> 74# include <random.h>
68# endif 75# endif
69 76
70# if !@HAVE_STRUCT_RANDOM_DATA@ || @REPLACE_RANDOM_R@ || !@HAVE_RANDOM_R@ 77# include <stdint.h>
71# include <stdint.h>
72# endif
73 78
74# if !@HAVE_STRUCT_RANDOM_DATA@ 79# if !@HAVE_STRUCT_RANDOM_DATA@
75/* Define 'struct random_data'. 80/* Define 'struct random_data'.
@@ -128,6 +133,28 @@ struct random_data
128# endif 133# endif
129#endif 134#endif
130 135
136/* _GL_ATTRIBUTE_NOTHROW declares that the function does not throw exceptions.
137 */
138#ifndef _GL_ATTRIBUTE_NOTHROW
139# if defined __cplusplus
140# if (__GNUC__ + (__GNUC_MINOR__ >= 8) > 2) || __clang_major >= 4
141# if __cplusplus >= 201103L
142# define _GL_ATTRIBUTE_NOTHROW noexcept (true)
143# else
144# define _GL_ATTRIBUTE_NOTHROW throw ()
145# endif
146# else
147# define _GL_ATTRIBUTE_NOTHROW
148# endif
149# else
150# if (__GNUC__ + (__GNUC_MINOR__ >= 3) > 3) || defined __clang__
151# define _GL_ATTRIBUTE_NOTHROW __attribute__ ((__nothrow__))
152# else
153# define _GL_ATTRIBUTE_NOTHROW
154# endif
155# endif
156#endif
157
131/* The __attribute__ feature is available in gcc versions 2.5 and later. 158/* The __attribute__ feature is available in gcc versions 2.5 and later.
132 The attribute __pure__ was added in gcc 2.96. */ 159 The attribute __pure__ was added in gcc 2.96. */
133#ifndef _GL_ATTRIBUTE_PURE 160#ifndef _GL_ATTRIBUTE_PURE
@@ -164,11 +191,22 @@ struct random_data
164#if @GNULIB__EXIT@ 191#if @GNULIB__EXIT@
165/* Terminate the current process with the given return code, without running 192/* Terminate the current process with the given return code, without running
166 the 'atexit' handlers. */ 193 the 'atexit' handlers. */
167# if !@HAVE__EXIT@ 194# if @REPLACE__EXIT@
195# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
196# undef _Exit
197# define _Exit rpl__Exit
198# endif
199_GL_FUNCDECL_RPL (_Exit, _Noreturn void, (int status));
200_GL_CXXALIAS_RPL (_Exit, void, (int status));
201# else
202# if !@HAVE__EXIT@
168_GL_FUNCDECL_SYS (_Exit, _Noreturn void, (int status)); 203_GL_FUNCDECL_SYS (_Exit, _Noreturn void, (int status));
169# endif 204# endif
170_GL_CXXALIAS_SYS (_Exit, void, (int status)); 205_GL_CXXALIAS_SYS (_Exit, void, (int status));
206# endif
207# if __GLIBC__ >= 2
171_GL_CXXALIASWARN (_Exit); 208_GL_CXXALIASWARN (_Exit);
209# endif
172#elif defined GNULIB_POSIXCHECK 210#elif defined GNULIB_POSIXCHECK
173# undef _Exit 211# undef _Exit
174# if HAVE_RAW_DECL__EXIT 212# if HAVE_RAW_DECL__EXIT
@@ -185,7 +223,7 @@ _GL_WARN_ON_USE (_Exit, "_Exit is unportable - "
185# define free rpl_free 223# define free rpl_free
186# endif 224# endif
187# if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2) 225# if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2)
188_GL_FUNCDECL_RPL (free, void, (void *ptr) throw ()); 226_GL_FUNCDECL_RPL (free, void, (void *ptr) _GL_ATTRIBUTE_NOTHROW);
189# else 227# else
190_GL_FUNCDECL_RPL (free, void, (void *ptr)); 228_GL_FUNCDECL_RPL (free, void, (void *ptr));
191# endif 229# endif
@@ -219,9 +257,16 @@ _GL_CXXALIAS_RPL (aligned_alloc, void *, (size_t alignment, size_t size));
219# if @HAVE_ALIGNED_ALLOC@ 257# if @HAVE_ALIGNED_ALLOC@
220# if __GNUC__ >= 11 258# if __GNUC__ >= 11
221/* For -Wmismatched-dealloc: Associate aligned_alloc with free or rpl_free. */ 259/* For -Wmismatched-dealloc: Associate aligned_alloc with free or rpl_free. */
260# if __GLIBC__ + (__GLIBC_MINOR__ >= 16) > 2
261_GL_FUNCDECL_SYS (aligned_alloc, void *,
262 (size_t alignment, size_t size)
263 _GL_ATTRIBUTE_NOTHROW
264 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
265# else
222_GL_FUNCDECL_SYS (aligned_alloc, void *, 266_GL_FUNCDECL_SYS (aligned_alloc, void *,
223 (size_t alignment, size_t size) 267 (size_t alignment, size_t size)
224 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 268 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
269# endif
225# endif 270# endif
226_GL_CXXALIAS_SYS (aligned_alloc, void *, (size_t alignment, size_t size)); 271_GL_CXXALIAS_SYS (aligned_alloc, void *, (size_t alignment, size_t size));
227# endif 272# endif
@@ -232,9 +277,16 @@ _GL_CXXALIASWARN (aligned_alloc);
232#else 277#else
233# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined aligned_alloc 278# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined aligned_alloc
234/* For -Wmismatched-dealloc: Associate aligned_alloc with free or rpl_free. */ 279/* For -Wmismatched-dealloc: Associate aligned_alloc with free or rpl_free. */
280# if __GLIBC__ + (__GLIBC_MINOR__ >= 16) > 2
235_GL_FUNCDECL_SYS (aligned_alloc, void *, 281_GL_FUNCDECL_SYS (aligned_alloc, void *,
236 (size_t alignment, size_t size) 282 (size_t alignment, size_t size)
283 _GL_ATTRIBUTE_NOTHROW
237 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 284 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
285# else
286_GL_FUNCDECL_SYS (aligned_alloc, void *,
287 (size_t alignment, size_t size)
288 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
289# endif
238# endif 290# endif
239# if defined GNULIB_POSIXCHECK 291# if defined GNULIB_POSIXCHECK
240# undef aligned_alloc 292# undef aligned_alloc
@@ -277,9 +329,16 @@ _GL_CXXALIAS_RPL (calloc, void *, (size_t nmemb, size_t size));
277# else 329# else
278# if __GNUC__ >= 11 330# if __GNUC__ >= 11
279/* For -Wmismatched-dealloc: Associate calloc with free or rpl_free. */ 331/* For -Wmismatched-dealloc: Associate calloc with free or rpl_free. */
332# if __GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2
280_GL_FUNCDECL_SYS (calloc, void *, 333_GL_FUNCDECL_SYS (calloc, void *,
281 (size_t nmemb, size_t size) 334 (size_t nmemb, size_t size)
335 _GL_ATTRIBUTE_NOTHROW
282 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 336 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
337# else
338_GL_FUNCDECL_SYS (calloc, void *,
339 (size_t nmemb, size_t size)
340 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
341# endif
283# endif 342# endif
284_GL_CXXALIAS_SYS (calloc, void *, (size_t nmemb, size_t size)); 343_GL_CXXALIAS_SYS (calloc, void *, (size_t nmemb, size_t size));
285# endif 344# endif
@@ -289,9 +348,16 @@ _GL_CXXALIASWARN (calloc);
289#else 348#else
290# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined calloc 349# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined calloc
291/* For -Wmismatched-dealloc: Associate calloc with free or rpl_free. */ 350/* For -Wmismatched-dealloc: Associate calloc with free or rpl_free. */
351# if __GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2
352_GL_FUNCDECL_SYS (calloc, void *,
353 (size_t nmemb, size_t size)
354 _GL_ATTRIBUTE_NOTHROW
355 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
356# else
292_GL_FUNCDECL_SYS (calloc, void *, 357_GL_FUNCDECL_SYS (calloc, void *,
293 (size_t nmemb, size_t size) 358 (size_t nmemb, size_t size)
294 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 359 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
360# endif
295# endif 361# endif
296# if defined GNULIB_POSIXCHECK 362# if defined GNULIB_POSIXCHECK
297# undef calloc 363# undef calloc
@@ -313,10 +379,18 @@ _GL_FUNCDECL_RPL (canonicalize_file_name, char *,
313_GL_CXXALIAS_RPL (canonicalize_file_name, char *, (const char *name)); 379_GL_CXXALIAS_RPL (canonicalize_file_name, char *, (const char *name));
314# else 380# else
315# if !@HAVE_CANONICALIZE_FILE_NAME@ || __GNUC__ >= 11 381# if !@HAVE_CANONICALIZE_FILE_NAME@ || __GNUC__ >= 11
382# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
316_GL_FUNCDECL_SYS (canonicalize_file_name, char *, 383_GL_FUNCDECL_SYS (canonicalize_file_name, char *,
317 (const char *name) 384 (const char *name)
385 _GL_ATTRIBUTE_NOTHROW
318 _GL_ARG_NONNULL ((1)) 386 _GL_ARG_NONNULL ((1))
319 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 387 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
388# else
389_GL_FUNCDECL_SYS (canonicalize_file_name, char *,
390 (const char *name)
391 _GL_ARG_NONNULL ((1))
392 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
393# endif
320# endif 394# endif
321_GL_CXXALIAS_SYS (canonicalize_file_name, char *, (const char *name)); 395_GL_CXXALIAS_SYS (canonicalize_file_name, char *, (const char *name));
322# endif 396# endif
@@ -329,10 +403,18 @@ _GL_CXXALIASWARN (canonicalize_file_name);
329# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined canonicalize_file_name 403# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined canonicalize_file_name
330/* For -Wmismatched-dealloc: Associate canonicalize_file_name with free or 404/* For -Wmismatched-dealloc: Associate canonicalize_file_name with free or
331 rpl_free. */ 405 rpl_free. */
406# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
332_GL_FUNCDECL_SYS (canonicalize_file_name, char *, 407_GL_FUNCDECL_SYS (canonicalize_file_name, char *,
333 (const char *name) 408 (const char *name)
409 _GL_ATTRIBUTE_NOTHROW
334 _GL_ARG_NONNULL ((1)) 410 _GL_ARG_NONNULL ((1))
335 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 411 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
412# else
413_GL_FUNCDECL_SYS (canonicalize_file_name, char *,
414 (const char *name)
415 _GL_ARG_NONNULL ((1))
416 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
417# endif
336# endif 418# endif
337# if defined GNULIB_POSIXCHECK 419# if defined GNULIB_POSIXCHECK
338# undef canonicalize_file_name 420# undef canonicalize_file_name
@@ -416,12 +498,24 @@ _GL_CXXALIASWARN (gcvt);
416 The three numbers are the load average of the last 1 minute, the last 5 498 The three numbers are the load average of the last 1 minute, the last 5
417 minutes, and the last 15 minutes, respectively. 499 minutes, and the last 15 minutes, respectively.
418 LOADAVG is an array of NELEM numbers. */ 500 LOADAVG is an array of NELEM numbers. */
419# if !@HAVE_DECL_GETLOADAVG@ 501# if @REPLACE_GETLOADAVG@
502# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
503# undef getloadavg
504# define getloadavg rpl_getloadavg
505# endif
506_GL_FUNCDECL_RPL (getloadavg, int, (double loadavg[], int nelem)
507 _GL_ARG_NONNULL ((1)));
508_GL_CXXALIAS_RPL (getloadavg, int, (double loadavg[], int nelem));
509# else
510# if !@HAVE_DECL_GETLOADAVG@
420_GL_FUNCDECL_SYS (getloadavg, int, (double loadavg[], int nelem) 511_GL_FUNCDECL_SYS (getloadavg, int, (double loadavg[], int nelem)
421 _GL_ARG_NONNULL ((1))); 512 _GL_ARG_NONNULL ((1)));
422# endif 513# endif
423_GL_CXXALIAS_SYS (getloadavg, int, (double loadavg[], int nelem)); 514_GL_CXXALIAS_SYS (getloadavg, int, (double loadavg[], int nelem));
515# endif
516# if __GLIBC__ >= 2
424_GL_CXXALIASWARN (getloadavg); 517_GL_CXXALIASWARN (getloadavg);
518# endif
425#elif defined GNULIB_POSIXCHECK 519#elif defined GNULIB_POSIXCHECK
426# undef getloadavg 520# undef getloadavg
427# if HAVE_RAW_DECL_GETLOADAVG 521# if HAVE_RAW_DECL_GETLOADAVG
@@ -430,6 +524,41 @@ _GL_WARN_ON_USE (getloadavg, "getloadavg is not portable - "
430# endif 524# endif
431#endif 525#endif
432 526
527#if @GNULIB_GETPROGNAME@
528/* Return the base name of the executing program.
529 On native Windows this will usually end in ".exe" or ".EXE". */
530# if @REPLACE_GETPROGNAME@
531# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
532# undef getprogname
533# define getprogname rpl_getprogname
534# endif
535# if @HAVE_DECL_PROGRAM_INVOCATION_NAME@
536_GL_FUNCDECL_RPL (getprogname, const char *, (void) _GL_ATTRIBUTE_PURE);
537# else
538_GL_FUNCDECL_RPL (getprogname, const char *, (void));
539# endif
540_GL_CXXALIAS_RPL (getprogname, const char *, (void));
541# else
542# if !@HAVE_GETPROGNAME@
543# if @HAVE_DECL_PROGRAM_INVOCATION_NAME@
544_GL_FUNCDECL_SYS (getprogname, const char *, (void) _GL_ATTRIBUTE_PURE);
545# else
546_GL_FUNCDECL_SYS (getprogname, const char *, (void));
547# endif
548# endif
549_GL_CXXALIAS_SYS (getprogname, const char *, (void));
550# endif
551# if __GLIBC__ >= 2
552_GL_CXXALIASWARN (getprogname);
553# endif
554#elif defined GNULIB_POSIXCHECK
555# undef getprogname
556# if HAVE_RAW_DECL_GETPROGNAME
557_GL_WARN_ON_USE (getprogname, "getprogname is unportable - "
558 "use gnulib module getprogname for portability");
559# endif
560#endif
561
433#if @GNULIB_GETSUBOPT@ 562#if @GNULIB_GETSUBOPT@
434/* Assuming *OPTIONP is a comma separated list of elements of the form 563/* Assuming *OPTIONP is a comma separated list of elements of the form
435 "token" or "token=value", getsubopt parses the first of these elements. 564 "token" or "token=value", getsubopt parses the first of these elements.
@@ -442,14 +571,28 @@ _GL_WARN_ON_USE (getloadavg, "getloadavg is not portable - "
442 Otherwise it returns -1, and *OPTIONP and *VALUEP are undefined. 571 Otherwise it returns -1, and *OPTIONP and *VALUEP are undefined.
443 For more details see the POSIX specification. 572 For more details see the POSIX specification.
444 https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsubopt.html */ 573 https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsubopt.html */
445# if !@HAVE_GETSUBOPT@ 574# if @REPLACE_GETSUBOPT@
575# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
576# undef getsubopt
577# define getsubopt rpl_getsubopt
578# endif
579_GL_FUNCDECL_RPL (getsubopt, int,
580 (char **optionp, char *const *tokens, char **valuep)
581 _GL_ARG_NONNULL ((1, 2, 3)));
582_GL_CXXALIAS_RPL (getsubopt, int,
583 (char **optionp, char *const *tokens, char **valuep));
584# else
585# if !@HAVE_GETSUBOPT@
446_GL_FUNCDECL_SYS (getsubopt, int, 586_GL_FUNCDECL_SYS (getsubopt, int,
447 (char **optionp, char *const *tokens, char **valuep) 587 (char **optionp, char *const *tokens, char **valuep)
448 _GL_ARG_NONNULL ((1, 2, 3))); 588 _GL_ARG_NONNULL ((1, 2, 3)));
449# endif 589# endif
450_GL_CXXALIAS_SYS (getsubopt, int, 590_GL_CXXALIAS_SYS (getsubopt, int,
451 (char **optionp, char *const *tokens, char **valuep)); 591 (char **optionp, char *const *tokens, char **valuep));
592# endif
593# if __GLIBC__ >= 2
452_GL_CXXALIASWARN (getsubopt); 594_GL_CXXALIASWARN (getsubopt);
595# endif
453#elif defined GNULIB_POSIXCHECK 596#elif defined GNULIB_POSIXCHECK
454# undef getsubopt 597# undef getsubopt
455# if HAVE_RAW_DECL_GETSUBOPT 598# if HAVE_RAW_DECL_GETSUBOPT
@@ -493,9 +636,16 @@ _GL_CXXALIAS_RPL (malloc, void *, (size_t size));
493# else 636# else
494# if __GNUC__ >= 11 637# if __GNUC__ >= 11
495/* For -Wmismatched-dealloc: Associate malloc with free or rpl_free. */ 638/* For -Wmismatched-dealloc: Associate malloc with free or rpl_free. */
639# if __GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2
496_GL_FUNCDECL_SYS (malloc, void *, 640_GL_FUNCDECL_SYS (malloc, void *,
497 (size_t size) 641 (size_t size)
642 _GL_ATTRIBUTE_NOTHROW
498 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 643 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
644# else
645_GL_FUNCDECL_SYS (malloc, void *,
646 (size_t size)
647 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
648# endif
499# endif 649# endif
500_GL_CXXALIAS_SYS (malloc, void *, (size_t size)); 650_GL_CXXALIAS_SYS (malloc, void *, (size_t size));
501# endif 651# endif
@@ -505,9 +655,16 @@ _GL_CXXALIASWARN (malloc);
505#else 655#else
506# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined malloc 656# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined malloc
507/* For -Wmismatched-dealloc: Associate malloc with free or rpl_free. */ 657/* For -Wmismatched-dealloc: Associate malloc with free or rpl_free. */
658# if __GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2
659_GL_FUNCDECL_SYS (malloc, void *,
660 (size_t size)
661 _GL_ATTRIBUTE_NOTHROW
662 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
663# else
508_GL_FUNCDECL_SYS (malloc, void *, 664_GL_FUNCDECL_SYS (malloc, void *,
509 (size_t size) 665 (size_t size)
510 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 666 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
667# endif
511# endif 668# endif
512# if defined GNULIB_POSIXCHECK && !_GL_USE_STDLIB_ALLOC 669# if defined GNULIB_POSIXCHECK && !_GL_USE_STDLIB_ALLOC
513# undef malloc 670# undef malloc
@@ -517,6 +674,51 @@ _GL_WARN_ON_USE (malloc, "malloc is not POSIX compliant everywhere - "
517# endif 674# endif
518#endif 675#endif
519 676
677/* Return maximum number of bytes of a multibyte character. */
678#if @REPLACE_MB_CUR_MAX@
679# if !GNULIB_defined_MB_CUR_MAX
680static inline
681int gl_MB_CUR_MAX (void)
682{
683 /* Turn the value 3 to the value 4, as needed for the UTF-8 encoding. */
684 return MB_CUR_MAX + (MB_CUR_MAX == 3);
685}
686# undef MB_CUR_MAX
687# define MB_CUR_MAX gl_MB_CUR_MAX ()
688# define GNULIB_defined_MB_CUR_MAX 1
689# endif
690#endif
691
692/* Convert a string to a wide string. */
693#if @GNULIB_MBSTOWCS@
694# if @REPLACE_MBSTOWCS@
695# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
696# undef mbstowcs
697# define mbstowcs rpl_mbstowcs
698# endif
699_GL_FUNCDECL_RPL (mbstowcs, size_t,
700 (wchar_t *restrict dest, const char *restrict src,
701 size_t len)
702 _GL_ARG_NONNULL ((2)));
703_GL_CXXALIAS_RPL (mbstowcs, size_t,
704 (wchar_t *restrict dest, const char *restrict src,
705 size_t len));
706# else
707_GL_CXXALIAS_SYS (mbstowcs, size_t,
708 (wchar_t *restrict dest, const char *restrict src,
709 size_t len));
710# endif
711# if __GLIBC__ >= 2
712_GL_CXXALIASWARN (mbstowcs);
713# endif
714#elif defined GNULIB_POSIXCHECK
715# undef mbstowcs
716# if HAVE_RAW_DECL_MBSTOWCS
717_GL_WARN_ON_USE (mbstowcs, "mbstowcs is unportable - "
718 "use gnulib module mbstowcs for portability");
719# endif
720#endif
721
520/* Convert a multibyte character to a wide character. */ 722/* Convert a multibyte character to a wide character. */
521#if @GNULIB_MBTOWC@ 723#if @GNULIB_MBTOWC@
522# if @REPLACE_MBTOWC@ 724# if @REPLACE_MBTOWC@
@@ -579,12 +781,24 @@ _GL_WARN_ON_USE (mkdtemp, "mkdtemp is unportable - "
579 implementation. 781 implementation.
580 Returns the open file descriptor if successful, otherwise -1 and errno 782 Returns the open file descriptor if successful, otherwise -1 and errno
581 set. */ 783 set. */
582# if !@HAVE_MKOSTEMP@ 784# if @REPLACE_MKOSTEMP@
785# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
786# undef mkostemp
787# define mkostemp rpl_mkostemp
788# endif
789_GL_FUNCDECL_RPL (mkostemp, int, (char * /*template*/, int /*flags*/)
790 _GL_ARG_NONNULL ((1)));
791_GL_CXXALIAS_RPL (mkostemp, int, (char * /*template*/, int /*flags*/));
792# else
793# if !@HAVE_MKOSTEMP@
583_GL_FUNCDECL_SYS (mkostemp, int, (char * /*template*/, int /*flags*/) 794_GL_FUNCDECL_SYS (mkostemp, int, (char * /*template*/, int /*flags*/)
584 _GL_ARG_NONNULL ((1))); 795 _GL_ARG_NONNULL ((1)));
585# endif 796# endif
586_GL_CXXALIAS_SYS (mkostemp, int, (char * /*template*/, int /*flags*/)); 797_GL_CXXALIAS_SYS (mkostemp, int, (char * /*template*/, int /*flags*/));
798# endif
799# if __GLIBC__ >= 2
587_GL_CXXALIASWARN (mkostemp); 800_GL_CXXALIASWARN (mkostemp);
801# endif
588#elif defined GNULIB_POSIXCHECK 802#elif defined GNULIB_POSIXCHECK
589# undef mkostemp 803# undef mkostemp
590# if HAVE_RAW_DECL_MKOSTEMP 804# if HAVE_RAW_DECL_MKOSTEMP
@@ -607,14 +821,28 @@ _GL_WARN_ON_USE (mkostemp, "mkostemp is unportable - "
607 implementation. 821 implementation.
608 Returns the open file descriptor if successful, otherwise -1 and errno 822 Returns the open file descriptor if successful, otherwise -1 and errno
609 set. */ 823 set. */
610# if !@HAVE_MKOSTEMPS@ 824# if @REPLACE_MKOSTEMPS@
825# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
826# undef mkostemps
827# define mkostemps rpl_mkostemps
828# endif
829_GL_FUNCDECL_RPL (mkostemps, int,
830 (char * /*template*/, int /*suffixlen*/, int /*flags*/)
831 _GL_ARG_NONNULL ((1)));
832_GL_CXXALIAS_RPL (mkostemps, int,
833 (char * /*template*/, int /*suffixlen*/, int /*flags*/));
834# else
835# if !@HAVE_MKOSTEMPS@
611_GL_FUNCDECL_SYS (mkostemps, int, 836_GL_FUNCDECL_SYS (mkostemps, int,
612 (char * /*template*/, int /*suffixlen*/, int /*flags*/) 837 (char * /*template*/, int /*suffixlen*/, int /*flags*/)
613 _GL_ARG_NONNULL ((1))); 838 _GL_ARG_NONNULL ((1)));
614# endif 839# endif
615_GL_CXXALIAS_SYS (mkostemps, int, 840_GL_CXXALIAS_SYS (mkostemps, int,
616 (char * /*template*/, int /*suffixlen*/, int /*flags*/)); 841 (char * /*template*/, int /*suffixlen*/, int /*flags*/));
842# endif
843# if __GLIBC__ >= 2
617_GL_CXXALIASWARN (mkostemps); 844_GL_CXXALIASWARN (mkostemps);
845# endif
618#elif defined GNULIB_POSIXCHECK 846#elif defined GNULIB_POSIXCHECK
619# undef mkostemps 847# undef mkostemps
620# if HAVE_RAW_DECL_MKOSTEMPS 848# if HAVE_RAW_DECL_MKOSTEMPS
@@ -713,7 +941,7 @@ _GL_CXXALIAS_SYS (posix_memalign, int,
713 (void **memptr, size_t alignment, size_t size)); 941 (void **memptr, size_t alignment, size_t size));
714# endif 942# endif
715# endif 943# endif
716# if @HAVE_POSIX_MEMALIGN@ 944# if __GLIBC__ >= 2 && @HAVE_POSIX_MEMALIGN@
717_GL_CXXALIASWARN (posix_memalign); 945_GL_CXXALIASWARN (posix_memalign);
718# endif 946# endif
719#elif defined GNULIB_POSIXCHECK 947#elif defined GNULIB_POSIXCHECK
@@ -727,11 +955,22 @@ _GL_WARN_ON_USE (posix_memalign, "posix_memalign is not portable - "
727#if @GNULIB_POSIX_OPENPT@ 955#if @GNULIB_POSIX_OPENPT@
728/* Return an FD open to the master side of a pseudo-terminal. Flags should 956/* Return an FD open to the master side of a pseudo-terminal. Flags should
729 include O_RDWR, and may also include O_NOCTTY. */ 957 include O_RDWR, and may also include O_NOCTTY. */
730# if !@HAVE_POSIX_OPENPT@ 958# if @REPLACE_POSIX_OPENPT@
959# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
960# undef posix_openpt
961# define posix_openpt rpl_posix_openpt
962# endif
963_GL_FUNCDECL_RPL (posix_openpt, int, (int flags));
964_GL_CXXALIAS_RPL (posix_openpt, int, (int flags));
965# else
966# if !@HAVE_POSIX_OPENPT@
731_GL_FUNCDECL_SYS (posix_openpt, int, (int flags)); 967_GL_FUNCDECL_SYS (posix_openpt, int, (int flags));
732# endif 968# endif
733_GL_CXXALIAS_SYS (posix_openpt, int, (int flags)); 969_GL_CXXALIAS_SYS (posix_openpt, int, (int flags));
970# endif
971# if __GLIBC__ >= 2
734_GL_CXXALIASWARN (posix_openpt); 972_GL_CXXALIASWARN (posix_openpt);
973# endif
735#elif defined GNULIB_POSIXCHECK 974#elif defined GNULIB_POSIXCHECK
736# undef posix_openpt 975# undef posix_openpt
737# if HAVE_RAW_DECL_POSIX_OPENPT 976# if HAVE_RAW_DECL_POSIX_OPENPT
@@ -808,6 +1047,10 @@ _GL_CXXALIAS_RPL (putenv, int, (char *string));
808# define putenv _putenv 1047# define putenv _putenv
809# endif 1048# endif
810_GL_CXXALIAS_MDA (putenv, int, (char *string)); 1049_GL_CXXALIAS_MDA (putenv, int, (char *string));
1050# elif defined __KLIBC__
1051/* Need to cast, because on OS/2 kLIBC, the first parameter is
1052 const char *string. */
1053_GL_CXXALIAS_SYS_CAST (putenv, int, (char *string));
811# else 1054# else
812_GL_CXXALIAS_SYS (putenv, int, (char *string)); 1055_GL_CXXALIAS_SYS (putenv, int, (char *string));
813# endif 1056# endif
@@ -824,6 +1067,10 @@ _GL_CXXALIASWARN (putenv);
824/* Need to cast, because on mingw, the parameter is either 1067/* Need to cast, because on mingw, the parameter is either
825 'const char *string' or 'char *string'. */ 1068 'const char *string' or 'char *string'. */
826_GL_CXXALIAS_MDA_CAST (putenv, int, (char *string)); 1069_GL_CXXALIAS_MDA_CAST (putenv, int, (char *string));
1070# elif defined __KLIBC__
1071/* Need to cast, because on OS/2 kLIBC, the first parameter is
1072 const char *string. */
1073_GL_CXXALIAS_SYS_CAST (putenv, int, (char *string));
827# else 1074# else
828_GL_CXXALIAS_SYS (putenv, int, (char *string)); 1075_GL_CXXALIAS_SYS (putenv, int, (char *string));
829# endif 1076# endif
@@ -865,7 +1112,9 @@ _GL_CXXALIAS_SYS (qsort_r, void, (void *base, size_t nmemb, size_t size,
865 _gl_qsort_r_compar_fn compare, 1112 _gl_qsort_r_compar_fn compare,
866 void *arg)); 1113 void *arg));
867# endif 1114# endif
1115# if __GLIBC__ >= 2
868_GL_CXXALIASWARN (qsort_r); 1116_GL_CXXALIASWARN (qsort_r);
1117# endif
869#elif defined GNULIB_POSIXCHECK 1118#elif defined GNULIB_POSIXCHECK
870# undef qsort_r 1119# undef qsort_r
871# if HAVE_RAW_DECL_QSORT_R 1120# if HAVE_RAW_DECL_QSORT_R
@@ -875,11 +1124,26 @@ _GL_WARN_ON_USE (qsort_r, "qsort_r is not portable - "
875#endif 1124#endif
876 1125
877 1126
878#if @GNULIB_RANDOM_R@ 1127#if @GNULIB_RAND@ || (@GNULIB_RANDOM_R@ && !@HAVE_RANDOM_R@)
879# if !@HAVE_RANDOM_R@ 1128# ifndef RAND_MAX
880# ifndef RAND_MAX 1129# define RAND_MAX 2147483647
881# define RAND_MAX 2147483647 1130# endif
1131#endif
1132
1133
1134#if @GNULIB_RAND@
1135# if @REPLACE_RAND@
1136# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1137# undef rand
1138# define rand rpl_rand
882# endif 1139# endif
1140_GL_FUNCDECL_RPL (rand, int, (void));
1141_GL_CXXALIAS_RPL (rand, int, (void));
1142# else
1143_GL_CXXALIAS_SYS (rand, int, (void));
1144# endif
1145# if __GLIBC__ >= 2
1146_GL_CXXALIASWARN (rand);
883# endif 1147# endif
884#endif 1148#endif
885 1149
@@ -900,7 +1164,9 @@ _GL_FUNCDECL_SYS (random, long, (void));
900 int. */ 1164 int. */
901_GL_CXXALIAS_SYS_CAST (random, long, (void)); 1165_GL_CXXALIAS_SYS_CAST (random, long, (void));
902# endif 1166# endif
1167# if __GLIBC__ >= 2
903_GL_CXXALIASWARN (random); 1168_GL_CXXALIASWARN (random);
1169# endif
904#elif defined GNULIB_POSIXCHECK 1170#elif defined GNULIB_POSIXCHECK
905# undef random 1171# undef random
906# if HAVE_RAW_DECL_RANDOM 1172# if HAVE_RAW_DECL_RANDOM
@@ -925,7 +1191,9 @@ _GL_FUNCDECL_SYS (srandom, void, (unsigned int seed));
925 unsigned long seed. */ 1191 unsigned long seed. */
926_GL_CXXALIAS_SYS_CAST (srandom, void, (unsigned int seed)); 1192_GL_CXXALIAS_SYS_CAST (srandom, void, (unsigned int seed));
927# endif 1193# endif
1194# if __GLIBC__ >= 2
928_GL_CXXALIASWARN (srandom); 1195_GL_CXXALIASWARN (srandom);
1196# endif
929#elif defined GNULIB_POSIXCHECK 1197#elif defined GNULIB_POSIXCHECK
930# undef srandom 1198# undef srandom
931# if HAVE_RAW_DECL_SRANDOM 1199# if HAVE_RAW_DECL_SRANDOM
@@ -956,7 +1224,9 @@ _GL_FUNCDECL_SYS (initstate, char *,
956_GL_CXXALIAS_SYS_CAST (initstate, char *, 1224_GL_CXXALIAS_SYS_CAST (initstate, char *,
957 (unsigned int seed, char *buf, size_t buf_size)); 1225 (unsigned int seed, char *buf, size_t buf_size));
958# endif 1226# endif
1227# if __GLIBC__ >= 2
959_GL_CXXALIASWARN (initstate); 1228_GL_CXXALIASWARN (initstate);
1229# endif
960#elif defined GNULIB_POSIXCHECK 1230#elif defined GNULIB_POSIXCHECK
961# undef initstate 1231# undef initstate
962# if HAVE_RAW_DECL_INITSTATE 1232# if HAVE_RAW_DECL_INITSTATE
@@ -981,7 +1251,9 @@ _GL_FUNCDECL_SYS (setstate, char *, (char *arg_state) _GL_ARG_NONNULL ((1)));
981 is const char *arg_state. */ 1251 is const char *arg_state. */
982_GL_CXXALIAS_SYS_CAST (setstate, char *, (char *arg_state)); 1252_GL_CXXALIAS_SYS_CAST (setstate, char *, (char *arg_state));
983# endif 1253# endif
1254# if __GLIBC__ >= 2
984_GL_CXXALIASWARN (setstate); 1255_GL_CXXALIASWARN (setstate);
1256# endif
985#elif defined GNULIB_POSIXCHECK 1257#elif defined GNULIB_POSIXCHECK
986# undef setstate 1258# undef setstate
987# if HAVE_RAW_DECL_SETSTATE 1259# if HAVE_RAW_DECL_SETSTATE
@@ -1126,8 +1398,16 @@ _GL_CXXALIAS_RPL (realloc, void *, (void *ptr, size_t size));
1126# else 1398# else
1127# if __GNUC__ >= 11 1399# if __GNUC__ >= 11
1128/* For -Wmismatched-dealloc: Associate realloc with free or rpl_free. */ 1400/* For -Wmismatched-dealloc: Associate realloc with free or rpl_free. */
1129_GL_FUNCDECL_SYS (realloc, void *, (void *ptr, size_t size) 1401# if __GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2
1130 _GL_ATTRIBUTE_DEALLOC_FREE); 1402_GL_FUNCDECL_SYS (realloc, void *,
1403 (void *ptr, size_t size)
1404 _GL_ATTRIBUTE_NOTHROW
1405 _GL_ATTRIBUTE_DEALLOC_FREE);
1406# else
1407_GL_FUNCDECL_SYS (realloc, void *,
1408 (void *ptr, size_t size)
1409 _GL_ATTRIBUTE_DEALLOC_FREE);
1410# endif
1131# endif 1411# endif
1132_GL_CXXALIAS_SYS (realloc, void *, (void *ptr, size_t size)); 1412_GL_CXXALIAS_SYS (realloc, void *, (void *ptr, size_t size));
1133# endif 1413# endif
@@ -1137,8 +1417,16 @@ _GL_CXXALIASWARN (realloc);
1137#else 1417#else
1138# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined realloc 1418# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined realloc
1139/* For -Wmismatched-dealloc: Associate realloc with free or rpl_free. */ 1419/* For -Wmismatched-dealloc: Associate realloc with free or rpl_free. */
1140_GL_FUNCDECL_SYS (realloc, void *, (void *ptr, size_t size) 1420# if __GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2
1141 _GL_ATTRIBUTE_DEALLOC_FREE); 1421_GL_FUNCDECL_SYS (realloc, void *,
1422 (void *ptr, size_t size)
1423 _GL_ATTRIBUTE_NOTHROW
1424 _GL_ATTRIBUTE_DEALLOC_FREE);
1425# else
1426_GL_FUNCDECL_SYS (realloc, void *,
1427 (void *ptr, size_t size)
1428 _GL_ATTRIBUTE_DEALLOC_FREE);
1429# endif
1142# endif 1430# endif
1143# if defined GNULIB_POSIXCHECK && !_GL_USE_STDLIB_ALLOC 1431# if defined GNULIB_POSIXCHECK && !_GL_USE_STDLIB_ALLOC
1144# undef realloc 1432# undef realloc
@@ -1167,7 +1455,9 @@ _GL_FUNCDECL_SYS (reallocarray, void *,
1167_GL_CXXALIAS_SYS (reallocarray, void *, 1455_GL_CXXALIAS_SYS (reallocarray, void *,
1168 (void *ptr, size_t nmemb, size_t size)); 1456 (void *ptr, size_t nmemb, size_t size));
1169# endif 1457# endif
1458# if __GLIBC__ >= 2
1170_GL_CXXALIASWARN (reallocarray); 1459_GL_CXXALIASWARN (reallocarray);
1460# endif
1171#elif defined GNULIB_POSIXCHECK 1461#elif defined GNULIB_POSIXCHECK
1172# undef reallocarray 1462# undef reallocarray
1173# if HAVE_RAW_DECL_REALLOCARRAY 1463# if HAVE_RAW_DECL_REALLOCARRAY
@@ -1301,6 +1591,38 @@ _GL_WARN_ON_USE (strtod, "strtod is unportable - "
1301# endif 1591# endif
1302#endif 1592#endif
1303 1593
1594#if @GNULIB_STRTOF@
1595 /* Parse a float from STRING, updating ENDP if appropriate. */
1596# if @REPLACE_STRTOF@
1597# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1598# define strtof rpl_strtof
1599# endif
1600# define GNULIB_defined_strtof_function 1
1601_GL_FUNCDECL_RPL (strtof, float,
1602 (const char *restrict str, char **restrict endp)
1603 _GL_ARG_NONNULL ((1)));
1604_GL_CXXALIAS_RPL (strtof, float,
1605 (const char *restrict str, char **restrict endp));
1606# else
1607# if !@HAVE_STRTOF@
1608_GL_FUNCDECL_SYS (strtof, float,
1609 (const char *restrict str, char **restrict endp)
1610 _GL_ARG_NONNULL ((1)));
1611# endif
1612_GL_CXXALIAS_SYS (strtof, float,
1613 (const char *restrict str, char **restrict endp));
1614# endif
1615# if __GLIBC__ >= 2
1616_GL_CXXALIASWARN (strtof);
1617# endif
1618#elif defined GNULIB_POSIXCHECK
1619# undef strtof
1620# if HAVE_RAW_DECL_STRTOF
1621_GL_WARN_ON_USE (strtof, "strtof is unportable - "
1622 "use gnulib module strtof for portability");
1623# endif
1624#endif
1625
1304#if @GNULIB_STRTOLD@ 1626#if @GNULIB_STRTOLD@
1305 /* Parse a 'long double' from STRING, updating ENDP if appropriate. */ 1627 /* Parse a 'long double' from STRING, updating ENDP if appropriate. */
1306# if @REPLACE_STRTOLD@ 1628# if @REPLACE_STRTOLD@
diff --git a/gl/str-two-way.h b/gl/str-two-way.h
index dfe70224..cf85e268 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2008-2024 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 3a5ce3e1..7939b404 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.
2 Copyright (C) 1998-1999, 2005-2007, 2009-2023 Free Software Foundation, Inc. 2 Copyright (C) 1998-1999, 2005-2007, 2009-2024 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
@@ -22,8 +22,6 @@
22#include <ctype.h> 22#include <ctype.h>
23#include <limits.h> 23#include <limits.h>
24 24
25#define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
26
27/* Compare strings S1 and S2, ignoring case, returning less than, equal to or 25/* Compare strings S1 and S2, ignoring case, returning less than, equal to or
28 greater than zero if S1 is lexicographically less than, equal to or greater 26 greater than zero if S1 is lexicographically less than, equal to or greater
29 than S2. 27 than S2.
@@ -41,8 +39,8 @@ strcasecmp (const char *s1, const char *s2)
41 39
42 do 40 do
43 { 41 {
44 c1 = TOLOWER (*p1); 42 c1 = tolower (*p1);
45 c2 = TOLOWER (*p2); 43 c2 = tolower (*p2);
46 44
47 if (c1 == '\0') 45 if (c1 == '\0')
48 break; 46 break;
diff --git a/gl/strcasestr.c b/gl/strcasestr.c
index 8eea435c..b8c0479d 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2005-2024 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
@@ -23,14 +23,12 @@
23#include <ctype.h> 23#include <ctype.h>
24#include <strings.h> 24#include <strings.h>
25 25
26#define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
27
28/* Two-Way algorithm. */ 26/* Two-Way algorithm. */
29#define RETURN_TYPE char * 27#define RETURN_TYPE char *
30#define AVAILABLE(h, h_l, j, n_l) \ 28#define AVAILABLE(h, h_l, j, n_l) \
31 (!memchr ((h) + (h_l), '\0', (j) + (n_l) - (h_l)) \ 29 (!memchr ((h) + (h_l), '\0', (j) + (n_l) - (h_l)) \
32 && ((h_l) = (j) + (n_l))) 30 && ((h_l) = (j) + (n_l)))
33#define CANON_ELEMENT(c) TOLOWER (c) 31#define CANON_ELEMENT(c) tolower (c)
34#define CMP_FUNC(p1, p2, l) \ 32#define CMP_FUNC(p1, p2, l) \
35 strncasecmp ((const char *) (p1), (const char *) (p2), l) 33 strncasecmp ((const char *) (p1), (const char *) (p2), l)
36#include "str-two-way.h" 34#include "str-two-way.h"
@@ -52,8 +50,8 @@ strcasestr (const char *haystack_start, const char *needle_start)
52 NEEDLE if HAYSTACK is too short). */ 50 NEEDLE if HAYSTACK is too short). */
53 while (*haystack && *needle) 51 while (*haystack && *needle)
54 { 52 {
55 ok &= (TOLOWER ((unsigned char) *haystack) 53 ok &= (tolower ((unsigned char) *haystack)
56 == TOLOWER ((unsigned char) *needle)); 54 == tolower ((unsigned char) *needle));
57 haystack++; 55 haystack++;
58 needle++; 56 needle++;
59 } 57 }
diff --git a/gl/streq.h b/gl/streq.h
index 712948eb..8593de6d 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2001-2002, 2007, 2009-2024 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
@@ -21,6 +21,11 @@
21 21
22#include <string.h> 22#include <string.h>
23 23
24#ifdef __cplusplus
25extern "C" {
26#endif
27
28
24/* STREQ_OPT allows to optimize string comparison with a small literal string. 29/* STREQ_OPT allows to optimize string comparison with a small literal string.
25 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)
26 is semantically equivalent to 31 is semantically equivalent to
@@ -173,4 +178,9 @@ streq0 (const char *s1, const char *s2, char s20, char s21, char s22, char s23,
173 178
174#endif 179#endif
175 180
181
182#ifdef __cplusplus
183}
184#endif
185
176#endif /* _GL_STREQ_H */ 186#endif /* _GL_STREQ_H */
diff --git a/gl/strerror-override.c b/gl/strerror-override.c
index cddaa4a9..b9c1c7ab 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2010-2024 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/strerror-override.h b/gl/strerror-override.h
index 388cc282..a1734a24 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2010-2024 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
@@ -16,42 +16,57 @@
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_STRERROR_OVERRIDE_H 18#ifndef _GL_STRERROR_OVERRIDE_H
19# define _GL_STRERROR_OVERRIDE_H 19#define _GL_STRERROR_OVERRIDE_H
20
21/* This file uses _GL_ATTRIBUTE_CONST. */
22#if !_GL_CONFIG_H_INCLUDED
23# error "Please include config.h first."
24#endif
25
26#include <errno.h>
27#include <stddef.h>
28
29#ifdef __cplusplus
30extern "C" {
31#endif
20 32
21# include <errno.h>
22# include <stddef.h>
23 33
24/* Reasonable buffer size that should never trigger ERANGE; if this 34/* Reasonable buffer size that should never trigger ERANGE; if this
25 proves too small, we intentionally abort(), to remind us to fix 35 proves too small, we intentionally abort(), to remind us to fix
26 this value. */ 36 this value. */
27# define STACKBUF_LEN 256 37#define STACKBUF_LEN 256
28 38
29/* If ERRNUM maps to an errno value defined by gnulib, return a string 39/* If ERRNUM maps to an errno value defined by gnulib, return a string
30 describing the error. Otherwise return NULL. */ 40 describing the error. Otherwise return NULL. */
31# if REPLACE_STRERROR_0 \ 41#if REPLACE_STRERROR_0 \
32 || GNULIB_defined_ESOCK \ 42 || GNULIB_defined_ESOCK \
33 || GNULIB_defined_ESTREAMS \ 43 || GNULIB_defined_ESTREAMS \
34 || GNULIB_defined_EWINSOCK \ 44 || GNULIB_defined_EWINSOCK \
35 || GNULIB_defined_ENOMSG \ 45 || GNULIB_defined_ENOMSG \
36 || GNULIB_defined_EIDRM \ 46 || GNULIB_defined_EIDRM \
37 || GNULIB_defined_ENOLINK \ 47 || GNULIB_defined_ENOLINK \
38 || GNULIB_defined_EPROTO \ 48 || GNULIB_defined_EPROTO \
39 || GNULIB_defined_EMULTIHOP \ 49 || GNULIB_defined_EMULTIHOP \
40 || GNULIB_defined_EBADMSG \ 50 || GNULIB_defined_EBADMSG \
41 || GNULIB_defined_EOVERFLOW \ 51 || GNULIB_defined_EOVERFLOW \
42 || GNULIB_defined_ENOTSUP \ 52 || GNULIB_defined_ENOTSUP \
43 || GNULIB_defined_ENETRESET \ 53 || GNULIB_defined_ENETRESET \
44 || GNULIB_defined_ECONNABORTED \ 54 || GNULIB_defined_ECONNABORTED \
45 || GNULIB_defined_ESTALE \ 55 || GNULIB_defined_ESTALE \
46 || GNULIB_defined_EDQUOT \ 56 || GNULIB_defined_EDQUOT \
47 || GNULIB_defined_ECANCELED \ 57 || GNULIB_defined_ECANCELED \
48 || GNULIB_defined_EOWNERDEAD \ 58 || GNULIB_defined_EOWNERDEAD \
49 || GNULIB_defined_ENOTRECOVERABLE \ 59 || GNULIB_defined_ENOTRECOVERABLE \
50 || GNULIB_defined_EILSEQ 60 || GNULIB_defined_EILSEQ
51extern const char *strerror_override (int errnum) _GL_ATTRIBUTE_CONST; 61extern const char *strerror_override (int errnum) _GL_ATTRIBUTE_CONST;
52# else 62#else
53# define strerror_override(ignored) NULL 63# define strerror_override(ignored) NULL
54# define GNULIB_defined_strerror_override_macro 1 64# define GNULIB_defined_strerror_override_macro 1
55# endif 65#endif
66
67
68#ifdef __cplusplus
69}
70#endif
56 71
57#endif /* _GL_STRERROR_OVERRIDE_H */ 72#endif /* _GL_STRERROR_OVERRIDE_H */
diff --git a/gl/strerror.c b/gl/strerror.c
index d754f601..6b760ff4 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2007-2024 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/string.in.h b/gl/string.in.h
index e993b2fb..44ec2e7e 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 1995-1996, 2001-2024 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
@@ -44,6 +44,13 @@
44#ifndef _@GUARD_PREFIX@_STRING_H 44#ifndef _@GUARD_PREFIX@_STRING_H
45#define _@GUARD_PREFIX@_STRING_H 45#define _@GUARD_PREFIX@_STRING_H
46 46
47/* This file uses _GL_ATTRIBUTE_DEALLOC, _GL_ATTRIBUTE_MALLOC,
48 _GL_ATTRIBUTE_NOTHROW, _GL_ATTRIBUTE_PURE, GNULIB_POSIXCHECK,
49 HAVE_RAW_DECL_*. */
50#if !_GL_CONFIG_H_INCLUDED
51 #error "Please include config.h first."
52#endif
53
47/* NetBSD 5.0 mis-defines NULL. */ 54/* NetBSD 5.0 mis-defines NULL. */
48#include <stddef.h> 55#include <stddef.h>
49 56
@@ -59,10 +66,11 @@
59# include <unistd.h> 66# include <unistd.h>
60#endif 67#endif
61 68
62/* AIX 7.2 declares ffsl and ffsll in <strings.h>, not in <string.h>. */ 69/* AIX 7.2 and Android 13 declare ffsl and ffsll in <strings.h>, not in
70 <string.h>. */
63/* But in any case avoid namespace pollution on glibc systems. */ 71/* But in any case avoid namespace pollution on glibc systems. */
64#if ((@GNULIB_FFSL@ || @GNULIB_FFSLL@ || defined GNULIB_POSIXCHECK) \ 72#if ((@GNULIB_FFSL@ || @GNULIB_FFSLL@ || defined GNULIB_POSIXCHECK) \
65 && defined _AIX) \ 73 && (defined _AIX || defined __ANDROID__)) \
66 && ! defined __GLIBC__ 74 && ! defined __GLIBC__
67# include <strings.h> 75# include <strings.h>
68#endif 76#endif
@@ -103,6 +111,28 @@
103# endif 111# endif
104#endif 112#endif
105 113
114/* _GL_ATTRIBUTE_NOTHROW declares that the function does not throw exceptions.
115 */
116#ifndef _GL_ATTRIBUTE_NOTHROW
117# if defined __cplusplus
118# if (__GNUC__ + (__GNUC_MINOR__ >= 8) > 2) || __clang_major >= 4
119# if __cplusplus >= 201103L
120# define _GL_ATTRIBUTE_NOTHROW noexcept (true)
121# else
122# define _GL_ATTRIBUTE_NOTHROW throw ()
123# endif
124# else
125# define _GL_ATTRIBUTE_NOTHROW
126# endif
127# else
128# if (__GNUC__ + (__GNUC_MINOR__ >= 3) > 3) || defined __clang__
129# define _GL_ATTRIBUTE_NOTHROW __attribute__ ((__nothrow__))
130# else
131# define _GL_ATTRIBUTE_NOTHROW
132# endif
133# endif
134#endif
135
106/* The __attribute__ feature is available in gcc versions 2.5 and later. 136/* The __attribute__ feature is available in gcc versions 2.5 and later.
107 The attribute __pure__ was added in gcc 2.96. */ 137 The attribute __pure__ was added in gcc 2.96. */
108#ifndef _GL_ATTRIBUTE_PURE 138#ifndef _GL_ATTRIBUTE_PURE
@@ -125,7 +155,11 @@
125# if (@REPLACE_FREE@ && !defined free \ 155# if (@REPLACE_FREE@ && !defined free \
126 && !(defined __cplusplus && defined GNULIB_NAMESPACE)) 156 && !(defined __cplusplus && defined GNULIB_NAMESPACE))
127/* We can't do '#define free rpl_free' here. */ 157/* We can't do '#define free rpl_free' here. */
158# if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2)
159_GL_EXTERN_C void rpl_free (void *) _GL_ATTRIBUTE_NOTHROW;
160# else
128_GL_EXTERN_C void rpl_free (void *); 161_GL_EXTERN_C void rpl_free (void *);
162# endif
129# undef _GL_ATTRIBUTE_DEALLOC_FREE 163# undef _GL_ATTRIBUTE_DEALLOC_FREE
130# define _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC (rpl_free, 1) 164# define _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC (rpl_free, 1)
131# else 165# else
@@ -137,7 +171,7 @@ _GL_EXTERN_C
137 void __cdecl free (void *); 171 void __cdecl free (void *);
138# else 172# else
139# if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2) 173# if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2)
140_GL_EXTERN_C void free (void *) throw (); 174_GL_EXTERN_C void free (void *) _GL_ATTRIBUTE_NOTHROW;
141# else 175# else
142_GL_EXTERN_C void free (void *); 176_GL_EXTERN_C void free (void *);
143# endif 177# endif
@@ -152,7 +186,7 @@ _GL_EXTERN_C
152 void __cdecl free (void *); 186 void __cdecl free (void *);
153# else 187# else
154# if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2) 188# if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2)
155_GL_EXTERN_C void free (void *) throw (); 189_GL_EXTERN_C void free (void *) _GL_ATTRIBUTE_NOTHROW;
156# else 190# else
157_GL_EXTERN_C void free (void *); 191_GL_EXTERN_C void free (void *);
158# endif 192# endif
@@ -255,9 +289,12 @@ _GL_CXXALIAS_SYS_CAST2 (memchr,
255# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \ 289# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \
256 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) \ 290 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) \
257 || defined __clang__) 291 || defined __clang__)
258_GL_CXXALIASWARN1 (memchr, void *, (void *__s, int __c, size_t __n) throw ()); 292_GL_CXXALIASWARN1 (memchr, void *,
293 (void *__s, int __c, size_t __n)
294 _GL_ATTRIBUTE_NOTHROW);
259_GL_CXXALIASWARN1 (memchr, void const *, 295_GL_CXXALIASWARN1 (memchr, void const *,
260 (void const *__s, int __c, size_t __n) throw ()); 296 (void const *__s, int __c, size_t __n)
297 _GL_ATTRIBUTE_NOTHROW);
261# elif __GLIBC__ >= 2 298# elif __GLIBC__ >= 2
262_GL_CXXALIASWARN (memchr); 299_GL_CXXALIASWARN (memchr);
263# endif 300# endif
@@ -307,16 +344,32 @@ _GL_WARN_ON_USE (memmem, "memmem is unportable and often quadratic - "
307/* Copy N bytes of SRC to DEST, return pointer to bytes after the 344/* Copy N bytes of SRC to DEST, return pointer to bytes after the
308 last written byte. */ 345 last written byte. */
309#if @GNULIB_MEMPCPY@ 346#if @GNULIB_MEMPCPY@
310# if ! @HAVE_MEMPCPY@ 347# if @REPLACE_MEMPCPY@
348# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
349# undef mempcpy
350# define mempcpy rpl_mempcpy
351# endif
352_GL_FUNCDECL_RPL (mempcpy, void *,
353 (void *restrict __dest, void const *restrict __src,
354 size_t __n)
355 _GL_ARG_NONNULL ((1, 2)));
356_GL_CXXALIAS_RPL (mempcpy, void *,
357 (void *restrict __dest, void const *restrict __src,
358 size_t __n));
359# else
360# if !@HAVE_MEMPCPY@
311_GL_FUNCDECL_SYS (mempcpy, void *, 361_GL_FUNCDECL_SYS (mempcpy, void *,
312 (void *restrict __dest, void const *restrict __src, 362 (void *restrict __dest, void const *restrict __src,
313 size_t __n) 363 size_t __n)
314 _GL_ARG_NONNULL ((1, 2))); 364 _GL_ARG_NONNULL ((1, 2)));
315# endif 365# endif
316_GL_CXXALIAS_SYS (mempcpy, void *, 366_GL_CXXALIAS_SYS (mempcpy, void *,
317 (void *restrict __dest, void const *restrict __src, 367 (void *restrict __dest, void const *restrict __src,
318 size_t __n)); 368 size_t __n));
369# endif
370# if __GLIBC__ >= 2
319_GL_CXXALIASWARN (mempcpy); 371_GL_CXXALIASWARN (mempcpy);
372# endif
320#elif defined GNULIB_POSIXCHECK 373#elif defined GNULIB_POSIXCHECK
321# undef mempcpy 374# undef mempcpy
322# if HAVE_RAW_DECL_MEMPCPY 375# if HAVE_RAW_DECL_MEMPCPY
@@ -341,9 +394,13 @@ _GL_CXXALIAS_SYS_CAST2 (memrchr,
341# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \ 394# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \
342 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) \ 395 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) \
343 || defined __clang__) 396 || defined __clang__)
344_GL_CXXALIASWARN1 (memrchr, void *, (void *, int, size_t) throw ()); 397_GL_CXXALIASWARN1 (memrchr, void *,
345_GL_CXXALIASWARN1 (memrchr, void const *, (void const *, int, size_t) throw ()); 398 (void *, int, size_t)
346# else 399 _GL_ATTRIBUTE_NOTHROW);
400_GL_CXXALIASWARN1 (memrchr, void const *,
401 (void const *, int, size_t)
402 _GL_ATTRIBUTE_NOTHROW);
403# elif __GLIBC__ >= 2
347_GL_CXXALIASWARN (memrchr); 404_GL_CXXALIASWARN (memrchr);
348# endif 405# endif
349#elif defined GNULIB_POSIXCHECK 406#elif defined GNULIB_POSIXCHECK
@@ -357,11 +414,21 @@ _GL_WARN_ON_USE (memrchr, "memrchr is unportable - "
357/* Overwrite a block of memory. The compiler will not optimize 414/* Overwrite a block of memory. The compiler will not optimize
358 effects away, even if the block is dead after the call. */ 415 effects away, even if the block is dead after the call. */
359#if @GNULIB_MEMSET_EXPLICIT@ 416#if @GNULIB_MEMSET_EXPLICIT@
360# if ! @HAVE_MEMSET_EXPLICIT@ 417# if @REPLACE_MEMSET_EXPLICIT@
418# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
419# undef memset_explicit
420# define memset_explicit rpl_memset_explicit
421# endif
422_GL_FUNCDECL_RPL (memset_explicit, void *,
423 (void *__dest, int __c, size_t __n) _GL_ARG_NONNULL ((1)));
424_GL_CXXALIAS_RPL (memset_explicit, void *, (void *__dest, int __c, size_t __n));
425# else
426# if !@HAVE_MEMSET_EXPLICIT@
361_GL_FUNCDECL_SYS (memset_explicit, void *, 427_GL_FUNCDECL_SYS (memset_explicit, void *,
362 (void *__dest, int __c, size_t __n) _GL_ARG_NONNULL ((1))); 428 (void *__dest, int __c, size_t __n) _GL_ARG_NONNULL ((1)));
363# endif 429# endif
364_GL_CXXALIAS_SYS (memset_explicit, void *, (void *__dest, int __c, size_t __n)); 430_GL_CXXALIAS_SYS (memset_explicit, void *, (void *__dest, int __c, size_t __n));
431# endif
365_GL_CXXALIASWARN (memset_explicit); 432_GL_CXXALIASWARN (memset_explicit);
366#elif defined GNULIB_POSIXCHECK 433#elif defined GNULIB_POSIXCHECK
367# undef memset_explicit 434# undef memset_explicit
@@ -389,9 +456,12 @@ _GL_CXXALIAS_SYS_CAST2 (rawmemchr,
389# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \ 456# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \
390 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) \ 457 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) \
391 || defined __clang__) 458 || defined __clang__)
392_GL_CXXALIASWARN1 (rawmemchr, void *, (void *__s, int __c_in) throw ()); 459_GL_CXXALIASWARN1 (rawmemchr, void *,
460 (void *__s, int __c_in)
461 _GL_ATTRIBUTE_NOTHROW);
393_GL_CXXALIASWARN1 (rawmemchr, void const *, 462_GL_CXXALIASWARN1 (rawmemchr, void const *,
394 (void const *__s, int __c_in) throw ()); 463 (void const *__s, int __c_in)
464 _GL_ATTRIBUTE_NOTHROW);
395# else 465# else
396_GL_CXXALIASWARN (rawmemchr); 466_GL_CXXALIASWARN (rawmemchr);
397# endif 467# endif
@@ -405,14 +475,28 @@ _GL_WARN_ON_USE (rawmemchr, "rawmemchr is unportable - "
405 475
406/* Copy SRC to DST, returning the address of the terminating '\0' in DST. */ 476/* Copy SRC to DST, returning the address of the terminating '\0' in DST. */
407#if @GNULIB_STPCPY@ 477#if @GNULIB_STPCPY@
408# if ! @HAVE_STPCPY@ 478# if @REPLACE_STPCPY@
479# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
480# undef stpcpy
481# define stpcpy rpl_stpcpy
482# endif
483_GL_FUNCDECL_RPL (stpcpy, char *,
484 (char *restrict __dst, char const *restrict __src)
485 _GL_ARG_NONNULL ((1, 2)));
486_GL_CXXALIAS_RPL (stpcpy, char *,
487 (char *restrict __dst, char const *restrict __src));
488# else
489# if !@HAVE_STPCPY@
409_GL_FUNCDECL_SYS (stpcpy, char *, 490_GL_FUNCDECL_SYS (stpcpy, char *,
410 (char *restrict __dst, char const *restrict __src) 491 (char *restrict __dst, char const *restrict __src)
411 _GL_ARG_NONNULL ((1, 2))); 492 _GL_ARG_NONNULL ((1, 2)));
412# endif 493# endif
413_GL_CXXALIAS_SYS (stpcpy, char *, 494_GL_CXXALIAS_SYS (stpcpy, char *,
414 (char *restrict __dst, char const *restrict __src)); 495 (char *restrict __dst, char const *restrict __src));
496# endif
497# if __GLIBC__ >= 2
415_GL_CXXALIASWARN (stpcpy); 498_GL_CXXALIASWARN (stpcpy);
499# endif
416#elif defined GNULIB_POSIXCHECK 500#elif defined GNULIB_POSIXCHECK
417# undef stpcpy 501# undef stpcpy
418# if HAVE_RAW_DECL_STPCPY 502# if HAVE_RAW_DECL_STPCPY
@@ -447,7 +531,9 @@ _GL_CXXALIAS_SYS (stpncpy, char *,
447 (char *restrict __dst, char const *restrict __src, 531 (char *restrict __dst, char const *restrict __src,
448 size_t __n)); 532 size_t __n));
449# endif 533# endif
534# if __GLIBC__ >= 2
450_GL_CXXALIASWARN (stpncpy); 535_GL_CXXALIASWARN (stpncpy);
536# endif
451#elif defined GNULIB_POSIXCHECK 537#elif defined GNULIB_POSIXCHECK
452# undef stpncpy 538# undef stpncpy
453# if HAVE_RAW_DECL_STPNCPY 539# if HAVE_RAW_DECL_STPNCPY
@@ -495,10 +581,13 @@ _GL_CXXALIAS_SYS_CAST2 (strchrnul,
495# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \ 581# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \
496 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) \ 582 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) \
497 || defined __clang__) 583 || defined __clang__)
498_GL_CXXALIASWARN1 (strchrnul, char *, (char *__s, int __c_in) throw ()); 584_GL_CXXALIASWARN1 (strchrnul, char *,
585 (char *__s, int __c_in)
586 _GL_ATTRIBUTE_NOTHROW);
499_GL_CXXALIASWARN1 (strchrnul, char const *, 587_GL_CXXALIASWARN1 (strchrnul, char const *,
500 (char const *__s, int __c_in) throw ()); 588 (char const *__s, int __c_in)
501# else 589 _GL_ATTRIBUTE_NOTHROW);
590# elif __GLIBC__ >= 2
502_GL_CXXALIASWARN (strchrnul); 591_GL_CXXALIASWARN (strchrnul);
503# endif 592# endif
504#elif defined GNULIB_POSIXCHECK 593#elif defined GNULIB_POSIXCHECK
@@ -533,10 +622,18 @@ _GL_CXXALIAS_MDA (strdup, char *, (char const *__s));
533# undef strdup 622# undef strdup
534# endif 623# endif
535# if (!@HAVE_DECL_STRDUP@ || __GNUC__ >= 11) && !defined strdup 624# if (!@HAVE_DECL_STRDUP@ || __GNUC__ >= 11) && !defined strdup
625# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
626_GL_FUNCDECL_SYS (strdup, char *,
627 (char const *__s)
628 _GL_ATTRIBUTE_NOTHROW
629 _GL_ARG_NONNULL ((1))
630 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
631# else
536_GL_FUNCDECL_SYS (strdup, char *, 632_GL_FUNCDECL_SYS (strdup, char *,
537 (char const *__s) 633 (char const *__s)
538 _GL_ARG_NONNULL ((1)) 634 _GL_ARG_NONNULL ((1))
539 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 635 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
636# endif
540# endif 637# endif
541_GL_CXXALIAS_SYS (strdup, char *, (char const *__s)); 638_GL_CXXALIAS_SYS (strdup, char *, (char const *__s));
542# endif 639# endif
@@ -544,10 +641,18 @@ _GL_CXXALIASWARN (strdup);
544#else 641#else
545# if __GNUC__ >= 11 && !defined strdup 642# if __GNUC__ >= 11 && !defined strdup
546/* For -Wmismatched-dealloc: Associate strdup with free or rpl_free. */ 643/* For -Wmismatched-dealloc: Associate strdup with free or rpl_free. */
644# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
547_GL_FUNCDECL_SYS (strdup, char *, 645_GL_FUNCDECL_SYS (strdup, char *,
548 (char const *__s) 646 (char const *__s)
647 _GL_ATTRIBUTE_NOTHROW
549 _GL_ARG_NONNULL ((1)) 648 _GL_ARG_NONNULL ((1))
550 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 649 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
650# else
651_GL_FUNCDECL_SYS (strdup, char *,
652 (char const *__s)
653 _GL_ARG_NONNULL ((1))
654 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
655# endif
551# endif 656# endif
552# if defined GNULIB_POSIXCHECK 657# if defined GNULIB_POSIXCHECK
553# undef strdup 658# undef strdup
@@ -616,10 +721,18 @@ _GL_FUNCDECL_RPL (strndup, char *,
616_GL_CXXALIAS_RPL (strndup, char *, (char const *__s, size_t __n)); 721_GL_CXXALIAS_RPL (strndup, char *, (char const *__s, size_t __n));
617# else 722# else
618# if !@HAVE_DECL_STRNDUP@ || (__GNUC__ >= 11 && !defined strndup) 723# if !@HAVE_DECL_STRNDUP@ || (__GNUC__ >= 11 && !defined strndup)
724# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
619_GL_FUNCDECL_SYS (strndup, char *, 725_GL_FUNCDECL_SYS (strndup, char *,
620 (char const *__s, size_t __n) 726 (char const *__s, size_t __n)
727 _GL_ATTRIBUTE_NOTHROW
621 _GL_ARG_NONNULL ((1)) 728 _GL_ARG_NONNULL ((1))
622 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 729 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
730# else
731_GL_FUNCDECL_SYS (strndup, char *,
732 (char const *__s, size_t __n)
733 _GL_ARG_NONNULL ((1))
734 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
735# endif
623# endif 736# endif
624_GL_CXXALIAS_SYS (strndup, char *, (char const *__s, size_t __n)); 737_GL_CXXALIAS_SYS (strndup, char *, (char const *__s, size_t __n));
625# endif 738# endif
@@ -627,10 +740,18 @@ _GL_CXXALIASWARN (strndup);
627#else 740#else
628# if __GNUC__ >= 11 && !defined strndup 741# if __GNUC__ >= 11 && !defined strndup
629/* For -Wmismatched-dealloc: Associate strndup with free or rpl_free. */ 742/* For -Wmismatched-dealloc: Associate strndup with free or rpl_free. */
743# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
630_GL_FUNCDECL_SYS (strndup, char *, 744_GL_FUNCDECL_SYS (strndup, char *,
631 (char const *__s, size_t __n) 745 (char const *__s, size_t __n)
746 _GL_ATTRIBUTE_NOTHROW
632 _GL_ARG_NONNULL ((1)) 747 _GL_ARG_NONNULL ((1))
633 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 748 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
749# else
750_GL_FUNCDECL_SYS (strndup, char *,
751 (char const *__s, size_t __n)
752 _GL_ARG_NONNULL ((1))
753 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
754# endif
634# endif 755# endif
635# if defined GNULIB_POSIXCHECK 756# if defined GNULIB_POSIXCHECK
636# undef strndup 757# undef strndup
@@ -699,9 +820,12 @@ _GL_CXXALIAS_SYS_CAST2 (strpbrk,
699# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \ 820# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \
700 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) \ 821 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) \
701 || defined __clang__) 822 || defined __clang__)
702_GL_CXXALIASWARN1 (strpbrk, char *, (char *__s, char const *__accept) throw ()); 823_GL_CXXALIASWARN1 (strpbrk, char *,
824 (char *__s, char const *__accept)
825 _GL_ATTRIBUTE_NOTHROW);
703_GL_CXXALIASWARN1 (strpbrk, char const *, 826_GL_CXXALIASWARN1 (strpbrk, char const *,
704 (char const *__s, char const *__accept) throw ()); 827 (char const *__s, char const *__accept)
828 _GL_ATTRIBUTE_NOTHROW);
705# elif __GLIBC__ >= 2 829# elif __GLIBC__ >= 2
706_GL_CXXALIASWARN (strpbrk); 830_GL_CXXALIASWARN (strpbrk);
707# endif 831# endif
@@ -809,9 +933,11 @@ _GL_CXXALIAS_SYS_CAST2 (strstr,
809 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) \ 933 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) \
810 || defined __clang__) 934 || defined __clang__)
811_GL_CXXALIASWARN1 (strstr, char *, 935_GL_CXXALIASWARN1 (strstr, char *,
812 (char *haystack, const char *needle) throw ()); 936 (char *haystack, const char *needle)
937 _GL_ATTRIBUTE_NOTHROW);
813_GL_CXXALIASWARN1 (strstr, const char *, 938_GL_CXXALIASWARN1 (strstr, const char *,
814 (const char *haystack, const char *needle) throw ()); 939 (const char *haystack, const char *needle)
940 _GL_ATTRIBUTE_NOTHROW);
815# elif __GLIBC__ >= 2 941# elif __GLIBC__ >= 2
816_GL_CXXALIASWARN (strstr); 942_GL_CXXALIASWARN (strstr);
817# endif 943# endif
@@ -860,10 +986,12 @@ _GL_CXXALIAS_SYS_CAST2 (strcasestr,
860 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) \ 986 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) \
861 || defined __clang__) 987 || defined __clang__)
862_GL_CXXALIASWARN1 (strcasestr, char *, 988_GL_CXXALIASWARN1 (strcasestr, char *,
863 (char *haystack, const char *needle) throw ()); 989 (char *haystack, const char *needle)
990 _GL_ATTRIBUTE_NOTHROW);
864_GL_CXXALIASWARN1 (strcasestr, const char *, 991_GL_CXXALIASWARN1 (strcasestr, const char *,
865 (const char *haystack, const char *needle) throw ()); 992 (const char *haystack, const char *needle)
866# else 993 _GL_ATTRIBUTE_NOTHROW);
994# elif __GLIBC__ >= 2
867_GL_CXXALIASWARN (strcasestr); 995_GL_CXXALIASWARN (strcasestr);
868# endif 996# endif
869#elif defined GNULIB_POSIXCHECK 997#elif defined GNULIB_POSIXCHECK
@@ -1211,7 +1339,7 @@ _GL_FUNCDECL_SYS (strerror_r, int, (int errnum, char *buf, size_t buflen)
1211# endif 1339# endif
1212_GL_CXXALIAS_SYS (strerror_r, int, (int errnum, char *buf, size_t buflen)); 1340_GL_CXXALIAS_SYS (strerror_r, int, (int errnum, char *buf, size_t buflen));
1213# endif 1341# endif
1214# if @HAVE_DECL_STRERROR_R@ 1342# if __GLIBC__ >= 2 && @HAVE_DECL_STRERROR_R@
1215_GL_CXXALIASWARN (strerror_r); 1343_GL_CXXALIASWARN (strerror_r);
1216# endif 1344# endif
1217#elif defined GNULIB_POSIXCHECK 1345#elif defined GNULIB_POSIXCHECK
@@ -1301,12 +1429,22 @@ _GL_WARN_ON_USE (strsignal, "strsignal is unportable - "
1301#endif 1429#endif
1302 1430
1303#if @GNULIB_STRVERSCMP@ 1431#if @GNULIB_STRVERSCMP@
1304# if !@HAVE_STRVERSCMP@ 1432# if @REPLACE_STRVERSCMP@
1433# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1434# define strverscmp rpl_strverscmp
1435# endif
1436_GL_FUNCDECL_RPL (strverscmp, int, (const char *, const char *)
1437 _GL_ATTRIBUTE_PURE
1438 _GL_ARG_NONNULL ((1, 2)));
1439_GL_CXXALIAS_RPL (strverscmp, int, (const char *, const char *));
1440# else
1441# if !@HAVE_STRVERSCMP@
1305_GL_FUNCDECL_SYS (strverscmp, int, (const char *, const char *) 1442_GL_FUNCDECL_SYS (strverscmp, int, (const char *, const char *)
1306 _GL_ATTRIBUTE_PURE 1443 _GL_ATTRIBUTE_PURE
1307 _GL_ARG_NONNULL ((1, 2))); 1444 _GL_ARG_NONNULL ((1, 2)));
1308# endif 1445# endif
1309_GL_CXXALIAS_SYS (strverscmp, int, (const char *, const char *)); 1446_GL_CXXALIAS_SYS (strverscmp, int, (const char *, const char *));
1447# endif
1310_GL_CXXALIASWARN (strverscmp); 1448_GL_CXXALIASWARN (strverscmp);
1311#elif defined GNULIB_POSIXCHECK 1449#elif defined GNULIB_POSIXCHECK
1312# undef strverscmp 1450# undef strverscmp
diff --git a/gl/strings.in.h b/gl/strings.in.h
index 2cfe8b16..2b3e062a 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2007-2024 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,6 +36,11 @@
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_*. */
40#if !_GL_CONFIG_H_INCLUDED
41 #error "Please include config.h first."
42#endif
43
39#if ! @HAVE_DECL_STRNCASECMP@ 44#if ! @HAVE_DECL_STRNCASECMP@
40/* Get size_t. */ 45/* Get size_t. */
41# include <stddef.h> 46# include <stddef.h>
diff --git a/gl/stripslash.c b/gl/stripslash.c
index fe46a9c1..c127ce7e 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-2023 Free Software Foundation, 3 Copyright (C) 1990, 2001, 2003-2006, 2009-2024 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 c5c2cd35..c79161f3 100644
--- a/gl/strncasecmp.c
+++ b/gl/strncasecmp.c
@@ -1,5 +1,5 @@
1/* strncasecmp.c -- case insensitive string comparator 1/* strncasecmp.c -- case insensitive string comparator
2 Copyright (C) 1998-1999, 2005-2007, 2009-2023 Free Software Foundation, Inc. 2 Copyright (C) 1998-1999, 2005-2007, 2009-2024 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
@@ -22,8 +22,6 @@
22#include <ctype.h> 22#include <ctype.h>
23#include <limits.h> 23#include <limits.h>
24 24
25#define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
26
27/* Compare no more than N bytes of strings S1 and S2, ignoring case, 25/* Compare no more than N bytes of strings S1 and S2, ignoring case,
28 returning less than, equal to or greater than zero if S1 is 26 returning less than, equal to or greater than zero if S1 is
29 lexicographically less than, equal to or greater than S2. 27 lexicographically less than, equal to or greater than S2.
@@ -41,8 +39,8 @@ strncasecmp (const char *s1, const char *s2, size_t n)
41 39
42 do 40 do
43 { 41 {
44 c1 = TOLOWER (*p1); 42 c1 = tolower (*p1);
45 c2 = TOLOWER (*p2); 43 c2 = tolower (*p2);
46 44
47 if (--n == 0 || c1 == '\0') 45 if (--n == 0 || c1 == '\0')
48 break; 46 break;
diff --git a/gl/strsep.c b/gl/strsep.c
index 8e9708a3..eefd85e2 100644
--- a/gl/strsep.c
+++ b/gl/strsep.c
@@ -1,4 +1,4 @@
1/* Copyright (C) 2004, 2007, 2009-2023 Free Software Foundation, Inc. 1/* Copyright (C) 2004, 2007, 2009-2024 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 574f4d50..7ea28603 100644
--- a/gl/strstr.c
+++ b/gl/strstr.c
@@ -1,4 +1,4 @@
1/* Copyright (C) 1991-1994, 1996-1998, 2000, 2004, 2007-2023 Free Software 1/* Copyright (C) 1991-1994, 1996-1998, 2000, 2004, 2007-2024 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 0e9556d6..d2f29d80 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-2023 Free Software Foundation, Inc. 3 Copyright 2018-2024 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 b7388cec..672d3aac 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2012-2024 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
@@ -18,5 +18,5 @@
18#include <config.h> 18#include <config.h>
19 19
20#define _GL_SYS_SOCKET_INLINE _GL_EXTERN_INLINE 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 6705593f..13833c0f 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2005-2024 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
@@ -63,9 +63,12 @@
63#ifndef _@GUARD_PREFIX@_SYS_SOCKET_H 63#ifndef _@GUARD_PREFIX@_SYS_SOCKET_H
64#define _@GUARD_PREFIX@_SYS_SOCKET_H 64#define _@GUARD_PREFIX@_SYS_SOCKET_H
65 65
66#ifndef _GL_INLINE_HEADER_BEGIN 66/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE, GNULIB_POSIXCHECK,
67 HAVE_RAW_DECL_*, alignof. */
68#if !_GL_CONFIG_H_INCLUDED
67 #error "Please include config.h first." 69 #error "Please include config.h first."
68#endif 70#endif
71
69_GL_INLINE_HEADER_BEGIN 72_GL_INLINE_HEADER_BEGIN
70#ifndef _GL_SYS_SOCKET_INLINE 73#ifndef _GL_SYS_SOCKET_INLINE
71# define _GL_SYS_SOCKET_INLINE _GL_INLINE 74# define _GL_SYS_SOCKET_INLINE _GL_INLINE
@@ -355,7 +358,9 @@ _GL_CXXALIAS_SYS_CAST (accept, int,
355 struct sockaddr *restrict addr, 358 struct sockaddr *restrict addr,
356 socklen_t *restrict addrlen)); 359 socklen_t *restrict addrlen));
357# endif 360# endif
361# if __GLIBC__ >= 2
358_GL_CXXALIASWARN (accept); 362_GL_CXXALIASWARN (accept);
363# endif
359#elif @HAVE_WINSOCK2_H@ 364#elif @HAVE_WINSOCK2_H@
360# undef accept 365# undef accept
361# define accept accept_used_without_requesting_gnulib_module_accept 366# define accept accept_used_without_requesting_gnulib_module_accept
@@ -417,7 +422,9 @@ _GL_CXXALIAS_SYS_CAST (getpeername, int,
417 (int fd, struct sockaddr *restrict addr, 422 (int fd, struct sockaddr *restrict addr,
418 socklen_t *restrict addrlen)); 423 socklen_t *restrict addrlen));
419# endif 424# endif
425# if __GLIBC__ >= 2
420_GL_CXXALIASWARN (getpeername); 426_GL_CXXALIASWARN (getpeername);
427# endif
421#elif @HAVE_WINSOCK2_H@ 428#elif @HAVE_WINSOCK2_H@
422# undef getpeername 429# undef getpeername
423# define getpeername getpeername_used_without_requesting_gnulib_module_getpeername 430# define getpeername getpeername_used_without_requesting_gnulib_module_getpeername
@@ -449,7 +456,9 @@ _GL_CXXALIAS_SYS_CAST (getsockname, int,
449 (int fd, struct sockaddr *restrict addr, 456 (int fd, struct sockaddr *restrict addr,
450 socklen_t *restrict addrlen)); 457 socklen_t *restrict addrlen));
451# endif 458# endif
459# if __GLIBC__ >= 2
452_GL_CXXALIASWARN (getsockname); 460_GL_CXXALIASWARN (getsockname);
461# endif
453#elif @HAVE_WINSOCK2_H@ 462#elif @HAVE_WINSOCK2_H@
454# undef getsockname 463# undef getsockname
455# define getsockname getsockname_used_without_requesting_gnulib_module_getsockname 464# define getsockname getsockname_used_without_requesting_gnulib_module_getsockname
@@ -596,7 +605,9 @@ _GL_CXXALIAS_SYS_CAST (recvfrom, ssize_t,
596 struct sockaddr *restrict from, 605 struct sockaddr *restrict from,
597 socklen_t *restrict fromlen)); 606 socklen_t *restrict fromlen));
598# endif 607# endif
608# if __GLIBC__ >= 2
599_GL_CXXALIASWARN (recvfrom); 609_GL_CXXALIASWARN (recvfrom);
610# endif
600#elif @HAVE_WINSOCK2_H@ 611#elif @HAVE_WINSOCK2_H@
601# undef recvfrom 612# undef recvfrom
602# define recvfrom recvfrom_used_without_requesting_gnulib_module_recvfrom 613# define recvfrom recvfrom_used_without_requesting_gnulib_module_recvfrom
diff --git a/gl/sys_stat.in.h b/gl/sys_stat.in.h
index 096887c0..bf08f335 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2005-2024 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,13 @@
25#endif 25#endif
26@PRAGMA_COLUMNS@ 26@PRAGMA_COLUMNS@
27 27
28/* This file uses #include_next of a system file that defines time_t.
29 For the 'year2038' module to work right, <config.h> needs to have been
30 included before. */
31#if !_GL_CONFIG_H_INCLUDED
32 #error "Please include config.h first."
33#endif
34
28#if defined __need_system_sys_stat_h 35#if defined __need_system_sys_stat_h
29/* Special invocation convention. */ 36/* Special invocation convention. */
30 37
@@ -48,12 +55,41 @@
48#ifndef _@GUARD_PREFIX@_SYS_STAT_H 55#ifndef _@GUARD_PREFIX@_SYS_STAT_H
49#define _@GUARD_PREFIX@_SYS_STAT_H 56#define _@GUARD_PREFIX@_SYS_STAT_H
50 57
58/* This file uses _GL_ATTRIBUTE_NOTHROW, GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */
59#if !_GL_CONFIG_H_INCLUDED
60 #error "Please include config.h first."
61#endif
62
63
64/* _GL_ATTRIBUTE_NOTHROW declares that the function does not throw exceptions.
65 */
66#ifndef _GL_ATTRIBUTE_NOTHROW
67# if defined __cplusplus
68# if (__GNUC__ + (__GNUC_MINOR__ >= 8) > 2) || __clang_major >= 4
69# if __cplusplus >= 201103L
70# define _GL_ATTRIBUTE_NOTHROW noexcept (true)
71# else
72# define _GL_ATTRIBUTE_NOTHROW throw ()
73# endif
74# else
75# define _GL_ATTRIBUTE_NOTHROW
76# endif
77# else
78# if (__GNUC__ + (__GNUC_MINOR__ >= 3) > 3) || defined __clang__
79# define _GL_ATTRIBUTE_NOTHROW __attribute__ ((__nothrow__))
80# else
81# define _GL_ATTRIBUTE_NOTHROW
82# endif
83# endif
84#endif
85
51/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ 86/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
52 87
53/* The definition of _GL_ARG_NONNULL is copied here. */ 88/* The definition of _GL_ARG_NONNULL is copied here. */
54 89
55/* The definition of _GL_WARN_ON_USE is copied here. */ 90/* The definition of _GL_WARN_ON_USE is copied here. */
56 91
92
57/* Before doing "#define mknod rpl_mknod" below, we need to include all 93/* Before doing "#define mknod rpl_mknod" below, we need to include all
58 headers that may declare mknod(). OS/2 kLIBC declares mknod() in 94 headers that may declare mknod(). OS/2 kLIBC declares mknod() in
59 <unistd.h>, not in <sys/stat.h>. */ 95 <unistd.h>, not in <sys/stat.h>. */
@@ -549,7 +585,7 @@ _GL_FUNCDECL_SYS (futimens, int, (int fd, struct timespec const times[2]));
549# endif 585# endif
550_GL_CXXALIAS_SYS (futimens, int, (int fd, struct timespec const times[2])); 586_GL_CXXALIAS_SYS (futimens, int, (int fd, struct timespec const times[2]));
551# endif 587# endif
552# if @HAVE_FUTIMENS@ 588# if __GLIBC__ >= 2 && @HAVE_FUTIMENS@
553_GL_CXXALIASWARN (futimens); 589_GL_CXXALIASWARN (futimens);
554# endif 590# endif
555#elif defined GNULIB_POSIXCHECK 591#elif defined GNULIB_POSIXCHECK
@@ -563,7 +599,11 @@ _GL_WARN_ON_USE (futimens, "futimens is not portable - "
563 599
564#if @GNULIB_GETUMASK@ 600#if @GNULIB_GETUMASK@
565# if !@HAVE_GETUMASK@ 601# if !@HAVE_GETUMASK@
602# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
603_GL_FUNCDECL_SYS (getumask, mode_t, (void) _GL_ATTRIBUTE_NOTHROW);
604# else
566_GL_FUNCDECL_SYS (getumask, mode_t, (void)); 605_GL_FUNCDECL_SYS (getumask, mode_t, (void));
606# endif
567# endif 607# endif
568_GL_CXXALIAS_SYS (getumask, mode_t, (void)); 608_GL_CXXALIAS_SYS (getumask, mode_t, (void));
569# if @HAVE_GETUMASK@ 609# if @HAVE_GETUMASK@
@@ -716,7 +756,9 @@ _GL_FUNCDECL_SYS (mkfifoat, int, (int fd, char const *file, mode_t mode)
716# endif 756# endif
717_GL_CXXALIAS_SYS (mkfifoat, int, (int fd, char const *file, mode_t mode)); 757_GL_CXXALIAS_SYS (mkfifoat, int, (int fd, char const *file, mode_t mode));
718# endif 758# endif
759# if __GLIBC__ >= 2
719_GL_CXXALIASWARN (mkfifoat); 760_GL_CXXALIASWARN (mkfifoat);
761# endif
720#elif defined GNULIB_POSIXCHECK 762#elif defined GNULIB_POSIXCHECK
721# undef mkfifoat 763# undef mkfifoat
722# if HAVE_RAW_DECL_MKFIFOAT 764# if HAVE_RAW_DECL_MKFIFOAT
@@ -773,7 +815,9 @@ _GL_FUNCDECL_SYS (mknodat, int,
773_GL_CXXALIAS_SYS (mknodat, int, 815_GL_CXXALIAS_SYS (mknodat, int,
774 (int fd, char const *file, mode_t mode, dev_t dev)); 816 (int fd, char const *file, mode_t mode, dev_t dev));
775# endif 817# endif
818# if __GLIBC__ >= 2
776_GL_CXXALIASWARN (mknodat); 819_GL_CXXALIASWARN (mknodat);
820# endif
777#elif defined GNULIB_POSIXCHECK 821#elif defined GNULIB_POSIXCHECK
778# undef mknodat 822# undef mknodat
779# if HAVE_RAW_DECL_MKNODAT 823# if HAVE_RAW_DECL_MKNODAT
@@ -937,7 +981,7 @@ _GL_FUNCDECL_SYS (utimensat, int, (int fd, char const *name,
937_GL_CXXALIAS_SYS (utimensat, int, (int fd, char const *name, 981_GL_CXXALIAS_SYS (utimensat, int, (int fd, char const *name,
938 struct timespec const times[2], int flag)); 982 struct timespec const times[2], int flag));
939# endif 983# endif
940# if @HAVE_UTIMENSAT@ 984# if __GLIBC__ >= 2 && @HAVE_UTIMENSAT@
941_GL_CXXALIASWARN (utimensat); 985_GL_CXXALIASWARN (utimensat);
942# endif 986# endif
943#elif defined GNULIB_POSIXCHECK 987#elif defined GNULIB_POSIXCHECK
diff --git a/gl/sys_types.in.h b/gl/sys_types.in.h
index 082a6c67..0a0ccc3c 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2011-2024 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,6 +20,13 @@
20#endif 20#endif
21@PRAGMA_COLUMNS@ 21@PRAGMA_COLUMNS@
22 22
23/* This file uses #include_next of a system file that defines time_t.
24 For the 'year2038' module to work right, <config.h> needs to have been
25 included before. */
26#if !_GL_CONFIG_H_INCLUDED
27 #error "Please include config.h first."
28#endif
29
23#if defined _WIN32 && !defined __CYGWIN__ \ 30#if defined _WIN32 && !defined __CYGWIN__ \
24 && (defined __need_off_t || defined __need___off64_t \ 31 && (defined __need_off_t || defined __need___off64_t \
25 || defined __need_ssize_t || defined __need_time_t) 32 || defined __need_ssize_t || defined __need_time_t)
diff --git a/gl/sys_uio.in.h b/gl/sys_uio.in.h
index 64c4fb6d..5e71859d 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2011-2024 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 50c9b30b..df99c8ab 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2007-2024 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,6 +20,13 @@
20#endif 20#endif
21@PRAGMA_COLUMNS@ 21@PRAGMA_COLUMNS@
22 22
23/* This file uses #include_next of a system file that defines time_t.
24 For the 'year2038' module to work right, <config.h> needs to have been
25 included before. */
26#if !_GL_CONFIG_H_INCLUDED
27 #error "Please include config.h first."
28#endif
29
23/* Don't get in the way of glibc when it includes time.h merely to 30/* Don't get in the way of glibc when it includes time.h merely to
24 declare a few standard symbols, rather than to declare all the 31 declare a few standard symbols, rather than to declare all the
25 symbols. (However, skip this for MinGW as it treats __need_time_t 32 symbols. (However, skip this for MinGW as it treats __need_time_t
@@ -45,6 +52,12 @@
45 52
46# @INCLUDE_NEXT@ @NEXT_TIME_H@ 53# @INCLUDE_NEXT@ @NEXT_TIME_H@
47 54
55/* This file uses _GL_ATTRIBUTE_DEPRECATED, GNULIB_POSIXCHECK,
56 HAVE_RAW_DECL_*. */
57# if !_GL_CONFIG_H_INCLUDED
58# error "Please include config.h first."
59# endif
60
48/* NetBSD 5.0 mis-defines NULL. */ 61/* NetBSD 5.0 mis-defines NULL. */
49# include <stddef.h> 62# include <stddef.h>
50 63
@@ -112,23 +125,79 @@ struct __time_t_must_be_integral {
112/* Set *TS to the current time, and return BASE. 125/* Set *TS to the current time, and return BASE.
113 Upon failure, return 0. */ 126 Upon failure, return 0. */
114# if @GNULIB_TIMESPEC_GET@ 127# if @GNULIB_TIMESPEC_GET@
115# if ! @HAVE_TIMESPEC_GET@ 128# if @REPLACE_TIMESPEC_GET@
129# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
130# undef timespec_get
131# define timespec_get rpl_timespec_get
132# endif
133_GL_FUNCDECL_RPL (timespec_get, int, (struct timespec *ts, int base)
134 _GL_ARG_NONNULL ((1)));
135_GL_CXXALIAS_RPL (timespec_get, int, (struct timespec *ts, int base));
136# else
137# if !@HAVE_TIMESPEC_GET@
116_GL_FUNCDECL_SYS (timespec_get, int, (struct timespec *ts, int base) 138_GL_FUNCDECL_SYS (timespec_get, int, (struct timespec *ts, int base)
117 _GL_ARG_NONNULL ((1))); 139 _GL_ARG_NONNULL ((1)));
118# endif 140# endif
119_GL_CXXALIAS_SYS (timespec_get, int, (struct timespec *ts, int base)); 141_GL_CXXALIAS_SYS (timespec_get, int, (struct timespec *ts, int base));
142# endif
143# if __GLIBC__ >= 2
120_GL_CXXALIASWARN (timespec_get); 144_GL_CXXALIASWARN (timespec_get);
145# endif
146# elif defined GNULIB_POSIXCHECK
147# undef timespec_get
148# if HAVE_RAW_DECL_TIMESPEC_GET
149_GL_WARN_ON_USE (timespec_get, "timespec_get is unportable - "
150 "use gnulib module timespec_get for portability");
151# endif
121# endif 152# endif
122 153
123/* Set *TS to the current time resolution, and return BASE. 154/* Set *TS to the current time resolution, and return BASE.
124 Upon failure, return 0. */ 155 Upon failure, return 0. */
125# if @GNULIB_TIMESPEC_GETRES@ 156# if @GNULIB_TIMESPEC_GETRES@
126# if ! @HAVE_TIMESPEC_GETRES@ 157# if @REPLACE_TIMESPEC_GETRES@
158# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
159# undef timespec_getres
160# define timespec_getres rpl_timespec_getres
161# endif
162_GL_FUNCDECL_RPL (timespec_getres, int, (struct timespec *ts, int base)
163 _GL_ARG_NONNULL ((1)));
164_GL_CXXALIAS_RPL (timespec_getres, int, (struct timespec *ts, int base));
165# else
166# if !@HAVE_TIMESPEC_GETRES@
127_GL_FUNCDECL_SYS (timespec_getres, int, (struct timespec *ts, int base) 167_GL_FUNCDECL_SYS (timespec_getres, int, (struct timespec *ts, int base)
128 _GL_ARG_NONNULL ((1))); 168 _GL_ARG_NONNULL ((1)));
129# endif 169# endif
130_GL_CXXALIAS_SYS (timespec_getres, int, (struct timespec *ts, int base)); 170_GL_CXXALIAS_SYS (timespec_getres, int, (struct timespec *ts, int base));
171# endif
131_GL_CXXALIASWARN (timespec_getres); 172_GL_CXXALIASWARN (timespec_getres);
173# elif defined GNULIB_POSIXCHECK
174# undef timespec_getres
175# if HAVE_RAW_DECL_TIMESPEC_GETRES
176_GL_WARN_ON_USE (timespec_getres, "timespec_getres is unportable - "
177 "use gnulib module timespec_getres for portability");
178# endif
179# endif
180
181/* Return the number of seconds that have elapsed since the Epoch. */
182# if @GNULIB_TIME@
183# if @REPLACE_TIME@
184# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
185# define time rpl_time
186# endif
187_GL_FUNCDECL_RPL (time, time_t, (time_t *__tp));
188_GL_CXXALIAS_RPL (time, time_t, (time_t *__tp));
189# else
190_GL_CXXALIAS_SYS (time, time_t, (time_t *__tp));
191# endif
192# if __GLIBC__ >= 2
193_GL_CXXALIASWARN (time);
194# endif
195# elif defined GNULIB_POSIXCHECK
196# undef time
197# if HAVE_RAW_DECL_TIME
198_GL_WARN_ON_USE (time, "time has consistency problems - "
199 "use gnulib module time for portability");
200# endif
132# endif 201# endif
133 202
134/* Sleep for at least RQTP seconds unless interrupted, If interrupted, 203/* Sleep for at least RQTP seconds unless interrupted, If interrupted,
@@ -154,6 +223,12 @@ _GL_CXXALIAS_SYS (nanosleep, int,
154 (struct timespec const *__rqtp, struct timespec *__rmtp)); 223 (struct timespec const *__rqtp, struct timespec *__rmtp));
155# endif 224# endif
156_GL_CXXALIASWARN (nanosleep); 225_GL_CXXALIASWARN (nanosleep);
226# elif defined GNULIB_POSIXCHECK
227# undef nanosleep
228# if HAVE_RAW_DECL_NANOSLEEP
229_GL_WARN_ON_USE (nanosleep, "nanosleep is unportable - "
230 "use gnulib module nanosleep for portability");
231# endif
157# endif 232# endif
158 233
159/* Initialize time conversion information. */ 234/* Initialize time conversion information. */
@@ -189,6 +264,12 @@ _GL_CXXALIAS_MDA (tzset, void, (void));
189_GL_CXXALIAS_SYS (tzset, void, (void)); 264_GL_CXXALIAS_SYS (tzset, void, (void));
190# endif 265# endif
191_GL_CXXALIASWARN (tzset); 266_GL_CXXALIASWARN (tzset);
267# elif defined GNULIB_POSIXCHECK
268# undef tzset
269# if HAVE_RAW_DECL_TZSET
270_GL_WARN_ON_USE (tzset, "tzset has portability problems - "
271 "use gnulib module tzset for portability");
272# endif
192# endif 273# endif
193 274
194/* Return the 'time_t' representation of TP and normalize TP. */ 275/* Return the 'time_t' representation of TP and normalize TP. */
@@ -205,6 +286,12 @@ _GL_CXXALIAS_SYS (mktime, time_t, (struct tm *__tp));
205# if __GLIBC__ >= 2 286# if __GLIBC__ >= 2
206_GL_CXXALIASWARN (mktime); 287_GL_CXXALIASWARN (mktime);
207# endif 288# endif
289# elif defined GNULIB_POSIXCHECK
290# undef mktime
291# if HAVE_RAW_DECL_MKTIME
292_GL_WARN_ON_USE (mktime, "mktime has portability problems - "
293 "use gnulib module mktime for portability");
294# endif
208# endif 295# endif
209 296
210/* Convert TIMER to RESULT, assuming local time and UTC respectively. See 297/* Convert TIMER to RESULT, assuming local time and UTC respectively. See
@@ -255,6 +342,17 @@ _GL_CXXALIAS_SYS (gmtime_r, struct tm *, (time_t const *restrict __timer,
255# if @HAVE_DECL_LOCALTIME_R@ 342# if @HAVE_DECL_LOCALTIME_R@
256_GL_CXXALIASWARN (gmtime_r); 343_GL_CXXALIASWARN (gmtime_r);
257# endif 344# endif
345# elif defined GNULIB_POSIXCHECK
346# undef localtime_r
347# if HAVE_RAW_DECL_LOCALTIME_R
348_GL_WARN_ON_USE (localtime_r, "localtime_r is unportable - "
349 "use gnulib module time_r for portability");
350# endif
351# undef gmtime_r
352# if HAVE_RAW_DECL_GMTIME_R
353_GL_WARN_ON_USE (gmtime_r, "gmtime_r is unportable - "
354 "use gnulib module time_r for portability");
355# endif
258# endif 356# endif
259 357
260/* Convert TIMER to RESULT, assuming local time and UTC respectively. See 358/* Convert TIMER to RESULT, assuming local time and UTC respectively. See
@@ -275,6 +373,12 @@ _GL_CXXALIAS_SYS (localtime, struct tm *, (time_t const *__timer));
275# if __GLIBC__ >= 2 373# if __GLIBC__ >= 2
276_GL_CXXALIASWARN (localtime); 374_GL_CXXALIASWARN (localtime);
277# endif 375# endif
376# elif defined GNULIB_POSIXCHECK
377# undef localtime
378# if HAVE_RAW_DECL_LOCALTIME
379_GL_WARN_ON_USE (localtime, "localtime has portability problems - "
380 "use gnulib module localtime for portability");
381# endif
278# endif 382# endif
279 383
280# if 0 || @REPLACE_GMTIME@ 384# if 0 || @REPLACE_GMTIME@
@@ -306,6 +410,12 @@ _GL_CXXALIAS_SYS (strptime, char *, (char const *restrict __buf,
306 char const *restrict __format, 410 char const *restrict __format,
307 struct tm *restrict __tm)); 411 struct tm *restrict __tm));
308_GL_CXXALIASWARN (strptime); 412_GL_CXXALIASWARN (strptime);
413# elif defined GNULIB_POSIXCHECK
414# undef strptime
415# if HAVE_RAW_DECL_STRPTIME
416_GL_WARN_ON_USE (strptime, "strptime is unportable - "
417 "use gnulib module strptime for portability");
418# endif
309# endif 419# endif
310 420
311/* Convert *TP to a date and time string. See 421/* Convert *TP to a date and time string. See
@@ -315,7 +425,9 @@ _GL_CXXALIASWARN (strptime);
315# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 425# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
316# define ctime rpl_ctime 426# define ctime rpl_ctime
317# endif 427# endif
428# ifndef __cplusplus
318_GL_ATTRIBUTE_DEPRECATED 429_GL_ATTRIBUTE_DEPRECATED
430# endif
319_GL_FUNCDECL_RPL (ctime, char *, (time_t const *__tp) 431_GL_FUNCDECL_RPL (ctime, char *, (time_t const *__tp)
320 _GL_ARG_NONNULL ((1))); 432 _GL_ARG_NONNULL ((1)));
321_GL_CXXALIAS_RPL (ctime, char *, (time_t const *__tp)); 433_GL_CXXALIAS_RPL (ctime, char *, (time_t const *__tp));
@@ -325,6 +437,8 @@ _GL_CXXALIAS_SYS (ctime, char *, (time_t const *__tp));
325# if __GLIBC__ >= 2 437# if __GLIBC__ >= 2
326_GL_CXXALIASWARN (ctime); 438_GL_CXXALIASWARN (ctime);
327# endif 439# endif
440# elif defined GNULIB_POSIXCHECK
441/* No need to warn about portability, as a more serious warning is below. */
328# endif 442# endif
329 443
330/* Convert *TP to a date and time string. See 444/* Convert *TP to a date and time string. See
@@ -349,6 +463,12 @@ _GL_CXXALIAS_SYS (strftime, size_t,
349# if __GLIBC__ >= 2 463# if __GLIBC__ >= 2
350_GL_CXXALIASWARN (strftime); 464_GL_CXXALIASWARN (strftime);
351# endif 465# endif
466# elif defined GNULIB_POSIXCHECK
467# undef strftime
468# if HAVE_RAW_DECL_STRFTIME
469_GL_WARN_ON_USE (strftime, "strftime has portability problems - "
470 "use gnulib module strftime-fixes for portability");
471# endif
352# endif 472# endif
353 473
354# if defined _GNU_SOURCE && @GNULIB_TIME_RZ@ && ! @HAVE_TIMEZONE_T@ 474# if defined _GNU_SOURCE && @GNULIB_TIME_RZ@ && ! @HAVE_TIMEZONE_T@
@@ -423,7 +543,15 @@ _GL_FUNCDECL_SYS (timegm, time_t, (struct tm *__tm) _GL_ARG_NONNULL ((1)));
423# endif 543# endif
424_GL_CXXALIAS_SYS (timegm, time_t, (struct tm *__tm)); 544_GL_CXXALIAS_SYS (timegm, time_t, (struct tm *__tm));
425# endif 545# endif
546# if __GLIBC__ >= 2
426_GL_CXXALIASWARN (timegm); 547_GL_CXXALIASWARN (timegm);
548# endif
549# elif defined GNULIB_POSIXCHECK
550# undef timegm
551# if HAVE_RAW_DECL_TIMEGM
552_GL_WARN_ON_USE (timegm, "timegm is unportable - "
553 "use gnulib module timegm for portability");
554# endif
427# endif 555# endif
428 556
429/* Encourage applications to avoid unsafe functions that can overrun 557/* Encourage applications to avoid unsafe functions that can overrun
@@ -431,8 +559,10 @@ _GL_CXXALIASWARN (timegm);
431 applications should use strftime (or even sprintf) instead. */ 559 applications should use strftime (or even sprintf) instead. */
432# if defined GNULIB_POSIXCHECK 560# if defined GNULIB_POSIXCHECK
433# undef asctime 561# undef asctime
562# if HAVE_RAW_DECL_ASCTIME
434_GL_WARN_ON_USE (asctime, "asctime can overrun buffers in some cases - " 563_GL_WARN_ON_USE (asctime, "asctime can overrun buffers in some cases - "
435 "better use strftime (or even sprintf) instead"); 564 "better use strftime (or even sprintf) instead");
565# endif
436# endif 566# endif
437# if defined GNULIB_POSIXCHECK 567# if defined GNULIB_POSIXCHECK
438# undef asctime_r 568# undef asctime_r
@@ -443,8 +573,10 @@ _GL_WARN_ON_USE (asctime_r, "asctime_r can overrun buffers in some cases - "
443# endif 573# endif
444# if defined GNULIB_POSIXCHECK 574# if defined GNULIB_POSIXCHECK
445# undef ctime 575# undef ctime
576# if HAVE_RAW_DECL_CTIME
446_GL_WARN_ON_USE (ctime, "ctime can overrun buffers in some cases - " 577_GL_WARN_ON_USE (ctime, "ctime can overrun buffers in some cases - "
447 "better use strftime (or even sprintf) instead"); 578 "better use strftime (or even sprintf) instead");
579# endif
448# endif 580# endif
449# if defined GNULIB_POSIXCHECK 581# if defined GNULIB_POSIXCHECK
450# undef ctime_r 582# undef ctime_r
diff --git a/gl/time_r.c b/gl/time_r.c
index 97be4fd0..b724f3b3 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2003, 2006-2007, 2010-2024 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
@@ -21,6 +21,11 @@
21 21
22#include <time.h> 22#include <time.h>
23 23
24/* The replacement functions in this file are only used on native Windows.
25 They are multithread-safe, because the gmtime() and localtime() functions
26 on native Windows — both in the ucrt and in the older MSVCRT — return a
27 pointer to a 'struct tm' in thread-local memory. */
28
24static struct tm * 29static struct tm *
25copy_tm_result (struct tm *dest, struct tm const *src) 30copy_tm_result (struct tm *dest, struct tm const *src)
26{ 31{
diff --git a/gl/timegm.c b/gl/timegm.c
index b47025a0..e5cf30c0 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 1994-2024 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
diff --git a/gl/unistd.c b/gl/unistd.c
index be7a8255..f3b3f7bd 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2012-2024 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
@@ -18,5 +18,5 @@
18#include <config.h> 18#include <config.h>
19 19
20#define _GL_UNISTD_INLINE _GL_EXTERN_INLINE 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 4812fdb1..b4129663 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2003-2024 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
@@ -40,6 +40,24 @@
40# undef _GL_INCLUDING_UNISTD_H 40# undef _GL_INCLUDING_UNISTD_H
41#endif 41#endif
42 42
43/* Avoid lseek bugs in FreeBSD, macOS <https://bugs.gnu.org/61386>.
44 This bug is fixed after FreeBSD 13; see <https://bugs.freebsd.org/256205>.
45 Use macOS "9999" to stand for a future fixed macOS version. */
46#if defined __FreeBSD__ && __FreeBSD__ < 14
47# undef SEEK_DATA
48# undef SEEK_HOLE
49#elif defined __APPLE__ && defined __MACH__ && defined SEEK_DATA
50# ifdef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
51# include <AvailabilityMacros.h>
52# endif
53# if (!defined MAC_OS_X_VERSION_MIN_REQUIRED \
54 || MAC_OS_X_VERSION_MIN_REQUIRED < 99990000)
55# include <sys/fcntl.h> /* It also defines the two macros. */
56# undef SEEK_DATA
57# undef SEEK_HOLE
58# endif
59#endif
60
43/* Get all possible declarations of gethostname(). */ 61/* Get all possible declarations of gethostname(). */
44#if @GNULIB_GETHOSTNAME@ && @UNISTD_H_HAVE_WINSOCK2_H@ \ 62#if @GNULIB_GETHOSTNAME@ && @UNISTD_H_HAVE_WINSOCK2_H@ \
45 && !defined _GL_INCLUDING_WINSOCK2_H 63 && !defined _GL_INCLUDING_WINSOCK2_H
@@ -51,6 +69,12 @@
51#if !defined _@GUARD_PREFIX@_UNISTD_H && !defined _GL_INCLUDING_WINSOCK2_H 69#if !defined _@GUARD_PREFIX@_UNISTD_H && !defined _GL_INCLUDING_WINSOCK2_H
52#define _@GUARD_PREFIX@_UNISTD_H 70#define _@GUARD_PREFIX@_UNISTD_H
53 71
72/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE, GNULIB_POSIXCHECK,
73 HAVE_RAW_DECL_*. */
74#if !_GL_CONFIG_H_INCLUDED
75 #error "Please include config.h first."
76#endif
77
54/* NetBSD 5.0 mis-defines NULL. Also get size_t. */ 78/* NetBSD 5.0 mis-defines NULL. Also get size_t. */
55/* But avoid namespace pollution on glibc systems. */ 79/* But avoid namespace pollution on glibc systems. */
56#ifndef __GLIBC__ 80#ifndef __GLIBC__
@@ -152,9 +176,6 @@
152# include <getopt-pfx-core.h> 176# include <getopt-pfx-core.h>
153#endif 177#endif
154 178
155#ifndef _GL_INLINE_HEADER_BEGIN
156 #error "Please include config.h first."
157#endif
158_GL_INLINE_HEADER_BEGIN 179_GL_INLINE_HEADER_BEGIN
159#ifndef _GL_UNISTD_INLINE 180#ifndef _GL_UNISTD_INLINE
160# define _GL_UNISTD_INLINE _GL_INLINE 181# define _GL_UNISTD_INLINE _GL_INLINE
@@ -541,17 +562,22 @@ _GL_CXXALIASWARN (dup2);
541 Return newfd if successful, otherwise -1 and errno set. 562 Return newfd if successful, otherwise -1 and errno set.
542 See the Linux man page at 563 See the Linux man page at
543 <https://www.kernel.org/doc/man-pages/online/pages/man2/dup3.2.html>. */ 564 <https://www.kernel.org/doc/man-pages/online/pages/man2/dup3.2.html>. */
544# if @HAVE_DUP3@ 565# if @REPLACE_DUP3@
545# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 566# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
567# undef dup3
546# define dup3 rpl_dup3 568# define dup3 rpl_dup3
547# endif 569# endif
548_GL_FUNCDECL_RPL (dup3, int, (int oldfd, int newfd, int flags)); 570_GL_FUNCDECL_RPL (dup3, int, (int oldfd, int newfd, int flags));
549_GL_CXXALIAS_RPL (dup3, int, (int oldfd, int newfd, int flags)); 571_GL_CXXALIAS_RPL (dup3, int, (int oldfd, int newfd, int flags));
550# else 572# else
573# if !@HAVE_DUP3@
551_GL_FUNCDECL_SYS (dup3, int, (int oldfd, int newfd, int flags)); 574_GL_FUNCDECL_SYS (dup3, int, (int oldfd, int newfd, int flags));
575# endif
552_GL_CXXALIAS_SYS (dup3, int, (int oldfd, int newfd, int flags)); 576_GL_CXXALIAS_SYS (dup3, int, (int oldfd, int newfd, int flags));
553# endif 577# endif
578# if __GLIBC__ >= 2
554_GL_CXXALIASWARN (dup3); 579_GL_CXXALIASWARN (dup3);
580# endif
555#elif defined GNULIB_POSIXCHECK 581#elif defined GNULIB_POSIXCHECK
556# undef dup3 582# undef dup3
557# if HAVE_RAW_DECL_DUP3 583# if HAVE_RAW_DECL_DUP3
@@ -870,7 +896,9 @@ _GL_FUNCDECL_SYS (execvpe, int,
870_GL_CXXALIAS_SYS (execvpe, int, 896_GL_CXXALIAS_SYS (execvpe, int,
871 (const char *program, char * const *argv, char * const *env)); 897 (const char *program, char * const *argv, char * const *env));
872# endif 898# endif
899# if __GLIBC__ >= 2
873_GL_CXXALIASWARN (execvpe); 900_GL_CXXALIASWARN (execvpe);
901# endif
874#elif defined GNULIB_POSIXCHECK 902#elif defined GNULIB_POSIXCHECK
875# undef execvpe 903# undef execvpe
876# if HAVE_RAW_DECL_EXECVPE 904# if HAVE_RAW_DECL_EXECVPE
@@ -925,7 +953,9 @@ _GL_FUNCDECL_SYS (faccessat, int,
925_GL_CXXALIAS_SYS (faccessat, int, 953_GL_CXXALIAS_SYS (faccessat, int,
926 (int fd, char const *file, int mode, int flag)); 954 (int fd, char const *file, int mode, int flag));
927# endif 955# endif
956# if __GLIBC__ >= 2
928_GL_CXXALIASWARN (faccessat); 957_GL_CXXALIASWARN (faccessat);
958# endif
929#elif defined GNULIB_POSIXCHECK 959#elif defined GNULIB_POSIXCHECK
930# undef faccessat 960# undef faccessat
931# if HAVE_RAW_DECL_FACCESSAT 961# if HAVE_RAW_DECL_FACCESSAT
@@ -941,23 +971,28 @@ _GL_WARN_ON_USE (faccessat, "faccessat is not portable - "
941 Return 0 if successful, otherwise -1 and errno set. 971 Return 0 if successful, otherwise -1 and errno set.
942 See the POSIX:2008 specification 972 See the POSIX:2008 specification
943 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html>. */ 973 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html>. */
944# if ! @HAVE_FCHDIR@ 974# if @REPLACE_FCHDIR@
975# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
976# undef fchdir
977# define fchdir rpl_fchdir
978# endif
979_GL_FUNCDECL_RPL (fchdir, int, (int /*fd*/));
980_GL_CXXALIAS_RPL (fchdir, int, (int /*fd*/));
981# else
982# if !@HAVE_FCHDIR@ || !@HAVE_DECL_FCHDIR@
945_GL_FUNCDECL_SYS (fchdir, int, (int /*fd*/)); 983_GL_FUNCDECL_SYS (fchdir, int, (int /*fd*/));
946 984# endif
985_GL_CXXALIAS_SYS (fchdir, int, (int /*fd*/));
986# endif
987_GL_CXXALIASWARN (fchdir);
988# if @REPLACE_FCHDIR@ || !@HAVE_FCHDIR@
947/* Gnulib internal hooks needed to maintain the fchdir metadata. */ 989/* Gnulib internal hooks needed to maintain the fchdir metadata. */
948_GL_EXTERN_C int _gl_register_fd (int fd, const char *filename) 990_GL_EXTERN_C int _gl_register_fd (int fd, const char *filename)
949 _GL_ARG_NONNULL ((2)); 991 _GL_ARG_NONNULL ((2));
950_GL_EXTERN_C void _gl_unregister_fd (int fd); 992_GL_EXTERN_C void _gl_unregister_fd (int fd);
951_GL_EXTERN_C int _gl_register_dup (int oldfd, int newfd); 993_GL_EXTERN_C int _gl_register_dup (int oldfd, int newfd);
952_GL_EXTERN_C const char *_gl_directory_name (int fd); 994_GL_EXTERN_C const char *_gl_directory_name (int fd);
953
954# else
955# if !@HAVE_DECL_FCHDIR@
956_GL_FUNCDECL_SYS (fchdir, int, (int /*fd*/));
957# endif
958# endif 995# endif
959_GL_CXXALIAS_SYS (fchdir, int, (int /*fd*/));
960_GL_CXXALIASWARN (fchdir);
961#elif defined GNULIB_POSIXCHECK 996#elif defined GNULIB_POSIXCHECK
962# undef fchdir 997# undef fchdir
963# if HAVE_RAW_DECL_FCHDIR 998# if HAVE_RAW_DECL_FCHDIR
@@ -1002,11 +1037,22 @@ _GL_WARN_ON_USE (fchownat, "fchownat is not portable - "
1002 Return 0 if successful, otherwise -1 and errno set. 1037 Return 0 if successful, otherwise -1 and errno set.
1003 See POSIX:2008 specification 1038 See POSIX:2008 specification
1004 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html>. */ 1039 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html>. */
1005# if !@HAVE_FDATASYNC@ || !@HAVE_DECL_FDATASYNC@ 1040# if @REPLACE_FDATASYNC@
1041# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1042# undef fdatasync
1043# define fdatasync rpl_fdatasync
1044# endif
1045_GL_FUNCDECL_RPL (fdatasync, int, (int fd));
1046_GL_CXXALIAS_RPL (fdatasync, int, (int fd));
1047# else
1048# if !@HAVE_FDATASYNC@|| !@HAVE_DECL_FDATASYNC@
1006_GL_FUNCDECL_SYS (fdatasync, int, (int fd)); 1049_GL_FUNCDECL_SYS (fdatasync, int, (int fd));
1007# endif 1050# endif
1008_GL_CXXALIAS_SYS (fdatasync, int, (int fd)); 1051_GL_CXXALIAS_SYS (fdatasync, int, (int fd));
1052# endif
1053# if __GLIBC__ >= 2
1009_GL_CXXALIASWARN (fdatasync); 1054_GL_CXXALIASWARN (fdatasync);
1055# endif
1010#elif defined GNULIB_POSIXCHECK 1056#elif defined GNULIB_POSIXCHECK
1011# undef fdatasync 1057# undef fdatasync
1012# if HAVE_RAW_DECL_FDATASYNC 1058# if HAVE_RAW_DECL_FDATASYNC
@@ -1053,7 +1099,9 @@ _GL_FUNCDECL_SYS (ftruncate, int, (int fd, off_t length));
1053# endif 1099# endif
1054_GL_CXXALIAS_SYS (ftruncate, int, (int fd, off_t length)); 1100_GL_CXXALIAS_SYS (ftruncate, int, (int fd, off_t length));
1055# endif 1101# endif
1102# if __GLIBC__ >= 2
1056_GL_CXXALIASWARN (ftruncate); 1103_GL_CXXALIASWARN (ftruncate);
1104# endif
1057#elif defined GNULIB_POSIXCHECK 1105#elif defined GNULIB_POSIXCHECK
1058# undef ftruncate 1106# undef ftruncate
1059# if HAVE_RAW_DECL_FTRUNCATE 1107# if HAVE_RAW_DECL_FTRUNCATE
@@ -1070,10 +1118,10 @@ _GL_WARN_ON_USE (ftruncate, "ftruncate is unportable - "
1070 or SIZE was too small. 1118 or SIZE was too small.
1071 See the POSIX:2008 specification 1119 See the POSIX:2008 specification
1072 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getcwd.html>. 1120 <https://pubs.opengroup.org/onlinepubs/9699919799/functions/getcwd.html>.
1073 Additionally, the gnulib module 'getcwd' guarantees the following GNU 1121 Additionally, the gnulib module 'getcwd' or 'getcwd-lgpl' guarantees the
1074 extension: If BUF is NULL, an array is allocated with 'malloc'; the array 1122 following GNU extension: If BUF is NULL, an array is allocated with
1075 is SIZE bytes long, unless SIZE == 0, in which case it is as big as 1123 'malloc'; the array is SIZE bytes long, unless SIZE == 0, in which case
1076 necessary. */ 1124 it is as big as necessary. */
1077# if @REPLACE_GETCWD@ 1125# if @REPLACE_GETCWD@
1078# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1126# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1079# define getcwd rpl_getcwd 1127# define getcwd rpl_getcwd
@@ -1185,11 +1233,22 @@ _GL_WARN_ON_USE (getdtablesize, "getdtablesize is unportable - "
1185 1233
1186#if @GNULIB_GETENTROPY@ 1234#if @GNULIB_GETENTROPY@
1187/* Fill a buffer with random bytes. */ 1235/* Fill a buffer with random bytes. */
1188# if !@HAVE_GETENTROPY@ 1236# if @REPLACE_GETENTROPY@
1237# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1238# undef getentropy
1239# define getentropy rpl_getentropy
1240# endif
1241_GL_FUNCDECL_RPL (getentropy, int, (void *buffer, size_t length));
1242_GL_CXXALIAS_RPL (getentropy, int, (void *buffer, size_t length));
1243# else
1244# if !@HAVE_GETENTROPY@
1189_GL_FUNCDECL_SYS (getentropy, int, (void *buffer, size_t length)); 1245_GL_FUNCDECL_SYS (getentropy, int, (void *buffer, size_t length));
1190# endif 1246# endif
1191_GL_CXXALIAS_SYS (getentropy, int, (void *buffer, size_t length)); 1247_GL_CXXALIAS_SYS (getentropy, int, (void *buffer, size_t length));
1248# endif
1249# if __GLIBC__ >= 2
1192_GL_CXXALIASWARN (getentropy); 1250_GL_CXXALIASWARN (getentropy);
1251# endif
1193#elif defined GNULIB_POSIXCHECK 1252#elif defined GNULIB_POSIXCHECK
1194# undef getentropy 1253# undef getentropy
1195# if HAVE_RAW_DECL_GETENTROPY 1254# if HAVE_RAW_DECL_GETENTROPY
@@ -1323,7 +1382,9 @@ _GL_FUNCDECL_SYS (getlogin_r, int, (char *name, size_t size)
1323 int size. */ 1382 int size. */
1324_GL_CXXALIAS_SYS_CAST (getlogin_r, int, (char *name, size_t size)); 1383_GL_CXXALIAS_SYS_CAST (getlogin_r, int, (char *name, size_t size));
1325# endif 1384# endif
1385# if __GLIBC__ >= 2
1326_GL_CXXALIASWARN (getlogin_r); 1386_GL_CXXALIASWARN (getlogin_r);
1387# endif
1327#elif defined GNULIB_POSIXCHECK 1388#elif defined GNULIB_POSIXCHECK
1328# undef getlogin_r 1389# undef getlogin_r
1329# if HAVE_RAW_DECL_GETLOGIN_R 1390# if HAVE_RAW_DECL_GETLOGIN_R
@@ -1661,7 +1722,9 @@ _GL_CXXALIAS_SYS (linkat, int,
1661 (int fd1, const char *path1, int fd2, const char *path2, 1722 (int fd1, const char *path1, int fd2, const char *path2,
1662 int flag)); 1723 int flag));
1663# endif 1724# endif
1725# if __GLIBC__ >= 2
1664_GL_CXXALIASWARN (linkat); 1726_GL_CXXALIASWARN (linkat);
1727# endif
1665#elif defined GNULIB_POSIXCHECK 1728#elif defined GNULIB_POSIXCHECK
1666# undef linkat 1729# undef linkat
1667# if HAVE_RAW_DECL_LINKAT 1730# if HAVE_RAW_DECL_LINKAT
@@ -1742,8 +1805,9 @@ _GL_WARN_ON_USE (pipe, "pipe is unportable - "
1742 Return 0 upon success, or -1 with errno set upon failure. 1805 Return 0 upon success, or -1 with errno set upon failure.
1743 See also the Linux man page at 1806 See also the Linux man page at
1744 <https://www.kernel.org/doc/man-pages/online/pages/man2/pipe2.2.html>. */ 1807 <https://www.kernel.org/doc/man-pages/online/pages/man2/pipe2.2.html>. */
1745# if @HAVE_PIPE2@ 1808# if @REPLACE_PIPE2@
1746# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 1809# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1810# undef pipe2
1747# define pipe2 rpl_pipe2 1811# define pipe2 rpl_pipe2
1748# endif 1812# endif
1749_GL_FUNCDECL_RPL (pipe2, int, (int fd[2], int flags) _GL_ARG_NONNULL ((1))); 1813_GL_FUNCDECL_RPL (pipe2, int, (int fd[2], int flags) _GL_ARG_NONNULL ((1)));
@@ -1752,7 +1816,9 @@ _GL_CXXALIAS_RPL (pipe2, int, (int fd[2], int flags));
1752_GL_FUNCDECL_SYS (pipe2, int, (int fd[2], int flags) _GL_ARG_NONNULL ((1))); 1816_GL_FUNCDECL_SYS (pipe2, int, (int fd[2], int flags) _GL_ARG_NONNULL ((1)));
1753_GL_CXXALIAS_SYS (pipe2, int, (int fd[2], int flags)); 1817_GL_CXXALIAS_SYS (pipe2, int, (int fd[2], int flags));
1754# endif 1818# endif
1819# if __GLIBC__ >= 2
1755_GL_CXXALIASWARN (pipe2); 1820_GL_CXXALIASWARN (pipe2);
1821# endif
1756#elif defined GNULIB_POSIXCHECK 1822#elif defined GNULIB_POSIXCHECK
1757# undef pipe2 1823# undef pipe2
1758# if HAVE_RAW_DECL_PIPE2 1824# if HAVE_RAW_DECL_PIPE2
@@ -1787,7 +1853,9 @@ _GL_FUNCDECL_SYS (pread, ssize_t,
1787_GL_CXXALIAS_SYS (pread, ssize_t, 1853_GL_CXXALIAS_SYS (pread, ssize_t,
1788 (int fd, void *buf, size_t bufsize, off_t offset)); 1854 (int fd, void *buf, size_t bufsize, off_t offset));
1789# endif 1855# endif
1856# if __GLIBC__ >= 2
1790_GL_CXXALIASWARN (pread); 1857_GL_CXXALIASWARN (pread);
1858# endif
1791#elif defined GNULIB_POSIXCHECK 1859#elif defined GNULIB_POSIXCHECK
1792# undef pread 1860# undef pread
1793# if HAVE_RAW_DECL_PREAD 1861# if HAVE_RAW_DECL_PREAD
@@ -1822,7 +1890,9 @@ _GL_FUNCDECL_SYS (pwrite, ssize_t,
1822_GL_CXXALIAS_SYS (pwrite, ssize_t, 1890_GL_CXXALIAS_SYS (pwrite, ssize_t,
1823 (int fd, const void *buf, size_t bufsize, off_t offset)); 1891 (int fd, const void *buf, size_t bufsize, off_t offset));
1824# endif 1892# endif
1893# if __GLIBC__ >= 2
1825_GL_CXXALIASWARN (pwrite); 1894_GL_CXXALIASWARN (pwrite);
1895# endif
1826#elif defined GNULIB_POSIXCHECK 1896#elif defined GNULIB_POSIXCHECK
1827# undef pwrite 1897# undef pwrite
1828# if HAVE_RAW_DECL_PWRITE 1898# if HAVE_RAW_DECL_PWRITE
@@ -1936,7 +2006,9 @@ _GL_CXXALIAS_SYS (readlinkat, ssize_t,
1936 (int fd, char const *restrict file, 2006 (int fd, char const *restrict file,
1937 char *restrict buf, size_t len)); 2007 char *restrict buf, size_t len));
1938# endif 2008# endif
2009# if __GLIBC__ >= 2
1939_GL_CXXALIASWARN (readlinkat); 2010_GL_CXXALIASWARN (readlinkat);
2011# endif
1940#elif defined GNULIB_POSIXCHECK 2012#elif defined GNULIB_POSIXCHECK
1941# undef readlinkat 2013# undef readlinkat
1942# if HAVE_RAW_DECL_READLINKAT 2014# if HAVE_RAW_DECL_READLINKAT
@@ -1996,15 +2068,27 @@ _GL_CXXALIASWARN (rmdir);
1996 2068
1997 Platforms with no ability to set the hostname return -1 and set 2069 Platforms with no ability to set the hostname return -1 and set
1998 errno = ENOSYS. */ 2070 errno = ENOSYS. */
1999# if !@HAVE_SETHOSTNAME@ || !@HAVE_DECL_SETHOSTNAME@ 2071# if @REPLACE_SETHOSTNAME@
2072# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
2073# undef sethostname
2074# define sethostname rpl_sethostname
2075# endif
2076_GL_FUNCDECL_RPL (sethostname, int, (const char *name, size_t len)
2077 _GL_ARG_NONNULL ((1)));
2078_GL_CXXALIAS_RPL (sethostname, int, (const char *name, size_t len));
2079# else
2080# if !@HAVE_SETHOSTNAME@ || !@HAVE_DECL_SETHOSTNAME@
2000_GL_FUNCDECL_SYS (sethostname, int, (const char *name, size_t len) 2081_GL_FUNCDECL_SYS (sethostname, int, (const char *name, size_t len)
2001 _GL_ARG_NONNULL ((1))); 2082 _GL_ARG_NONNULL ((1)));
2002# endif 2083# endif
2003/* Need to cast, because on Solaris 11 2011-10, Mac OS X 10.5, IRIX 6.5 2084/* Need to cast, because on Solaris 11 2011-10, Mac OS X 10.5, IRIX 6.5
2004 and FreeBSD 6.4 the second parameter is int. On Solaris 11 2085 and FreeBSD 6.4 the second parameter is int. On Solaris 11
2005 2011-10, the first parameter is not const. */ 2086 2011-10, the first parameter is not const. */
2006_GL_CXXALIAS_SYS_CAST (sethostname, int, (const char *name, size_t len)); 2087_GL_CXXALIAS_SYS_CAST (sethostname, int, (const char *name, size_t len));
2088# endif
2089# if __GLIBC__ >= 2
2007_GL_CXXALIASWARN (sethostname); 2090_GL_CXXALIASWARN (sethostname);
2091# endif
2008#elif defined GNULIB_POSIXCHECK 2092#elif defined GNULIB_POSIXCHECK
2009# undef sethostname 2093# undef sethostname
2010# if HAVE_RAW_DECL_SETHOSTNAME 2094# if HAVE_RAW_DECL_SETHOSTNAME
@@ -2113,7 +2197,9 @@ _GL_FUNCDECL_SYS (symlinkat, int,
2113_GL_CXXALIAS_SYS (symlinkat, int, 2197_GL_CXXALIAS_SYS (symlinkat, int,
2114 (char const *contents, int fd, char const *file)); 2198 (char const *contents, int fd, char const *file));
2115# endif 2199# endif
2200# if __GLIBC__ >= 2
2116_GL_CXXALIASWARN (symlinkat); 2201_GL_CXXALIASWARN (symlinkat);
2202# endif
2117#elif defined GNULIB_POSIXCHECK 2203#elif defined GNULIB_POSIXCHECK
2118# undef symlinkat 2204# undef symlinkat
2119# if HAVE_RAW_DECL_SYMLINKAT 2205# if HAVE_RAW_DECL_SYMLINKAT
@@ -2143,7 +2229,9 @@ _GL_FUNCDECL_SYS (truncate, int, (const char *filename, off_t length)
2143# endif 2229# endif
2144_GL_CXXALIAS_SYS (truncate, int, (const char *filename, off_t length)); 2230_GL_CXXALIAS_SYS (truncate, int, (const char *filename, off_t length));
2145# endif 2231# endif
2232# if __GLIBC__ >= 2
2146_GL_CXXALIASWARN (truncate); 2233_GL_CXXALIASWARN (truncate);
2234# endif
2147#elif defined GNULIB_POSIXCHECK 2235#elif defined GNULIB_POSIXCHECK
2148# undef truncate 2236# undef truncate
2149# if HAVE_RAW_DECL_TRUNCATE 2237# if HAVE_RAW_DECL_TRUNCATE
@@ -2173,7 +2261,9 @@ _GL_FUNCDECL_SYS (ttyname_r, int,
2173_GL_CXXALIAS_SYS (ttyname_r, int, 2261_GL_CXXALIAS_SYS (ttyname_r, int,
2174 (int fd, char *buf, size_t buflen)); 2262 (int fd, char *buf, size_t buflen));
2175# endif 2263# endif
2264# if __GLIBC__ >= 2
2176_GL_CXXALIASWARN (ttyname_r); 2265_GL_CXXALIASWARN (ttyname_r);
2266# endif
2177#elif defined GNULIB_POSIXCHECK 2267#elif defined GNULIB_POSIXCHECK
2178# undef ttyname_r 2268# undef ttyname_r
2179# if HAVE_RAW_DECL_TTYNAME_R 2269# if HAVE_RAW_DECL_TTYNAME_R
diff --git a/gl/unlocked-io.h b/gl/unlocked-io.h
index fdef624a..0cd9bbf3 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2001-2004, 2009-2024 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
@@ -31,6 +31,11 @@
31 the *_unlocked functions directly. On hosts that lack those 31 the *_unlocked functions directly. On hosts that lack those
32 functions, invoke the non-thread-safe versions instead. */ 32 functions, invoke the non-thread-safe versions instead. */
33 33
34/* This file uses HAVE_DECL_*_UNLOCKED. */
35# if !_GL_CONFIG_H_INCLUDED
36# error "Please include config.h first."
37# endif
38
34# include <stdio.h> 39# include <stdio.h>
35 40
36# if HAVE_DECL_CLEARERR_UNLOCKED || defined clearerr_unlocked 41# if HAVE_DECL_CLEARERR_UNLOCKED || defined clearerr_unlocked
@@ -96,7 +101,7 @@
96# define fwrite_unlocked(w,x,y,z) fwrite (w,x,y,z) 101# define fwrite_unlocked(w,x,y,z) fwrite (w,x,y,z)
97# endif 102# endif
98 103
99# if HAVE_DECL_GETC_UNLOCKED || defined get_unlocked 104# if HAVE_DECL_GETC_UNLOCKED || defined getc_unlocked
100# undef getc 105# undef getc
101# define getc(x) getc_unlocked (x) 106# define getc(x) getc_unlocked (x)
102# else 107# else
diff --git a/gl/unsetenv.c b/gl/unsetenv.c
index e5489490..d8ada2aa 100644
--- a/gl/unsetenv.c
+++ b/gl/unsetenv.c
@@ -1,4 +1,4 @@
1/* Copyright (C) 1992, 1995-2002, 2005-2023 Free Software Foundation, Inc. 1/* Copyright (C) 1992, 1995-2002, 2005-2024 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
diff --git a/gl/vasnprintf.c b/gl/vasnprintf.c
index 277c39e3..de204458 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2002-2024 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
@@ -83,9 +83,9 @@
83#include <stdio.h> /* snprintf(), sprintf() */ 83#include <stdio.h> /* snprintf(), sprintf() */
84#include <stdlib.h> /* abort(), malloc(), realloc(), free() */ 84#include <stdlib.h> /* abort(), malloc(), realloc(), free() */
85#include <string.h> /* memcpy(), strlen() */ 85#include <string.h> /* memcpy(), strlen() */
86#include <wchar.h> /* mbstate_t, mbrtowc(), mbrlen(), wcrtomb() */ 86#include <wchar.h> /* mbstate_t, mbrtowc(), mbrlen(), wcrtomb(), mbszero() */
87#include <errno.h> /* errno */ 87#include <errno.h> /* errno */
88#include <limits.h> /* CHAR_BIT */ 88#include <limits.h> /* CHAR_BIT, INT_WIDTH, LONG_WIDTH */
89#include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */ 89#include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */
90#if HAVE_NL_LANGINFO 90#if HAVE_NL_LANGINFO
91# include <langinfo.h> 91# include <langinfo.h>
@@ -103,29 +103,29 @@
103 103
104#include "attribute.h" 104#include "attribute.h"
105 105
106#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL 106#if NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
107# include <math.h> 107# include <math.h>
108# include "float+.h" 108# include "float+.h"
109#endif 109#endif
110 110
111#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL 111#if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE
112# include <math.h> 112# include <math.h>
113# include "isnand-nolibm.h" 113# include "isnand-nolibm.h"
114#endif 114#endif
115 115
116#if (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE) && !defined IN_LIBINTL 116#if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
117# include <math.h> 117# include <math.h>
118# include "isnanl-nolibm.h" 118# include "isnanl-nolibm.h"
119# include "fpucw.h" 119# include "fpucw.h"
120#endif 120#endif
121 121
122#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL 122#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_DOUBLE
123# include <math.h> 123# include <math.h>
124# include "isnand-nolibm.h" 124# include "isnand-nolibm.h"
125# include "printf-frexp.h" 125# include "printf-frexp.h"
126#endif 126#endif
127 127
128#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL 128#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
129# include <math.h> 129# include <math.h>
130# include "isnanl-nolibm.h" 130# include "isnanl-nolibm.h"
131# include "printf-frexpl.h" 131# include "printf-frexpl.h"
@@ -138,8 +138,6 @@
138# define VASNPRINTF vasnwprintf 138# define VASNPRINTF vasnwprintf
139# define FCHAR_T wchar_t 139# define FCHAR_T wchar_t
140# define DCHAR_T wchar_t 140# define DCHAR_T wchar_t
141# define TCHAR_T wchar_t
142# define DCHAR_IS_TCHAR 1
143# define DIRECTIVE wchar_t_directive 141# define DIRECTIVE wchar_t_directive
144# define DIRECTIVES wchar_t_directives 142# define DIRECTIVES wchar_t_directives
145# define PRINTF_PARSE wprintf_parse 143# define PRINTF_PARSE wprintf_parse
@@ -159,24 +157,32 @@
159# endif 157# endif
160#endif 158#endif
161#if WIDE_CHAR_VERSION 159#if WIDE_CHAR_VERSION
162 /* TCHAR_T is wchar_t. */ 160 /* DCHAR_T is wchar_t. */
163# define USE_SNPRINTF 1 161# if HAVE_DECL__SNWPRINTF || (HAVE_SWPRINTF && HAVE_WORKING_SWPRINTF)
164# if HAVE_DECL__SNWPRINTF 162# define TCHAR_T wchar_t
165 /* On Windows, the function swprintf() has a different signature than 163# define DCHAR_IS_TCHAR 1
166 on Unix; we use the function _snwprintf() or - on mingw - snwprintf() 164# define USE_SNPRINTF 1
167 instead. The mingw function snwprintf() has fewer bugs than the 165# if HAVE_DECL__SNWPRINTF
168 MSVCRT function _snwprintf(), so prefer that. */ 166 /* On Windows, the function swprintf() has a different signature than
169# if defined __MINGW32__ 167 on Unix; we use the function _snwprintf() or - on mingw - snwprintf()
170# define SNPRINTF snwprintf 168 instead. The mingw function snwprintf() has fewer bugs than the
169 MSVCRT function _snwprintf(), so prefer that. */
170# if defined __MINGW32__
171# define SNPRINTF snwprintf
172# else
173# define SNPRINTF _snwprintf
174# define USE_MSVC__SNPRINTF 1
175# endif
171# else 176# else
172# define SNPRINTF _snwprintf 177 /* Unix. */
173# define USE_MSVC__SNPRINTF 1 178# define SNPRINTF swprintf
174# endif 179# endif
175# else 180# else
176 /* Unix. */ 181 /* Old platforms such as NetBSD 3.0, OpenBSD 3.8, HP-UX 11.00, IRIX 6.5. */
177# define SNPRINTF swprintf 182# define TCHAR_T char
178# endif 183# endif
179#else 184#endif
185#if !WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR
180 /* TCHAR_T is char. */ 186 /* TCHAR_T is char. */
181 /* Use snprintf if it exists under the name 'snprintf' or '_snprintf'. 187 /* Use snprintf if it exists under the name 'snprintf' or '_snprintf'.
182 But don't use it on BeOS, since BeOS snprintf produces no output if the 188 But don't use it on BeOS, since BeOS snprintf produces no output if the
@@ -241,7 +247,7 @@ local_strnlen (const char *string, size_t maxlen)
241# endif 247# endif
242#endif 248#endif
243 249
244#if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && !WIDE_CHAR_VERSION && DCHAR_IS_TCHAR)) && HAVE_WCHAR_T 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
245# if HAVE_WCSLEN 251# if HAVE_WCSLEN
246# define local_wcslen wcslen 252# define local_wcslen wcslen
247# else 253# else
@@ -264,8 +270,8 @@ local_wcslen (const wchar_t *s)
264# endif 270# endif
265#endif 271#endif
266 272
267#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && HAVE_WCHAR_T && WIDE_CHAR_VERSION 273#if (!USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && HAVE_WCHAR_T && WIDE_CHAR_VERSION
268# if HAVE_WCSNLEN 274# if HAVE_WCSNLEN && HAVE_DECL_WCSNLEN
269# define local_wcsnlen wcsnlen 275# define local_wcsnlen wcsnlen
270# else 276# else
271# ifndef local_wcsnlen_defined 277# ifndef local_wcsnlen_defined
@@ -283,12 +289,12 @@ local_wcsnlen (const wchar_t *s, size_t maxlen)
283# endif 289# endif
284#endif 290#endif
285 291
286#if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL) || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T) || (ENABLE_WCHAR_FALLBACK && HAVE_WINT_T)) && !WIDE_CHAR_VERSION 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
287# if ENABLE_WCHAR_FALLBACK 293# if ENABLE_WCHAR_FALLBACK
288static size_t 294static size_t
289wctomb_fallback (char *s, wchar_t wc) 295wctomb_fallback (char *s, wchar_t wc)
290{ 296{
291 static char hex[16] = "0123456789ABCDEF"; 297 static char const hex[16] = "0123456789ABCDEF";
292 298
293 s[0] = '\\'; 299 s[0] = '\\';
294 if (sizeof (wchar_t) > 2 && wc > 0xffff) 300 if (sizeof (wchar_t) > 2 && wc > 0xffff)
@@ -351,7 +357,7 @@ local_wctomb (char *s, wchar_t wc)
351# endif 357# endif
352#endif 358#endif
353 359
354#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL 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)
355/* Determine the decimal-point character according to the current locale. */ 361/* Determine the decimal-point character according to the current locale. */
356# ifndef decimal_point_char_defined 362# ifndef decimal_point_char_defined
357# define decimal_point_char_defined 1 363# define decimal_point_char_defined 1
@@ -378,7 +384,7 @@ decimal_point_char (void)
378# endif 384# endif
379#endif 385#endif
380 386
381#if NEED_PRINTF_INFINITE_DOUBLE && !NEED_PRINTF_DOUBLE && !defined IN_LIBINTL 387#if NEED_PRINTF_INFINITE_DOUBLE && !NEED_PRINTF_DOUBLE
382 388
383/* Equivalent to !isfinite(x) || x == 0, but does not require libm. */ 389/* Equivalent to !isfinite(x) || x == 0, but does not require libm. */
384static int 390static int
@@ -389,7 +395,7 @@ is_infinite_or_zero (double x)
389 395
390#endif 396#endif
391 397
392#if NEED_PRINTF_INFINITE_LONG_DOUBLE && !NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL 398#if NEED_PRINTF_INFINITE_LONG_DOUBLE && !NEED_PRINTF_LONG_DOUBLE
393 399
394/* Equivalent to !isfinite(x) || x == 0, but does not require libm. */ 400/* Equivalent to !isfinite(x) || x == 0, but does not require libm. */
395static int 401static int
@@ -400,7 +406,7 @@ is_infinite_or_zerol (long double x)
400 406
401#endif 407#endif
402 408
403#if (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL 409#if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE
404 410
405/* Converting 'long double' to decimal without rare rounding bugs requires 411/* Converting 'long double' to decimal without rare rounding bugs requires
406 real bignums. We use the naming conventions of GNU gmp, but vastly simpler 412 real bignums. We use the naming conventions of GNU gmp, but vastly simpler
@@ -921,6 +927,14 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
921 return roomptr; 927 return roomptr;
922} 928}
923 929
930/* Avoid pointless GCC warning "argument 1 value '18446744073709551615' exceeds
931 maximum object size 9223372036854775807", triggered by the use of xsum as
932 argument of malloc. */
933# if __GNUC__ >= 7
934# pragma GCC diagnostic push
935# pragma GCC diagnostic ignored "-Walloc-size-larger-than="
936# endif
937
924/* Convert a bignum a >= 0, multiplied with 10^extra_zeroes, to decimal 938/* Convert a bignum a >= 0, multiplied with 10^extra_zeroes, to decimal
925 representation. 939 representation.
926 Destroys the contents of a. 940 Destroys the contents of a.
@@ -977,6 +991,10 @@ convert_to_decimal (mpn_t a, size_t extra_zeroes)
977 return c_ptr; 991 return c_ptr;
978} 992}
979 993
994# if __GNUC__ >= 7
995# pragma GCC diagnostic pop
996# endif
997
980# if NEED_PRINTF_LONG_DOUBLE 998# if NEED_PRINTF_LONG_DOUBLE
981 999
982/* Assuming x is finite and >= 0: 1000/* Assuming x is finite and >= 0:
@@ -1171,8 +1189,6 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
1171 void *z_memory; 1189 void *z_memory;
1172 char *digits; 1190 char *digits;
1173 1191
1174 if (memory == NULL)
1175 return NULL;
1176 /* x = 2^e * m, hence 1192 /* x = 2^e * m, hence
1177 y = round (2^e * 10^n * m) = round (2^(e+n) * 5^n * m) 1193 y = round (2^e * 10^n * m) = round (2^(e+n) * 5^n * m)
1178 = round (2^s * 5^n * m). */ 1194 = round (2^s * 5^n * m). */
@@ -1380,10 +1396,13 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
1380static char * 1396static char *
1381scale10_round_decimal_long_double (long double x, int n) 1397scale10_round_decimal_long_double (long double x, int n)
1382{ 1398{
1383 int e IF_LINT(= 0); 1399 int e;
1384 mpn_t m; 1400 mpn_t m;
1385 void *memory = decode_long_double (x, &e, &m); 1401 void *memory = decode_long_double (x, &e, &m);
1386 return scale10_round_decimal_decoded (e, m, memory, n); 1402 if (memory != NULL)
1403 return scale10_round_decimal_decoded (e, m, memory, n);
1404 else
1405 return NULL;
1387} 1406}
1388 1407
1389# endif 1408# endif
@@ -1398,10 +1417,13 @@ scale10_round_decimal_long_double (long double x, int n)
1398static char * 1417static char *
1399scale10_round_decimal_double (double x, int n) 1418scale10_round_decimal_double (double x, int n)
1400{ 1419{
1401 int e IF_LINT(= 0); 1420 int e;
1402 mpn_t m; 1421 mpn_t m;
1403 void *memory = decode_double (x, &e, &m); 1422 void *memory = decode_double (x, &e, &m);
1404 return scale10_round_decimal_decoded (e, m, memory, n); 1423 if (memory != NULL)
1424 return scale10_round_decimal_decoded (e, m, memory, n);
1425 else
1426 return NULL;
1405} 1427}
1406 1428
1407# endif 1429# endif
@@ -1604,7 +1626,7 @@ is_borderline (const char *digits, size_t precision)
1604 1626
1605#endif 1627#endif
1606 1628
1607#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF 1629#if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
1608 1630
1609/* Use a different function name, to make it possible that the 'wchar_t' 1631/* Use a different function name, to make it possible that the 'wchar_t'
1610 parametrization and the 'char' parametrization get compiled in the same 1632 parametrization and the 'char' parametrization get compiled in the same
@@ -1627,24 +1649,156 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
1627 switch (conversion) 1649 switch (conversion)
1628 { 1650 {
1629 case 'd': case 'i': case 'u': 1651 case 'd': case 'i': case 'u':
1630 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) 1652 switch (type)
1631 tmp_length = 1653 {
1632 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT 1654 default:
1633 * 0.30103 /* binary -> decimal */ 1655 tmp_length =
1634 ) 1656 (unsigned int) (sizeof (unsigned int) * CHAR_BIT
1635 + 1; /* turn floor into ceil */ 1657 * 0.30103 /* binary -> decimal */
1636 else if (type == TYPE_LONGINT || type == TYPE_ULONGINT) 1658 )
1637 tmp_length = 1659 + 1; /* turn floor into ceil */
1638 (unsigned int) (sizeof (unsigned long) * CHAR_BIT 1660 break;
1639 * 0.30103 /* binary -> decimal */ 1661 case TYPE_LONGINT:
1640 ) 1662 tmp_length =
1641 + 1; /* turn floor into ceil */ 1663 (unsigned int) (sizeof (long int) * CHAR_BIT
1642 else 1664 * 0.30103 /* binary -> decimal */
1643 tmp_length = 1665 )
1644 (unsigned int) (sizeof (unsigned int) * CHAR_BIT 1666 + 1; /* turn floor into ceil */
1645 * 0.30103 /* binary -> decimal */ 1667 break;
1646 ) 1668 case TYPE_ULONGINT:
1647 + 1; /* turn floor into ceil */ 1669 tmp_length =
1670 (unsigned int) (sizeof (unsigned long int) * CHAR_BIT
1671 * 0.30103 /* binary -> decimal */
1672 )
1673 + 1; /* turn floor into ceil */
1674 break;
1675 case TYPE_LONGLONGINT:
1676 tmp_length =
1677 (unsigned int) (sizeof (long long int) * CHAR_BIT
1678 * 0.30103 /* binary -> decimal */
1679 )
1680 + 1; /* turn floor into ceil */
1681 break;
1682 case TYPE_ULONGLONGINT:
1683 tmp_length =
1684 (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT
1685 * 0.30103 /* binary -> decimal */
1686 )
1687 + 1; /* turn floor into ceil */
1688 break;
1689 case TYPE_INT8_T:
1690 tmp_length =
1691 (unsigned int) (sizeof (int8_t) * CHAR_BIT
1692 * 0.30103 /* binary -> decimal */
1693 )
1694 + 1; /* turn floor into ceil */
1695 break;
1696 case TYPE_UINT8_T:
1697 tmp_length =
1698 (unsigned int) (sizeof (uint8_t) * CHAR_BIT
1699 * 0.30103 /* binary -> decimal */
1700 )
1701 + 1; /* turn floor into ceil */
1702 break;
1703 case TYPE_INT16_T:
1704 tmp_length =
1705 (unsigned int) (sizeof (int16_t) * CHAR_BIT
1706 * 0.30103 /* binary -> decimal */
1707 )
1708 + 1; /* turn floor into ceil */
1709 break;
1710 case TYPE_UINT16_T:
1711 tmp_length =
1712 (unsigned int) (sizeof (uint16_t) * CHAR_BIT
1713 * 0.30103 /* binary -> decimal */
1714 )
1715 + 1; /* turn floor into ceil */
1716 break;
1717 case TYPE_INT32_T:
1718 tmp_length =
1719 (unsigned int) (sizeof (int32_t) * CHAR_BIT
1720 * 0.30103 /* binary -> decimal */
1721 )
1722 + 1; /* turn floor into ceil */
1723 break;
1724 case TYPE_UINT32_T:
1725 tmp_length =
1726 (unsigned int) (sizeof (uint32_t) * CHAR_BIT
1727 * 0.30103 /* binary -> decimal */
1728 )
1729 + 1; /* turn floor into ceil */
1730 break;
1731 case TYPE_INT64_T:
1732 tmp_length =
1733 (unsigned int) (sizeof (int64_t) * CHAR_BIT
1734 * 0.30103 /* binary -> decimal */
1735 )
1736 + 1; /* turn floor into ceil */
1737 break;
1738 case TYPE_UINT64_T:
1739 tmp_length =
1740 (unsigned int) (sizeof (uint64_t) * CHAR_BIT
1741 * 0.30103 /* binary -> decimal */
1742 )
1743 + 1; /* turn floor into ceil */
1744 break;
1745 case TYPE_INT_FAST8_T:
1746 tmp_length =
1747 (unsigned int) (sizeof (int_fast8_t) * CHAR_BIT
1748 * 0.30103 /* binary -> decimal */
1749 )
1750 + 1; /* turn floor into ceil */
1751 break;
1752 case TYPE_UINT_FAST8_T:
1753 tmp_length =
1754 (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT
1755 * 0.30103 /* binary -> decimal */
1756 )
1757 + 1; /* turn floor into ceil */
1758 break;
1759 case TYPE_INT_FAST16_T:
1760 tmp_length =
1761 (unsigned int) (sizeof (int_fast16_t) * CHAR_BIT
1762 * 0.30103 /* binary -> decimal */
1763 )
1764 + 1; /* turn floor into ceil */
1765 break;
1766 case TYPE_UINT_FAST16_T:
1767 tmp_length =
1768 (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT
1769 * 0.30103 /* binary -> decimal */
1770 )
1771 + 1; /* turn floor into ceil */
1772 break;
1773 case TYPE_INT_FAST32_T:
1774 tmp_length =
1775 (unsigned int) (sizeof (int_fast32_t) * CHAR_BIT
1776 * 0.30103 /* binary -> decimal */
1777 )
1778 + 1; /* turn floor into ceil */
1779 break;
1780 case TYPE_UINT_FAST32_T:
1781 tmp_length =
1782 (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT
1783 * 0.30103 /* binary -> decimal */
1784 )
1785 + 1; /* turn floor into ceil */
1786 break;
1787 case TYPE_INT_FAST64_T:
1788 tmp_length =
1789 (unsigned int) (sizeof (int_fast64_t) * CHAR_BIT
1790 * 0.30103 /* binary -> decimal */
1791 )
1792 + 1; /* turn floor into ceil */
1793 break;
1794 case TYPE_UINT_FAST64_T:
1795 tmp_length =
1796 (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT
1797 * 0.30103 /* binary -> decimal */
1798 )
1799 + 1; /* turn floor into ceil */
1800 break;
1801 }
1648 if (tmp_length < precision) 1802 if (tmp_length < precision)
1649 tmp_length = precision; 1803 tmp_length = precision;
1650 /* Multiply by 2, as an estimate for FLAG_GROUP. */ 1804 /* Multiply by 2, as an estimate for FLAG_GROUP. */
@@ -1653,25 +1807,156 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
1653 tmp_length = xsum (tmp_length, 1); 1807 tmp_length = xsum (tmp_length, 1);
1654 break; 1808 break;
1655 1809
1810 case 'b':
1811 #if SUPPORT_GNU_PRINTF_DIRECTIVES \
1812 || (__GLIBC__ + (__GLIBC_MINOR__ >= 35) > 2)
1813 case 'B':
1814 #endif
1815 switch (type)
1816 {
1817 default:
1818 tmp_length =
1819 (unsigned int) (sizeof (unsigned int) * CHAR_BIT)
1820 + 1; /* turn floor into ceil */
1821 break;
1822 case TYPE_ULONGINT:
1823 tmp_length =
1824 (unsigned int) (sizeof (unsigned long int) * CHAR_BIT)
1825 + 1; /* turn floor into ceil */
1826 break;
1827 case TYPE_ULONGLONGINT:
1828 tmp_length =
1829 (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT)
1830 + 1; /* turn floor into ceil */
1831 break;
1832 case TYPE_UINT8_T:
1833 tmp_length =
1834 (unsigned int) (sizeof (uint8_t) * CHAR_BIT)
1835 + 1; /* turn floor into ceil */
1836 break;
1837 case TYPE_UINT16_T:
1838 tmp_length =
1839 (unsigned int) (sizeof (uint16_t) * CHAR_BIT)
1840 + 1; /* turn floor into ceil */
1841 break;
1842 case TYPE_UINT32_T:
1843 tmp_length =
1844 (unsigned int) (sizeof (uint32_t) * CHAR_BIT)
1845 + 1; /* turn floor into ceil */
1846 break;
1847 case TYPE_UINT64_T:
1848 tmp_length =
1849 (unsigned int) (sizeof (uint64_t) * CHAR_BIT)
1850 + 1; /* turn floor into ceil */
1851 break;
1852 case TYPE_UINT_FAST8_T:
1853 tmp_length =
1854 (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT)
1855 + 1; /* turn floor into ceil */
1856 break;
1857 case TYPE_UINT_FAST16_T:
1858 tmp_length =
1859 (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT)
1860 + 1; /* turn floor into ceil */
1861 break;
1862 case TYPE_UINT_FAST32_T:
1863 tmp_length =
1864 (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT)
1865 + 1; /* turn floor into ceil */
1866 break;
1867 case TYPE_UINT_FAST64_T:
1868 tmp_length =
1869 (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT)
1870 + 1; /* turn floor into ceil */
1871 break;
1872 }
1873 if (tmp_length < precision)
1874 tmp_length = precision;
1875 /* Add 2, to account for a prefix from the alternate form. */
1876 tmp_length = xsum (tmp_length, 2);
1877 break;
1878
1656 case 'o': 1879 case 'o':
1657 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) 1880 switch (type)
1658 tmp_length = 1881 {
1659 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT 1882 default:
1660 * 0.333334 /* binary -> octal */ 1883 tmp_length =
1661 ) 1884 (unsigned int) (sizeof (unsigned int) * CHAR_BIT
1662 + 1; /* turn floor into ceil */ 1885 * 0.333334 /* binary -> octal */
1663 else if (type == TYPE_LONGINT || type == TYPE_ULONGINT) 1886 )
1664 tmp_length = 1887 + 1; /* turn floor into ceil */
1665 (unsigned int) (sizeof (unsigned long) * CHAR_BIT 1888 break;
1666 * 0.333334 /* binary -> octal */ 1889 case TYPE_ULONGINT:
1667 ) 1890 tmp_length =
1668 + 1; /* turn floor into ceil */ 1891 (unsigned int) (sizeof (unsigned long int) * CHAR_BIT
1669 else 1892 * 0.333334 /* binary -> octal */
1670 tmp_length = 1893 )
1671 (unsigned int) (sizeof (unsigned int) * CHAR_BIT 1894 + 1; /* turn floor into ceil */
1672 * 0.333334 /* binary -> octal */ 1895 break;
1673 ) 1896 case TYPE_ULONGLONGINT:
1674 + 1; /* turn floor into ceil */ 1897 tmp_length =
1898 (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT
1899 * 0.333334 /* binary -> octal */
1900 )
1901 + 1; /* turn floor into ceil */
1902 break;
1903 case TYPE_UINT8_T:
1904 tmp_length =
1905 (unsigned int) (sizeof (uint8_t) * CHAR_BIT
1906 * 0.333334 /* binary -> octal */
1907 )
1908 + 1; /* turn floor into ceil */
1909 break;
1910 case TYPE_UINT16_T:
1911 tmp_length =
1912 (unsigned int) (sizeof (uint16_t) * CHAR_BIT
1913 * 0.333334 /* binary -> octal */
1914 )
1915 + 1; /* turn floor into ceil */
1916 break;
1917 case TYPE_UINT32_T:
1918 tmp_length =
1919 (unsigned int) (sizeof (uint32_t) * CHAR_BIT
1920 * 0.333334 /* binary -> octal */
1921 )
1922 + 1; /* turn floor into ceil */
1923 break;
1924 case TYPE_UINT64_T:
1925 tmp_length =
1926 (unsigned int) (sizeof (uint64_t) * CHAR_BIT
1927 * 0.333334 /* binary -> octal */
1928 )
1929 + 1; /* turn floor into ceil */
1930 break;
1931 case TYPE_UINT_FAST8_T:
1932 tmp_length =
1933 (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT
1934 * 0.333334 /* binary -> octal */
1935 )
1936 + 1; /* turn floor into ceil */
1937 break;
1938 case TYPE_UINT_FAST16_T:
1939 tmp_length =
1940 (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT
1941 * 0.333334 /* binary -> octal */
1942 )
1943 + 1; /* turn floor into ceil */
1944 break;
1945 case TYPE_UINT_FAST32_T:
1946 tmp_length =
1947 (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT
1948 * 0.333334 /* binary -> octal */
1949 )
1950 + 1; /* turn floor into ceil */
1951 break;
1952 case TYPE_UINT_FAST64_T:
1953 tmp_length =
1954 (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT
1955 * 0.333334 /* binary -> octal */
1956 )
1957 + 1; /* turn floor into ceil */
1958 break;
1959 }
1675 if (tmp_length < precision) 1960 if (tmp_length < precision)
1676 tmp_length = precision; 1961 tmp_length = precision;
1677 /* Add 1, to account for a leading sign. */ 1962 /* Add 1, to account for a leading sign. */
@@ -1679,27 +1964,89 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
1679 break; 1964 break;
1680 1965
1681 case 'x': case 'X': 1966 case 'x': case 'X':
1682 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) 1967 switch (type)
1683 tmp_length = 1968 {
1684 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT 1969 default:
1685 * 0.25 /* binary -> hexadecimal */ 1970 tmp_length =
1686 ) 1971 (unsigned int) (sizeof (unsigned int) * CHAR_BIT
1687 + 1; /* turn floor into ceil */ 1972 * 0.25 /* binary -> hexadecimal */
1688 else if (type == TYPE_LONGINT || type == TYPE_ULONGINT) 1973 )
1689 tmp_length = 1974 + 1; /* turn floor into ceil */
1690 (unsigned int) (sizeof (unsigned long) * CHAR_BIT 1975 break;
1691 * 0.25 /* binary -> hexadecimal */ 1976 case TYPE_ULONGINT:
1692 ) 1977 tmp_length =
1693 + 1; /* turn floor into ceil */ 1978 (unsigned int) (sizeof (unsigned long int) * CHAR_BIT
1694 else 1979 * 0.25 /* binary -> hexadecimal */
1695 tmp_length = 1980 )
1696 (unsigned int) (sizeof (unsigned int) * CHAR_BIT 1981 + 1; /* turn floor into ceil */
1697 * 0.25 /* binary -> hexadecimal */ 1982 break;
1698 ) 1983 case TYPE_ULONGLONGINT:
1699 + 1; /* turn floor into ceil */ 1984 tmp_length =
1985 (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT
1986 * 0.25 /* binary -> hexadecimal */
1987 )
1988 + 1; /* turn floor into ceil */
1989 break;
1990 case TYPE_UINT8_T:
1991 tmp_length =
1992 (unsigned int) (sizeof (uint8_t) * CHAR_BIT
1993 * 0.25 /* binary -> hexadecimal */
1994 )
1995 + 1; /* turn floor into ceil */
1996 break;
1997 case TYPE_UINT16_T:
1998 tmp_length =
1999 (unsigned int) (sizeof (uint16_t) * CHAR_BIT
2000 * 0.25 /* binary -> hexadecimal */
2001 )
2002 + 1; /* turn floor into ceil */
2003 break;
2004 case TYPE_UINT32_T:
2005 tmp_length =
2006 (unsigned int) (sizeof (uint32_t) * CHAR_BIT
2007 * 0.25 /* binary -> hexadecimal */
2008 )
2009 + 1; /* turn floor into ceil */
2010 break;
2011 case TYPE_UINT64_T:
2012 tmp_length =
2013 (unsigned int) (sizeof (uint64_t) * CHAR_BIT
2014 * 0.25 /* binary -> hexadecimal */
2015 )
2016 + 1; /* turn floor into ceil */
2017 break;
2018 case TYPE_UINT_FAST8_T:
2019 tmp_length =
2020 (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT
2021 * 0.25 /* binary -> hexadecimal */
2022 )
2023 + 1; /* turn floor into ceil */
2024 break;
2025 case TYPE_UINT_FAST16_T:
2026 tmp_length =
2027 (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT
2028 * 0.25 /* binary -> hexadecimal */
2029 )
2030 + 1; /* turn floor into ceil */
2031 break;
2032 case TYPE_UINT_FAST32_T:
2033 tmp_length =
2034 (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT
2035 * 0.25 /* binary -> hexadecimal */
2036 )
2037 + 1; /* turn floor into ceil */
2038 break;
2039 case TYPE_UINT_FAST64_T:
2040 tmp_length =
2041 (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT
2042 * 0.25 /* binary -> hexadecimal */
2043 )
2044 + 1; /* turn floor into ceil */
2045 break;
2046 }
1700 if (tmp_length < precision) 2047 if (tmp_length < precision)
1701 tmp_length = precision; 2048 tmp_length = precision;
1702 /* Add 2, to account for a leading sign or alternate form. */ 2049 /* Add 2, to account for a prefix from the alternate form. */
1703 tmp_length = xsum (tmp_length, 2); 2050 tmp_length = xsum (tmp_length, 2);
1704 break; 2051 break;
1705 2052
@@ -1988,6 +2335,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
1988 2335
1989 if (dp->conversion == 'n') 2336 if (dp->conversion == 'n')
1990 { 2337 {
2338#if NEED_PRINTF_WITH_N_DIRECTIVE
1991 switch (a.arg[dp->arg_index].type) 2339 switch (a.arg[dp->arg_index].type)
1992 { 2340 {
1993 case TYPE_COUNT_SCHAR_POINTER: 2341 case TYPE_COUNT_SCHAR_POINTER:
@@ -2005,9 +2353,36 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2005 case TYPE_COUNT_LONGLONGINT_POINTER: 2353 case TYPE_COUNT_LONGLONGINT_POINTER:
2006 *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length; 2354 *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
2007 break; 2355 break;
2356 case TYPE_COUNT_INT8_T_POINTER:
2357 *a.arg[dp->arg_index].a.a_count_int8_t_pointer = length;
2358 break;
2359 case TYPE_COUNT_INT16_T_POINTER:
2360 *a.arg[dp->arg_index].a.a_count_int16_t_pointer = length;
2361 break;
2362 case TYPE_COUNT_INT32_T_POINTER:
2363 *a.arg[dp->arg_index].a.a_count_int32_t_pointer = length;
2364 break;
2365 case TYPE_COUNT_INT64_T_POINTER:
2366 *a.arg[dp->arg_index].a.a_count_int64_t_pointer = length;
2367 break;
2368 case TYPE_COUNT_INT_FAST8_T_POINTER:
2369 *a.arg[dp->arg_index].a.a_count_int_fast8_t_pointer = length;
2370 break;
2371 case TYPE_COUNT_INT_FAST16_T_POINTER:
2372 *a.arg[dp->arg_index].a.a_count_int_fast16_t_pointer = length;
2373 break;
2374 case TYPE_COUNT_INT_FAST32_T_POINTER:
2375 *a.arg[dp->arg_index].a.a_count_int_fast32_t_pointer = length;
2376 break;
2377 case TYPE_COUNT_INT_FAST64_T_POINTER:
2378 *a.arg[dp->arg_index].a.a_count_int_fast64_t_pointer = length;
2379 break;
2008 default: 2380 default:
2009 abort (); 2381 abort ();
2010 } 2382 }
2383#else
2384 abort ();
2385#endif
2011 } 2386 }
2012#if ENABLE_UNISTDIO 2387#if ENABLE_UNISTDIO
2013 /* The unistdio extensions. */ 2388 /* The unistdio extensions. */
@@ -2130,7 +2505,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2130 characters = 0; 2505 characters = 0;
2131 } 2506 }
2132 2507
2133 if (characters < width && !(dp->flags & FLAG_LEFT)) 2508 if (characters < width && !(flags & FLAG_LEFT))
2134 { 2509 {
2135 size_t n = width - characters; 2510 size_t n = width - characters;
2136 ENSURE_ALLOCATION (xsum (length, n)); 2511 ENSURE_ALLOCATION (xsum (length, n));
@@ -2175,7 +2550,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2175 } 2550 }
2176# endif 2551# endif
2177 2552
2178 if (characters < width && (dp->flags & FLAG_LEFT)) 2553 if (characters < width && (flags & FLAG_LEFT))
2179 { 2554 {
2180 size_t n = width - characters; 2555 size_t n = width - characters;
2181 ENSURE_ALLOCATION (xsum (length, n)); 2556 ENSURE_ALLOCATION (xsum (length, n));
@@ -2232,7 +2607,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2232 characters = 0; 2607 characters = 0;
2233 } 2608 }
2234 2609
2235 if (characters < width && !(dp->flags & FLAG_LEFT)) 2610 if (characters < width && !(flags & FLAG_LEFT))
2236 { 2611 {
2237 size_t n = width - characters; 2612 size_t n = width - characters;
2238 ENSURE_ALLOCATION (xsum (length, n)); 2613 ENSURE_ALLOCATION (xsum (length, n));
@@ -2277,7 +2652,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2277 } 2652 }
2278# endif 2653# endif
2279 2654
2280 if (characters < width && (dp->flags & FLAG_LEFT)) 2655 if (characters < width && (flags & FLAG_LEFT))
2281 { 2656 {
2282 size_t n = width - characters; 2657 size_t n = width - characters;
2283 ENSURE_ALLOCATION (xsum (length, n)); 2658 ENSURE_ALLOCATION (xsum (length, n));
@@ -2334,7 +2709,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2334 characters = 0; 2709 characters = 0;
2335 } 2710 }
2336 2711
2337 if (characters < width && !(dp->flags & FLAG_LEFT)) 2712 if (characters < width && !(flags & FLAG_LEFT))
2338 { 2713 {
2339 size_t n = width - characters; 2714 size_t n = width - characters;
2340 ENSURE_ALLOCATION (xsum (length, n)); 2715 ENSURE_ALLOCATION (xsum (length, n));
@@ -2379,7 +2754,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2379 } 2754 }
2380# endif 2755# endif
2381 2756
2382 if (characters < width && (dp->flags & FLAG_LEFT)) 2757 if (characters < width && (flags & FLAG_LEFT))
2383 { 2758 {
2384 size_t n = width - characters; 2759 size_t n = width - characters;
2385 ENSURE_ALLOCATION (xsum (length, n)); 2760 ENSURE_ALLOCATION (xsum (length, n));
@@ -2394,7 +2769,150 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2394 } 2769 }
2395 } 2770 }
2396#endif 2771#endif
2397#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL) || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T 2772#if WIDE_CHAR_VERSION && (!DCHAR_IS_TCHAR || NEED_WPRINTF_DIRECTIVE_LC)
2773 else if ((dp->conversion == 's'
2774 && a.arg[dp->arg_index].type == TYPE_WIDE_STRING)
2775 || (dp->conversion == 'c'
2776 && a.arg[dp->arg_index].type == TYPE_WIDE_CHAR))
2777 {
2778 /* %ls or %lc in vasnwprintf. See the specification of
2779 fwprintf. */
2780 /* It would be silly to use snprintf ("%ls", ...) and then
2781 convert back the result from a char[] to a wchar_t[].
2782 Instead, just copy the argument wchar_t[] to the result. */
2783 int flags = dp->flags;
2784 size_t width;
2785
2786 width = 0;
2787 if (dp->width_start != dp->width_end)
2788 {
2789 if (dp->width_arg_index != ARG_NONE)
2790 {
2791 int arg;
2792
2793 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
2794 abort ();
2795 arg = a.arg[dp->width_arg_index].a.a_int;
2796 width = arg;
2797 if (arg < 0)
2798 {
2799 /* "A negative field width is taken as a '-' flag
2800 followed by a positive field width." */
2801 flags |= FLAG_LEFT;
2802 width = -width;
2803 }
2804 }
2805 else
2806 {
2807 const FCHAR_T *digitp = dp->width_start;
2808
2809 do
2810 width = xsum (xtimes (width, 10), *digitp++ - '0');
2811 while (digitp != dp->width_end);
2812 }
2813 }
2814
2815 {
2816 const wchar_t *ls_arg;
2817 wchar_t lc_arg[1];
2818 size_t characters;
2819
2820 if (dp->conversion == 's')
2821 {
2822 int has_precision;
2823 size_t precision;
2824
2825 has_precision = 0;
2826 precision = 6;
2827 if (dp->precision_start != dp->precision_end)
2828 {
2829 if (dp->precision_arg_index != ARG_NONE)
2830 {
2831 int arg;
2832
2833 if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
2834 abort ();
2835 arg = a.arg[dp->precision_arg_index].a.a_int;
2836 /* "A negative precision is taken as if the precision
2837 were omitted." */
2838 if (arg >= 0)
2839 {
2840 precision = arg;
2841 has_precision = 1;
2842 }
2843 }
2844 else
2845 {
2846 const FCHAR_T *digitp = dp->precision_start + 1;
2847
2848 precision = 0;
2849 while (digitp != dp->precision_end)
2850 precision = xsum (xtimes (precision, 10), *digitp++ - '0');
2851 has_precision = 1;
2852 }
2853 }
2854
2855 ls_arg = a.arg[dp->arg_index].a.a_wide_string;
2856
2857 if (has_precision)
2858 {
2859 /* Use only at most PRECISION wide characters, from
2860 the left. */
2861 const wchar_t *ls_arg_end;
2862
2863 ls_arg_end = ls_arg;
2864 characters = 0;
2865 for (; precision > 0; precision--)
2866 {
2867 if (*ls_arg_end == 0)
2868 /* Found the terminating null wide character. */
2869 break;
2870 ls_arg_end++;
2871 characters++;
2872 }
2873 }
2874 else
2875 {
2876 /* Use the entire string, and count the number of wide
2877 characters. */
2878 characters = local_wcslen (ls_arg);
2879 }
2880 }
2881 else /* dp->conversion == 'c' */
2882 {
2883 lc_arg[0] = (wchar_t) a.arg[dp->arg_index].a.a_wide_char;
2884 ls_arg = lc_arg;
2885 characters = 1;
2886 }
2887
2888 {
2889 size_t total = (characters < width ? width : characters);
2890 ENSURE_ALLOCATION (xsum (length, total));
2891
2892 if (characters < width && !(flags & FLAG_LEFT))
2893 {
2894 size_t n = width - characters;
2895 DCHAR_SET (result + length, ' ', n);
2896 length += n;
2897 }
2898
2899 if (characters > 0)
2900 {
2901 DCHAR_CPY (result + length, ls_arg, characters);
2902 length += characters;
2903 }
2904
2905 if (characters < width && (flags & FLAG_LEFT))
2906 {
2907 size_t n = width - characters;
2908 DCHAR_SET (result + length, ' ', n);
2909 length += n;
2910 }
2911 }
2912 }
2913 }
2914#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
2398 else if (dp->conversion == 's' 2916 else if (dp->conversion == 's'
2399# if WIDE_CHAR_VERSION 2917# if WIDE_CHAR_VERSION
2400 && a.arg[dp->arg_index].type != TYPE_WIDE_STRING 2918 && a.arg[dp->arg_index].type != TYPE_WIDE_STRING
@@ -2493,7 +3011,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2493 wide characters, from the left. */ 3011 wide characters, from the left. */
2494# if HAVE_MBRTOWC 3012# if HAVE_MBRTOWC
2495 mbstate_t state; 3013 mbstate_t state;
2496 memset (&state, '\0', sizeof (mbstate_t)); 3014 mbszero (&state);
2497# endif 3015# endif
2498 arg_end = arg; 3016 arg_end = arg;
2499 characters = 0; 3017 characters = 0;
@@ -2521,7 +3039,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2521 characters. */ 3039 characters. */
2522# if HAVE_MBRTOWC 3040# if HAVE_MBRTOWC
2523 mbstate_t state; 3041 mbstate_t state;
2524 memset (&state, '\0', sizeof (mbstate_t)); 3042 mbszero (&state);
2525# endif 3043# endif
2526 arg_end = arg; 3044 arg_end = arg;
2527 characters = 0; 3045 characters = 0;
@@ -2551,7 +3069,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2551 characters = 0; 3069 characters = 0;
2552 } 3070 }
2553 3071
2554 if (characters < width && !(dp->flags & FLAG_LEFT)) 3072 if (characters < width && !(flags & FLAG_LEFT))
2555 { 3073 {
2556 size_t n = width - characters; 3074 size_t n = width - characters;
2557 ENSURE_ALLOCATION (xsum (length, n)); 3075 ENSURE_ALLOCATION (xsum (length, n));
@@ -2565,7 +3083,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2565 size_t remaining; 3083 size_t remaining;
2566# if HAVE_MBRTOWC 3084# if HAVE_MBRTOWC
2567 mbstate_t state; 3085 mbstate_t state;
2568 memset (&state, '\0', sizeof (mbstate_t)); 3086 mbszero (&state);
2569# endif 3087# endif
2570 ENSURE_ALLOCATION (xsum (length, characters)); 3088 ENSURE_ALLOCATION (xsum (length, characters));
2571 for (remaining = characters; remaining > 0; remaining--) 3089 for (remaining = characters; remaining > 0; remaining--)
@@ -2591,7 +3109,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2591 { 3109 {
2592# if HAVE_MBRTOWC 3110# if HAVE_MBRTOWC
2593 mbstate_t state; 3111 mbstate_t state;
2594 memset (&state, '\0', sizeof (mbstate_t)); 3112 mbszero (&state);
2595# endif 3113# endif
2596 while (arg < arg_end) 3114 while (arg < arg_end)
2597 { 3115 {
@@ -2602,17 +3120,19 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2602# else 3120# else
2603 count = mbtowc (&wc, arg, arg_end - arg); 3121 count = mbtowc (&wc, arg, arg_end - arg);
2604# endif 3122# endif
2605 if (count <= 0) 3123 if (count == 0)
2606 /* mbrtowc not consistent with mbrlen, or mbtowc 3124 /* mbrtowc not consistent with strlen. */
2607 not consistent with mblen. */
2608 abort (); 3125 abort ();
3126 if (count < 0)
3127 /* Invalid or incomplete multibyte character. */
3128 goto fail_with_EILSEQ;
2609 ENSURE_ALLOCATION (xsum (length, 1)); 3129 ENSURE_ALLOCATION (xsum (length, 1));
2610 result[length++] = wc; 3130 result[length++] = wc;
2611 arg += count; 3131 arg += count;
2612 } 3132 }
2613 } 3133 }
2614 3134
2615 if (characters < width && (dp->flags & FLAG_LEFT)) 3135 if (characters < width && (flags & FLAG_LEFT))
2616 { 3136 {
2617 size_t n = width - characters; 3137 size_t n = width - characters;
2618 ENSURE_ALLOCATION (xsum (length, n)); 3138 ENSURE_ALLOCATION (xsum (length, n));
@@ -2641,7 +3161,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2641 at most PRECISION bytes, from the left. */ 3161 at most PRECISION bytes, from the left. */
2642# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 3162# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
2643 mbstate_t state; 3163 mbstate_t state;
2644 memset (&state, '\0', sizeof (mbstate_t)); 3164 mbszero (&state);
2645# endif 3165# endif
2646 arg_end = arg; 3166 arg_end = arg;
2647 characters = 0; 3167 characters = 0;
@@ -2674,7 +3194,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2674 bytes. */ 3194 bytes. */
2675# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 3195# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
2676 mbstate_t state; 3196 mbstate_t state;
2677 memset (&state, '\0', sizeof (mbstate_t)); 3197 mbszero (&state);
2678# endif 3198# endif
2679 arg_end = arg; 3199 arg_end = arg;
2680 characters = 0; 3200 characters = 0;
@@ -2714,7 +3234,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2714 size_t remaining; 3234 size_t remaining;
2715# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 3235# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
2716 mbstate_t state; 3236 mbstate_t state;
2717 memset (&state, '\0', sizeof (mbstate_t)); 3237 mbszero (&state);
2718# endif 3238# endif
2719 for (remaining = characters; remaining > 0; ) 3239 for (remaining = characters; remaining > 0; )
2720 { 3240 {
@@ -2768,7 +3288,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2768 /* w doesn't matter. */ 3288 /* w doesn't matter. */
2769 w = 0; 3289 w = 0;
2770 3290
2771 if (w < width && !(dp->flags & FLAG_LEFT)) 3291 if (w < width && !(flags & FLAG_LEFT))
2772 { 3292 {
2773 size_t n = width - w; 3293 size_t n = width - w;
2774 ENSURE_ALLOCATION (xsum (length, n)); 3294 ENSURE_ALLOCATION (xsum (length, n));
@@ -2783,7 +3303,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2783 size_t remaining; 3303 size_t remaining;
2784# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 3304# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
2785 mbstate_t state; 3305 mbstate_t state;
2786 memset (&state, '\0', sizeof (mbstate_t)); 3306 mbszero (&state);
2787# endif 3307# endif
2788 ENSURE_ALLOCATION (xsum (length, characters)); 3308 ENSURE_ALLOCATION (xsum (length, characters));
2789 for (remaining = characters; remaining > 0; ) 3309 for (remaining = characters; remaining > 0; )
@@ -2809,7 +3329,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2809 { 3329 {
2810# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 3330# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
2811 mbstate_t state; 3331 mbstate_t state;
2812 memset (&state, '\0', sizeof (mbstate_t)); 3332 mbszero (&state);
2813# endif 3333# endif
2814 while (arg < arg_end) 3334 while (arg < arg_end)
2815 { 3335 {
@@ -2836,7 +3356,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2836 length += tmpdst_len; 3356 length += tmpdst_len;
2837# endif 3357# endif
2838 3358
2839 if (w < width && (dp->flags & FLAG_LEFT)) 3359 if (w < width && (flags & FLAG_LEFT))
2840 { 3360 {
2841 size_t n = width - w; 3361 size_t n = width - w;
2842 ENSURE_ALLOCATION (xsum (length, n)); 3362 ENSURE_ALLOCATION (xsum (length, n));
@@ -2847,12 +3367,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2847# endif 3367# endif
2848 } 3368 }
2849#endif 3369#endif
2850#if ENABLE_WCHAR_FALLBACK && HAVE_WINT_T && !WIDE_CHAR_VERSION 3370#if (NEED_PRINTF_DIRECTIVE_LC || ENABLE_WCHAR_FALLBACK) && HAVE_WINT_T && !WIDE_CHAR_VERSION
2851 else if (dp->conversion == 'c' 3371 else if (dp->conversion == 'c'
2852 && a.arg[dp->arg_index].type == TYPE_WIDE_CHAR) 3372 && a.arg[dp->arg_index].type == TYPE_WIDE_CHAR)
2853 { 3373 {
2854 /* Implement the 'lc' directive ourselves, in order to provide 3374 /* Implement the 'lc' directive ourselves, in order to provide
2855 the fallback that avoids EILSEQ. */ 3375 a correct behaviour for the null wint_t argument and/or the
3376 fallback that avoids EILSEQ. */
2856 int flags = dp->flags; 3377 int flags = dp->flags;
2857 int has_width; 3378 int has_width;
2858 size_t width; 3379 size_t width;
@@ -2907,21 +3428,18 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2907 { 3428 {
2908 /* Count the number of bytes. */ 3429 /* Count the number of bytes. */
2909 characters = 0; 3430 characters = 0;
2910 if (arg != 0) 3431 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
2911 { 3432 int count;
2912 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
2913 int count;
2914# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 3433# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
2915 mbstate_t state; 3434 mbstate_t state;
2916 memset (&state, '\0', sizeof (mbstate_t)); 3435 mbszero (&state);
2917# endif 3436# endif
2918 3437
2919 count = local_wcrtomb (cbuf, arg, &state); 3438 count = local_wcrtomb (cbuf, arg, &state);
2920 if (count < 0) 3439 if (count < 0)
2921 /* Inconsistency. */ 3440 /* Cannot convert. */
2922 abort (); 3441 goto fail_with_EILSEQ;
2923 characters = count; 3442 characters = count;
2924 }
2925 } 3443 }
2926# if DCHAR_IS_TCHAR 3444# if DCHAR_IS_TCHAR
2927 else 3445 else
@@ -2933,13 +3451,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2933 3451
2934# if !DCHAR_IS_TCHAR 3452# if !DCHAR_IS_TCHAR
2935 /* Convert the string into a piece of temporary memory. */ 3453 /* Convert the string into a piece of temporary memory. */
2936 if (characters > 0) /* implies arg != 0 */ 3454 if (characters > 0)
2937 { 3455 {
2938 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */ 3456 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
2939 int count; 3457 int count;
2940# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 3458# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
2941 mbstate_t state; 3459 mbstate_t state;
2942 memset (&state, '\0', sizeof (mbstate_t)); 3460 mbszero (&state);
2943# endif 3461# endif
2944 3462
2945 count = local_wcrtomb (cbuf, arg, &state); 3463 count = local_wcrtomb (cbuf, arg, &state);
@@ -2977,7 +3495,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2977 /* w doesn't matter. */ 3495 /* w doesn't matter. */
2978 w = 0; 3496 w = 0;
2979 3497
2980 if (w < width && !(dp->flags & FLAG_LEFT)) 3498 if (w < width && !(flags & FLAG_LEFT))
2981 { 3499 {
2982 size_t n = width - w; 3500 size_t n = width - w;
2983 ENSURE_ALLOCATION (xsum (length, n)); 3501 ENSURE_ALLOCATION (xsum (length, n));
@@ -2990,12 +3508,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2990 { 3508 {
2991 /* We know the number of bytes in advance. */ 3509 /* We know the number of bytes in advance. */
2992 ENSURE_ALLOCATION (xsum (length, characters)); 3510 ENSURE_ALLOCATION (xsum (length, characters));
2993 if (characters > 0) /* implies arg != 0 */ 3511 if (characters > 0)
2994 { 3512 {
2995 int count; 3513 int count;
2996# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 3514# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
2997 mbstate_t state; 3515 mbstate_t state;
2998 memset (&state, '\0', sizeof (mbstate_t)); 3516 mbszero (&state);
2999# endif 3517# endif
3000 3518
3001 count = local_wcrtomb (result + length, arg, &state); 3519 count = local_wcrtomb (result + length, arg, &state);
@@ -3007,23 +3525,20 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3007 } 3525 }
3008 else 3526 else
3009 { 3527 {
3010 if (arg != 0) 3528 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
3011 { 3529 int count;
3012 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
3013 int count;
3014# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 3530# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
3015 mbstate_t state; 3531 mbstate_t state;
3016 memset (&state, '\0', sizeof (mbstate_t)); 3532 mbszero (&state);
3017# endif 3533# endif
3018 3534
3019 count = local_wcrtomb (cbuf, arg, &state); 3535 count = local_wcrtomb (cbuf, arg, &state);
3020 if (count <= 0) 3536 if (count < 0)
3021 /* Inconsistency. */ 3537 /* Cannot convert. */
3022 abort (); 3538 goto fail_with_EILSEQ;
3023 ENSURE_ALLOCATION (xsum (length, count)); 3539 ENSURE_ALLOCATION (xsum (length, count));
3024 memcpy (result + length, cbuf, count); 3540 memcpy (result + length, cbuf, count);
3025 length += count; 3541 length += count;
3026 }
3027 } 3542 }
3028# else 3543# else
3029 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len), 3544 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len),
@@ -3033,7 +3548,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3033 length += tmpdst_len; 3548 length += tmpdst_len;
3034# endif 3549# endif
3035 3550
3036 if (w < width && (dp->flags & FLAG_LEFT)) 3551 if (w < width && (flags & FLAG_LEFT))
3037 { 3552 {
3038 size_t n = width - w; 3553 size_t n = width - w;
3039 ENSURE_ALLOCATION (xsum (length, n)); 3554 ENSURE_ALLOCATION (xsum (length, n));
@@ -3043,14 +3558,399 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3043 } 3558 }
3044 } 3559 }
3045#endif 3560#endif
3046#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL 3561#if NEED_WPRINTF_DIRECTIVE_C && WIDE_CHAR_VERSION
3562 else if (dp->conversion == 'c'
3563 && a.arg[dp->arg_index].type != TYPE_WIDE_CHAR)
3564 {
3565 /* Implement the 'c' directive ourselves, in order to avoid
3566 EILSEQ in the "C" locale. */
3567 int flags = dp->flags;
3568 size_t width;
3569
3570 width = 0;
3571 if (dp->width_start != dp->width_end)
3572 {
3573 if (dp->width_arg_index != ARG_NONE)
3574 {
3575 int arg;
3576
3577 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
3578 abort ();
3579 arg = a.arg[dp->width_arg_index].a.a_int;
3580 width = arg;
3581 if (arg < 0)
3582 {
3583 /* "A negative field width is taken as a '-' flag
3584 followed by a positive field width." */
3585 flags |= FLAG_LEFT;
3586 width = -width;
3587 }
3588 }
3589 else
3590 {
3591 const FCHAR_T *digitp = dp->width_start;
3592
3593 do
3594 width = xsum (xtimes (width, 10), *digitp++ - '0');
3595 while (digitp != dp->width_end);
3596 }
3597 }
3598
3599 /* %c in vasnwprintf. See the specification of fwprintf. */
3600 {
3601 char arg = (char) a.arg[dp->arg_index].a.a_char;
3602 mbstate_t state;
3603 wchar_t wc;
3604
3605 mbszero (&state);
3606 int count = mbrtowc (&wc, &arg, 1, &state);
3607 if (count < 0)
3608 /* Invalid or incomplete multibyte character. */
3609 goto fail_with_EILSEQ;
3610
3611 if (1 < width && !(flags & FLAG_LEFT))
3612 {
3613 size_t n = width - 1;
3614 ENSURE_ALLOCATION (xsum (length, n));
3615 DCHAR_SET (result + length, ' ', n);
3616 length += n;
3617 }
3618
3619 ENSURE_ALLOCATION (xsum (length, 1));
3620 result[length++] = wc;
3621
3622 if (1 < width && (flags & FLAG_LEFT))
3623 {
3624 size_t n = width - 1;
3625 ENSURE_ALLOCATION (xsum (length, n));
3626 DCHAR_SET (result + length, ' ', n);
3627 length += n;
3628 }
3629 }
3630 }
3631#endif
3632#if NEED_PRINTF_DIRECTIVE_B || NEED_PRINTF_DIRECTIVE_UPPERCASE_B
3633 else if (0
3634# if NEED_PRINTF_DIRECTIVE_B
3635 || (dp->conversion == 'b')
3636# endif
3637# if NEED_PRINTF_DIRECTIVE_UPPERCASE_B
3638 || (dp->conversion == 'B')
3639# endif
3640 )
3641 {
3642 arg_type type = a.arg[dp->arg_index].type;
3643 int flags = dp->flags;
3644 int has_width;
3645 size_t width;
3646 int has_precision;
3647 size_t precision;
3648 size_t tmp_length;
3649 size_t count;
3650 DCHAR_T tmpbuf[700];
3651 DCHAR_T *tmp;
3652 DCHAR_T *tmp_end;
3653 DCHAR_T *tmp_start;
3654 DCHAR_T *pad_ptr;
3655 DCHAR_T *p;
3656
3657 has_width = 0;
3658 width = 0;
3659 if (dp->width_start != dp->width_end)
3660 {
3661 if (dp->width_arg_index != ARG_NONE)
3662 {
3663 int arg;
3664
3665 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
3666 abort ();
3667 arg = a.arg[dp->width_arg_index].a.a_int;
3668 width = arg;
3669 if (arg < 0)
3670 {
3671 /* "A negative field width is taken as a '-' flag
3672 followed by a positive field width." */
3673 flags |= FLAG_LEFT;
3674 width = -width;
3675 }
3676 }
3677 else
3678 {
3679 const FCHAR_T *digitp = dp->width_start;
3680
3681 do
3682 width = xsum (xtimes (width, 10), *digitp++ - '0');
3683 while (digitp != dp->width_end);
3684 }
3685 has_width = 1;
3686 }
3687
3688 has_precision = 0;
3689 precision = 1;
3690 if (dp->precision_start != dp->precision_end)
3691 {
3692 if (dp->precision_arg_index != ARG_NONE)
3693 {
3694 int arg;
3695
3696 if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
3697 abort ();
3698 arg = a.arg[dp->precision_arg_index].a.a_int;
3699 /* "A negative precision is taken as if the precision
3700 were omitted." */
3701 if (arg >= 0)
3702 {
3703 precision = arg;
3704 has_precision = 1;
3705 }
3706 }
3707 else
3708 {
3709 const FCHAR_T *digitp = dp->precision_start + 1;
3710
3711 precision = 0;
3712 while (digitp != dp->precision_end)
3713 precision = xsum (xtimes (precision, 10), *digitp++ - '0');
3714 has_precision = 1;
3715 }
3716 }
3717
3718 /* Allocate a temporary buffer of sufficient size. */
3719 switch (type)
3720 {
3721 default:
3722 tmp_length =
3723 (unsigned int) (sizeof (unsigned int) * CHAR_BIT)
3724 + 1; /* turn floor into ceil */
3725 break;
3726 case TYPE_ULONGINT:
3727 tmp_length =
3728 (unsigned int) (sizeof (unsigned long int) * CHAR_BIT)
3729 + 1; /* turn floor into ceil */
3730 break;
3731 case TYPE_ULONGLONGINT:
3732 tmp_length =
3733 (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT)
3734 + 1; /* turn floor into ceil */
3735 break;
3736 case TYPE_UINT8_T:
3737 tmp_length =
3738 (unsigned int) (sizeof (uint8_t) * CHAR_BIT)
3739 + 1; /* turn floor into ceil */
3740 break;
3741 case TYPE_UINT16_T:
3742 tmp_length =
3743 (unsigned int) (sizeof (uint16_t) * CHAR_BIT)
3744 + 1; /* turn floor into ceil */
3745 break;
3746 case TYPE_UINT32_T:
3747 tmp_length =
3748 (unsigned int) (sizeof (uint32_t) * CHAR_BIT)
3749 + 1; /* turn floor into ceil */
3750 break;
3751 case TYPE_UINT64_T:
3752 tmp_length =
3753 (unsigned int) (sizeof (uint64_t) * CHAR_BIT)
3754 + 1; /* turn floor into ceil */
3755 break;
3756 case TYPE_UINT_FAST8_T:
3757 tmp_length =
3758 (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT)
3759 + 1; /* turn floor into ceil */
3760 break;
3761 case TYPE_UINT_FAST16_T:
3762 tmp_length =
3763 (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT)
3764 + 1; /* turn floor into ceil */
3765 break;
3766 case TYPE_UINT_FAST32_T:
3767 tmp_length =
3768 (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT)
3769 + 1; /* turn floor into ceil */
3770 break;
3771 case TYPE_UINT_FAST64_T:
3772 tmp_length =
3773 (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT)
3774 + 1; /* turn floor into ceil */
3775 break;
3776 }
3777 if (tmp_length < precision)
3778 tmp_length = precision;
3779 /* Add 2, to account for a prefix from the alternate form. */
3780 tmp_length = xsum (tmp_length, 2);
3781
3782 if (tmp_length < width)
3783 tmp_length = width;
3784
3785 if (tmp_length <= sizeof (tmpbuf) / sizeof (DCHAR_T))
3786 tmp = tmpbuf;
3787 else
3788 {
3789 size_t tmp_memsize = xtimes (tmp_length, sizeof (DCHAR_T));
3790
3791 if (size_overflow_p (tmp_memsize))
3792 /* Overflow, would lead to out of memory. */
3793 goto out_of_memory;
3794 tmp = (DCHAR_T *) malloc (tmp_memsize);
3795 if (tmp == NULL)
3796 /* Out of memory. */
3797 goto out_of_memory;
3798 }
3799
3800 tmp_end = tmp + tmp_length;
3801
3802 unsigned long long arg;
3803 switch (type)
3804 {
3805 case TYPE_UCHAR:
3806 arg = a.arg[dp->arg_index].a.a_uchar;
3807 break;
3808 case TYPE_USHORT:
3809 arg = a.arg[dp->arg_index].a.a_ushort;
3810 break;
3811 case TYPE_UINT:
3812 arg = a.arg[dp->arg_index].a.a_uint;
3813 break;
3814 case TYPE_ULONGINT:
3815 arg = a.arg[dp->arg_index].a.a_ulongint;
3816 break;
3817 case TYPE_ULONGLONGINT:
3818 arg = a.arg[dp->arg_index].a.a_ulonglongint;
3819 break;
3820 case TYPE_UINT8_T:
3821 arg = a.arg[dp->arg_index].a.a_uint8_t;
3822 break;
3823 case TYPE_UINT16_T:
3824 arg = a.arg[dp->arg_index].a.a_uint16_t;
3825 break;
3826 case TYPE_UINT32_T:
3827 arg = a.arg[dp->arg_index].a.a_uint32_t;
3828 break;
3829 case TYPE_UINT64_T:
3830 arg = a.arg[dp->arg_index].a.a_uint64_t;
3831 break;
3832 case TYPE_UINT_FAST8_T:
3833 arg = a.arg[dp->arg_index].a.a_uint_fast8_t;
3834 break;
3835 case TYPE_UINT_FAST16_T:
3836 arg = a.arg[dp->arg_index].a.a_uint_fast16_t;
3837 break;
3838 case TYPE_UINT_FAST32_T:
3839 arg = a.arg[dp->arg_index].a.a_uint_fast32_t;
3840 break;
3841 case TYPE_UINT_FAST64_T:
3842 arg = a.arg[dp->arg_index].a.a_uint_fast64_t;
3843 break;
3844 default:
3845 abort ();
3846 }
3847 int need_prefix = ((flags & FLAG_ALT) && arg != 0);
3848
3849 p = tmp_end;
3850 /* "The result of converting a zero value with a precision
3851 of zero is no characters." */
3852 if (!(has_precision && precision == 0 && arg == 0))
3853 {
3854 do
3855 {
3856 *--p = '0' + (arg & 1);
3857 arg = arg >> 1;
3858 }
3859 while (arg != 0);
3860 }
3861
3862 if (has_precision)
3863 {
3864 DCHAR_T *digits_start = tmp_end - precision;
3865 while (p > digits_start)
3866 *--p = '0';
3867 }
3868
3869 pad_ptr = p;
3870
3871 if (need_prefix)
3872 {
3873# if NEED_PRINTF_DIRECTIVE_B && !NEED_PRINTF_DIRECTIVE_UPPERCASE_B
3874 *--p = 'b';
3875# elif NEED_PRINTF_DIRECTIVE_UPPERCASE_B && !NEED_PRINTF_DIRECTIVE_B
3876 *--p = 'B';
3877# else
3878 *--p = dp->conversion;
3879# endif
3880 *--p = '0';
3881 }
3882 tmp_start = p;
3883
3884 /* The generated string now extends from tmp_start to tmp_end,
3885 with the zero padding insertion point being at pad_ptr,
3886 tmp_start <= pad_ptr <= tmp_end. */
3887 count = tmp_end - tmp_start;
3888
3889 if (count < width)
3890 {
3891 size_t pad = width - count;
3892
3893 if (flags & FLAG_LEFT)
3894 {
3895 /* Pad with spaces on the right. */
3896 for (p = tmp_start; p < tmp_end; p++)
3897 *(p - pad) = *p;
3898 for (p = tmp_end - pad; p < tmp_end; p++)
3899 *p = ' ';
3900 }
3901 else if ((flags & FLAG_ZERO)
3902 /* Neither ISO C nor POSIX specify that the '0'
3903 flag is ignored when a width and a precision
3904 are both present. But most implementations
3905 do so. */
3906 && !(has_width && has_precision))
3907 {
3908 /* Pad with zeroes. */
3909 for (p = tmp_start; p < pad_ptr; p++)
3910 *(p - pad) = *p;
3911 for (p = pad_ptr - pad; p < pad_ptr; p++)
3912 *p = '0';
3913 }
3914 else
3915 {
3916 /* Pad with spaces on the left. */
3917 for (p = tmp_start - pad; p < tmp_start; p++)
3918 *p = ' ';
3919 }
3920
3921 tmp_start = tmp_start - pad;
3922 }
3923
3924 count = tmp_end - tmp_start;
3925
3926 if (count > tmp_length)
3927 /* tmp_length was incorrectly calculated - fix the
3928 code above! */
3929 abort ();
3930
3931 /* Make room for the result. */
3932 if (count >= allocated - length)
3933 {
3934 size_t n = xsum (length, count);
3935
3936 ENSURE_ALLOCATION (n);
3937 }
3938
3939 /* Append the result. */
3940 memcpy (result + length, tmp_start, count * sizeof (DCHAR_T));
3941 if (tmp != tmpbuf)
3942 free (tmp);
3943 length += count;
3944 }
3945#endif
3946#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
3047 else if ((dp->conversion == 'a' || dp->conversion == 'A') 3947 else if ((dp->conversion == 'a' || dp->conversion == 'A')
3048# if !(NEED_PRINTF_DIRECTIVE_A || (NEED_PRINTF_LONG_DOUBLE && NEED_PRINTF_DOUBLE)) 3948# if !(NEED_PRINTF_DIRECTIVE_A || (NEED_PRINTF_LONG_DOUBLE && NEED_PRINTF_DOUBLE))
3049 && (0 3949 && (0
3050# if NEED_PRINTF_DOUBLE 3950# if NEED_PRINTF_DOUBLE
3051 || a.arg[dp->arg_index].type == TYPE_DOUBLE 3951 || a.arg[dp->arg_index].type == TYPE_DOUBLE
3052# endif 3952# endif
3053# if NEED_PRINTF_LONG_DOUBLE 3953# if NEED_PRINTF_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
3054 || a.arg[dp->arg_index].type == TYPE_LONGDOUBLE 3954 || a.arg[dp->arg_index].type == TYPE_LONGDOUBLE
3055# endif 3955# endif
3056 ) 3956 )
@@ -3170,7 +4070,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3170 p = tmp; 4070 p = tmp;
3171 if (type == TYPE_LONGDOUBLE) 4071 if (type == TYPE_LONGDOUBLE)
3172 { 4072 {
3173# if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE 4073# if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
3174 long double arg = a.arg[dp->arg_index].a.a_longdouble; 4074 long double arg = a.arg[dp->arg_index].a.a_longdouble;
3175 4075
3176 if (isnanl (arg)) 4076 if (isnanl (arg))
@@ -3290,7 +4190,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3290 } 4190 }
3291 } 4191 }
3292 *p++ = dp->conversion - 'A' + 'P'; 4192 *p++ = dp->conversion - 'A' + 'P';
3293# if WIDE_CHAR_VERSION 4193# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
3294 { 4194 {
3295 static const wchar_t decimal_format[] = 4195 static const wchar_t decimal_format[] =
3296 { '%', '+', 'd', '\0' }; 4196 { '%', '+', 'd', '\0' };
@@ -3441,7 +4341,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3441 } 4341 }
3442 } 4342 }
3443 *p++ = dp->conversion - 'A' + 'P'; 4343 *p++ = dp->conversion - 'A' + 'P';
3444# if WIDE_CHAR_VERSION 4344# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
3445 { 4345 {
3446 static const wchar_t decimal_format[] = 4346 static const wchar_t decimal_format[] =
3447 { '%', '+', 'd', '\0' }; 4347 { '%', '+', 'd', '\0' };
@@ -3533,7 +4433,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3533 length += count; 4433 length += count;
3534 } 4434 }
3535#endif 4435#endif
3536#if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL 4436#if NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE
3537 else if ((dp->conversion == 'f' || dp->conversion == 'F' 4437 else if ((dp->conversion == 'f' || dp->conversion == 'F'
3538 || dp->conversion == 'e' || dp->conversion == 'E' 4438 || dp->conversion == 'e' || dp->conversion == 'E'
3539 || dp->conversion == 'g' || dp->conversion == 'G' 4439 || dp->conversion == 'g' || dp->conversion == 'G'
@@ -3901,7 +4801,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3901 } 4801 }
3902 4802
3903 *p++ = dp->conversion; /* 'e' or 'E' */ 4803 *p++ = dp->conversion; /* 'e' or 'E' */
3904# if WIDE_CHAR_VERSION 4804# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
3905 { 4805 {
3906 static const wchar_t decimal_format[] = 4806 static const wchar_t decimal_format[] =
3907 { '%', '+', '.', '2', 'd', '\0' }; 4807 { '%', '+', '.', '2', 'd', '\0' };
@@ -4082,7 +4982,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4082 } 4982 }
4083 } 4983 }
4084 *p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */ 4984 *p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */
4085# if WIDE_CHAR_VERSION 4985# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
4086 { 4986 {
4087 static const wchar_t decimal_format[] = 4987 static const wchar_t decimal_format[] =
4088 { '%', '+', '.', '2', 'd', '\0' }; 4988 { '%', '+', '.', '2', 'd', '\0' };
@@ -4359,7 +5259,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4359 } 5259 }
4360 5260
4361 *p++ = dp->conversion; /* 'e' or 'E' */ 5261 *p++ = dp->conversion; /* 'e' or 'E' */
4362# if WIDE_CHAR_VERSION 5262# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
4363 { 5263 {
4364 static const wchar_t decimal_format[] = 5264 static const wchar_t decimal_format[] =
4365 /* Produce the same number of exponent digits 5265 /* Produce the same number of exponent digits
@@ -4552,7 +5452,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4552 } 5452 }
4553 } 5453 }
4554 *p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */ 5454 *p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */
4555# if WIDE_CHAR_VERSION 5455# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
4556 { 5456 {
4557 static const wchar_t decimal_format[] = 5457 static const wchar_t decimal_format[] =
4558 /* Produce the same number of exponent digits 5458 /* Produce the same number of exponent digits
@@ -4720,24 +5620,24 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4720 { 5620 {
4721 arg_type type = a.arg[dp->arg_index].type; 5621 arg_type type = a.arg[dp->arg_index].type;
4722 int flags = dp->flags; 5622 int flags = dp->flags;
4723#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 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
4724 int has_width; 5624 int has_width;
4725#endif 5625#endif
4726#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 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
4727 size_t width; 5627 size_t width;
4728#endif 5628#endif
4729#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION 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
4730 int has_precision; 5630 int has_precision;
4731 size_t precision; 5631 size_t precision;
4732#endif 5632#endif
4733#if NEED_PRINTF_UNBOUNDED_PRECISION 5633#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
4734 int prec_ourselves; 5634 int prec_ourselves;
4735#else 5635#else
4736# define prec_ourselves 0 5636# define prec_ourselves 0
4737#endif 5637#endif
4738#if NEED_PRINTF_FLAG_LEFTADJUST 5638#if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST
4739# define pad_ourselves 1 5639# define pad_ourselves 1
4740#elif !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 5640#elif !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
4741 int pad_ourselves; 5641 int pad_ourselves;
4742#else 5642#else
4743# define pad_ourselves 0 5643# define pad_ourselves 0
@@ -4752,10 +5652,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4752 TCHAR_T *tmp; 5652 TCHAR_T *tmp;
4753#endif 5653#endif
4754 5654
4755#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 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
4756 has_width = 0; 5656 has_width = 0;
4757#endif 5657#endif
4758#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 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
4759 width = 0; 5659 width = 0;
4760 if (dp->width_start != dp->width_end) 5660 if (dp->width_start != dp->width_end)
4761 { 5661 {
@@ -4783,13 +5683,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4783 width = xsum (xtimes (width, 10), *digitp++ - '0'); 5683 width = xsum (xtimes (width, 10), *digitp++ - '0');
4784 while (digitp != dp->width_end); 5684 while (digitp != dp->width_end);
4785 } 5685 }
4786#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 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
4787 has_width = 1; 5687 has_width = 1;
4788#endif 5688# endif
4789 } 5689 }
4790#endif 5690#endif
4791 5691
4792#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION 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
4793 has_precision = 0; 5693 has_precision = 0;
4794 precision = 6; 5694 precision = 6;
4795 if (dp->precision_start != dp->precision_end) 5695 if (dp->precision_start != dp->precision_end)
@@ -4822,14 +5722,32 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4822#endif 5722#endif
4823 5723
4824 /* Decide whether to handle the precision ourselves. */ 5724 /* Decide whether to handle the precision ourselves. */
4825#if NEED_PRINTF_UNBOUNDED_PRECISION 5725#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
4826 switch (dp->conversion) 5726 switch (dp->conversion)
4827 { 5727 {
5728# if NEED_PRINTF_UNBOUNDED_PRECISION
4828 case 'd': case 'i': case 'u': 5729 case 'd': case 'i': case 'u':
5730 case 'b':
5731 #if SUPPORT_GNU_PRINTF_DIRECTIVES \
5732 || (__GLIBC__ + (__GLIBC_MINOR__ >= 35) > 2)
5733 case 'B':
5734 #endif
4829 case 'o': 5735 case 'o':
4830 case 'x': case 'X': case 'p':
4831 prec_ourselves = has_precision && (precision > 0); 5736 prec_ourselves = has_precision && (precision > 0);
4832 break; 5737 break;
5738# endif
5739 case 'x': case 'X': case 'p':
5740 prec_ourselves =
5741 has_precision
5742 && (0
5743# if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO
5744 || (precision == 0)
5745# endif
5746# if NEED_PRINTF_UNBOUNDED_PRECISION
5747 || (precision > 0)
5748# endif
5749 );
5750 break;
4833 default: 5751 default:
4834 prec_ourselves = 0; 5752 prec_ourselves = 0;
4835 break; 5753 break;
@@ -4837,7 +5755,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4837#endif 5755#endif
4838 5756
4839 /* Decide whether to perform the padding ourselves. */ 5757 /* Decide whether to perform the padding ourselves. */
4840#if !NEED_PRINTF_FLAG_LEFTADJUST && (!DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION) 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)
4841 switch (dp->conversion) 5759 switch (dp->conversion)
4842 { 5760 {
4843# if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO 5761# if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO
@@ -4956,6 +5874,54 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4956 { 5874 {
4957 case TYPE_LONGLONGINT: 5875 case TYPE_LONGLONGINT:
4958 case TYPE_ULONGLONGINT: 5876 case TYPE_ULONGLONGINT:
5877 #if INT8_WIDTH > LONG_WIDTH
5878 case TYPE_INT8_T:
5879 #endif
5880 #if UINT8_WIDTH > LONG_WIDTH
5881 case TYPE_UINT8_T:
5882 #endif
5883 #if INT16_WIDTH > LONG_WIDTH
5884 case TYPE_INT16_T:
5885 #endif
5886 #if UINT16_WIDTH > LONG_WIDTH
5887 case TYPE_UINT16_T:
5888 #endif
5889 #if INT32_WIDTH > LONG_WIDTH
5890 case TYPE_INT32_T:
5891 #endif
5892 #if UINT32_WIDTH > LONG_WIDTH
5893 case TYPE_UINT32_T:
5894 #endif
5895 #if INT64_WIDTH > LONG_WIDTH
5896 case TYPE_INT64_T:
5897 #endif
5898 #if UINT64_WIDTH > LONG_WIDTH
5899 case TYPE_UINT64_T:
5900 #endif
5901 #if INT_FAST8_WIDTH > LONG_WIDTH
5902 case TYPE_INT_FAST8_T:
5903 #endif
5904 #if UINT_FAST8_WIDTH > LONG_WIDTH
5905 case TYPE_UINT_FAST8_T:
5906 #endif
5907 #if INT_FAST16_WIDTH > LONG_WIDTH
5908 case TYPE_INT_FAST16_T:
5909 #endif
5910 #if UINT_FAST16_WIDTH > LONG_WIDTH
5911 case TYPE_UINT_FAST16_T:
5912 #endif
5913 #if INT_FAST32_WIDTH > LONG_WIDTH
5914 case TYPE_INT3_FAST2_T:
5915 #endif
5916 #if UINT_FAST32_WIDTH > LONG_WIDTH
5917 case TYPE_UINT_FAST32_T:
5918 #endif
5919 #if INT_FAST64_WIDTH > LONG_WIDTH
5920 case TYPE_INT_FAST64_T:
5921 #endif
5922 #if UINT_FAST64_WIDTH > LONG_WIDTH
5923 case TYPE_UINT_FAST64_T:
5924 #endif
4959#if defined _WIN32 && ! defined __CYGWIN__ 5925#if defined _WIN32 && ! defined __CYGWIN__
4960 *fbp++ = 'I'; 5926 *fbp++ = 'I';
4961 *fbp++ = '6'; 5927 *fbp++ = '6';
@@ -4967,12 +5933,60 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4967 FALLTHROUGH; 5933 FALLTHROUGH;
4968 case TYPE_LONGINT: 5934 case TYPE_LONGINT:
4969 case TYPE_ULONGINT: 5935 case TYPE_ULONGINT:
4970#if HAVE_WINT_T 5936 #if INT8_WIDTH > INT_WIDTH && INT8_WIDTH <= LONG_WIDTH
5937 case TYPE_INT8_T:
5938 #endif
5939 #if UINT8_WIDTH > INT_WIDTH && UINT8_WIDTH <= LONG_WIDTH
5940 case TYPE_UINT8_T:
5941 #endif
5942 #if INT16_WIDTH > INT_WIDTH && INT16_WIDTH <= LONG_WIDTH
5943 case TYPE_INT16_T:
5944 #endif
5945 #if UINT16_WIDTH > INT_WIDTH && UINT16_WIDTH <= LONG_WIDTH
5946 case TYPE_UINT16_T:
5947 #endif
5948 #if INT32_WIDTH > INT_WIDTH && INT32_WIDTH <= LONG_WIDTH
5949 case TYPE_INT32_T:
5950 #endif
5951 #if UINT32_WIDTH > INT_WIDTH && UINT32_WIDTH <= LONG_WIDTH
5952 case TYPE_UINT32_T:
5953 #endif
5954 #if INT64_WIDTH > INT_WIDTH && INT64_WIDTH <= LONG_WIDTH
5955 case TYPE_INT64_T:
5956 #endif
5957 #if UINT64_WIDTH > INT_WIDTH && UINT64_WIDTH <= LONG_WIDTH
5958 case TYPE_UINT64_T:
5959 #endif
5960 #if INT_FAST8_WIDTH > INT_WIDTH && INT_FAST8_WIDTH <= LONG_WIDTH
5961 case TYPE_INT_FAST8_T:
5962 #endif
5963 #if UINT_FAST8_WIDTH > INT_WIDTH && UINT_FAST8_WIDTH <= LONG_WIDTH
5964 case TYPE_UINT_FAST8_T:
5965 #endif
5966 #if INT_FAST16_WIDTH > INT_WIDTH && INT_FAST16_WIDTH <= LONG_WIDTH
5967 case TYPE_INT_FAST16_T:
5968 #endif
5969 #if UINT_FAST16_WIDTH > INT_WIDTH && UINT_FAST16_WIDTH <= LONG_WIDTH
5970 case TYPE_UINT_FAST16_T:
5971 #endif
5972 #if INT_FAST32_WIDTH > INT_WIDTH && INT_FAST32_WIDTH <= LONG_WIDTH
5973 case TYPE_INT_FAST32_T:
5974 #endif
5975 #if UINT_FAST32_WIDTH > INT_WIDTH && UINT_FAST32_WIDTH <= LONG_WIDTH
5976 case TYPE_UINT_FAST32_T:
5977 #endif
5978 #if INT_FAST64_WIDTH > INT_WIDTH && INT_FAST64_WIDTH <= LONG_WIDTH
5979 case TYPE_INT_FAST64_T:
5980 #endif
5981 #if UINT_FAST64_WIDTH > INT_WIDTH && UINT_FAST64_WIDTH <= LONG_WIDTH
5982 case TYPE_UINT_FAST64_T:
5983 #endif
5984 #if HAVE_WINT_T
4971 case TYPE_WIDE_CHAR: 5985 case TYPE_WIDE_CHAR:
4972#endif 5986 #endif
4973#if HAVE_WCHAR_T 5987 #if HAVE_WCHAR_T
4974 case TYPE_WIDE_STRING: 5988 case TYPE_WIDE_STRING:
4975#endif 5989 #endif
4976 *fbp++ = 'l'; 5990 *fbp++ = 'l';
4977 break; 5991 break;
4978 case TYPE_LONGDOUBLE: 5992 case TYPE_LONGDOUBLE:
@@ -4988,47 +6002,74 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4988#endif 6002#endif
4989 *fbp = dp->conversion; 6003 *fbp = dp->conversion;
4990#if USE_SNPRINTF 6004#if USE_SNPRINTF
4991# if ((HAVE_SNPRINTF_RETVAL_C99 && HAVE_SNPRINTF_TRUNCATION_C99) \ 6005 /* Decide whether to pass %n in the format string
6006 to SNPRINTF. */
6007# if (((!WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR) \
6008 && (HAVE_SNPRINTF_RETVAL_C99 && HAVE_SNPRINTF_TRUNCATION_C99)) \
4992 || ((__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) \ 6009 || ((__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) \
4993 && !defined __UCLIBC__) \ 6010 && !defined __UCLIBC__) \
4994 || (defined __APPLE__ && defined __MACH__) \ 6011 || (defined __APPLE__ && defined __MACH__) \
6012 || defined __OpenBSD__ \
4995 || defined __ANDROID__ \ 6013 || defined __ANDROID__ \
4996 || (defined _WIN32 && ! defined __CYGWIN__)) 6014 || (defined _WIN32 && ! defined __CYGWIN__)) \
4997 /* On systems where we know that snprintf's return value 6015 || (WIDE_CHAR_VERSION && MUSL_LIBC)
4998 conforms to ISO C 99 (HAVE_SNPRINTF_RETVAL_C99) and that 6016 /* We can avoid passing %n and instead rely on SNPRINTF's
4999 snprintf always produces NUL-terminated strings 6017 return value if
5000 (HAVE_SNPRINTF_TRUNCATION_C99), it is possible to avoid 6018 - !WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR, because otherwise,
5001 using %n. And it is desirable to do so, because more and 6019 when WIDE_CHAR_VERSION && DCHAR_IS_TCHAR,
5002 more platforms no longer support %n, for "security reasons". 6020 snwprintf()/_snwprintf() (Windows) and swprintf() (Unix)
5003 In particular, the following platforms: 6021 don't return the needed buffer size,
6022 and
6023 - we're compiling for a system where we know
6024 - that snprintf's return value conforms to ISO C 99
6025 (HAVE_SNPRINTF_RETVAL_C99) and
6026 - that snprintf always produces NUL-terminated strings
6027 (HAVE_SNPRINTF_TRUNCATION_C99).
6028 And it is desirable to do so, because more and more platforms
6029 no longer support %n, for "security reasons". */
6030 /* On specific platforms, listed below, we *must* avoid %n.
6031 In the case
6032 !WIDE_CHAR_VERSION && HAVE_SNPRINTF_RETVAL_C99 && !USE_MSVC__SNPRINTF
6033 we can rely on the return value of snprintf instead. Whereas
6034 in the opposite case
6035 WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
6036 we need to make room based on an estimation, computed by
6037 MAX_ROOM_NEEDED. */
6038 /* The following platforms forbid %n:
5004 - On glibc2 systems from 2004-10-18 or newer, the use of 6039 - On glibc2 systems from 2004-10-18 or newer, the use of
5005 %n in format strings in writable memory may crash the 6040 %n in format strings in writable memory may crash the
5006 program (if compiled with _FORTIFY_SOURCE=2). 6041 program (if compiled with _FORTIFY_SOURCE=2).
5007 - On Mac OS X 10.13 or newer, the use of %n in format 6042 - On macOS 10.13 or newer, the use of %n in format
5008 strings in writable memory by default crashes the 6043 strings in writable memory by default crashes the
5009 program. 6044 program.
6045 - On OpenBSD, since 2021-08-30, the use of %n in format
6046 strings produces an abort (see
6047 <https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdio/vfprintf.c.diff?r1=1.79&r2=1.80&f=h>,
6048 <https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdio/vfwprintf.c.diff?r1=1.20&r2=1.21&f=h>).
5010 - On Android, starting on 2018-03-07, the use of %n in 6049 - On Android, starting on 2018-03-07, the use of %n in
5011 format strings produces a fatal error (see 6050 format strings produces a fatal error (see
5012 <https://android.googlesource.com/platform/bionic/+/41398d03b7e8e0dfb951660ae713e682e9fc0336>). 6051 <https://android.googlesource.com/platform/bionic/+/41398d03b7e8e0dfb951660ae713e682e9fc0336>).
5013 On these platforms, HAVE_SNPRINTF_RETVAL_C99 and 6052 - On native Windows systems (such as mingw) where the OS is
5014 HAVE_SNPRINTF_TRUNCATION_C99 are 1. We have listed them 6053 Windows Vista, the use of %n in format strings by default
5015 explicitly in the condition above, in case of cross- 6054 crashes the program. See
5016 compilation (just to be sure). */ 6055 <https://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and
5017 /* On native Windows systems (such as mingw), we can avoid using 6056 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/set-printf-count-output>
5018 %n because: 6057 On the first four of these platforms, if !WIDE_CHAR_VERSION,
6058 it is not a big deal to avoid %n, because on these platforms,
6059 HAVE_SNPRINTF_RETVAL_C99 and HAVE_SNPRINTF_TRUNCATION_C99 are
6060 1.
6061 On native Windows, if !WIDE_CHAR_VERSION, it's not a big deal
6062 either because:
5019 - Although the gl_SNPRINTF_TRUNCATION_C99 test fails, 6063 - Although the gl_SNPRINTF_TRUNCATION_C99 test fails,
5020 snprintf does not write more than the specified number 6064 snprintf does not write more than the specified number
5021 of bytes. (snprintf (buf, 3, "%d %d", 4567, 89) writes 6065 of bytes. (snprintf (buf, 3, "%d %d", 4567, 89) writes
5022 '4', '5', '6' into buf, not '4', '5', '\0'.) 6066 '4', '5', '6' into buf, not '4', '5', '\0'.)
5023 - Although the gl_SNPRINTF_RETVAL_C99 test fails, snprintf 6067 - Although the gl_SNPRINTF_RETVAL_C99 test fails, snprintf
5024 allows us to recognize the case of an insufficient 6068 allows us to recognize the case of an insufficient
5025 buffer size: it returns -1 in this case. 6069 buffer size: it returns -1 in this case. */
5026 On native Windows systems (such as mingw) where the OS is 6070 /* Additionally, in the WIDE_CHAR_VERSION case, we cannot use %n
5027 Windows Vista, the use of %n in format strings by default 6071 on musl libc because we would run into an swprintf() bug.
5028 crashes the program. See 6072 See <https://www.openwall.com/lists/musl/2023/03/19/1>. */
5029 <https://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and
5030 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/set-printf-count-output>
5031 So we should avoid %n in this situation. */
5032 fbp[1] = '\0'; 6073 fbp[1] = '\0';
5033# else /* AIX <= 5.1, HP-UX, IRIX, OSF/1, Solaris <= 9, BeOS */ 6074# else /* AIX <= 5.1, HP-UX, IRIX, OSF/1, Solaris <= 9, BeOS */
5034 fbp[1] = '%'; 6075 fbp[1] = '%';
@@ -5189,6 +6230,102 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5189 SNPRINTF_BUF (arg); 6230 SNPRINTF_BUF (arg);
5190 } 6231 }
5191 break; 6232 break;
6233 case TYPE_INT8_T:
6234 {
6235 int8_t arg = a.arg[dp->arg_index].a.a_int8_t;
6236 SNPRINTF_BUF (arg);
6237 }
6238 break;
6239 case TYPE_UINT8_T:
6240 {
6241 uint8_t arg = a.arg[dp->arg_index].a.a_uint8_t;
6242 SNPRINTF_BUF (arg);
6243 }
6244 break;
6245 case TYPE_INT16_T:
6246 {
6247 int16_t arg = a.arg[dp->arg_index].a.a_int16_t;
6248 SNPRINTF_BUF (arg);
6249 }
6250 break;
6251 case TYPE_UINT16_T:
6252 {
6253 uint16_t arg = a.arg[dp->arg_index].a.a_uint16_t;
6254 SNPRINTF_BUF (arg);
6255 }
6256 break;
6257 case TYPE_INT32_T:
6258 {
6259 int32_t arg = a.arg[dp->arg_index].a.a_int32_t;
6260 SNPRINTF_BUF (arg);
6261 }
6262 break;
6263 case TYPE_UINT32_T:
6264 {
6265 uint32_t arg = a.arg[dp->arg_index].a.a_uint32_t;
6266 SNPRINTF_BUF (arg);
6267 }
6268 break;
6269 case TYPE_INT64_T:
6270 {
6271 int64_t arg = a.arg[dp->arg_index].a.a_int64_t;
6272 SNPRINTF_BUF (arg);
6273 }
6274 break;
6275 case TYPE_UINT64_T:
6276 {
6277 uint64_t arg = a.arg[dp->arg_index].a.a_uint64_t;
6278 SNPRINTF_BUF (arg);
6279 }
6280 break;
6281 case TYPE_INT_FAST8_T:
6282 {
6283 int_fast8_t arg = a.arg[dp->arg_index].a.a_int_fast8_t;
6284 SNPRINTF_BUF (arg);
6285 }
6286 break;
6287 case TYPE_UINT_FAST8_T:
6288 {
6289 uint_fast8_t arg = a.arg[dp->arg_index].a.a_uint_fast8_t;
6290 SNPRINTF_BUF (arg);
6291 }
6292 break;
6293 case TYPE_INT_FAST16_T:
6294 {
6295 int_fast16_t arg = a.arg[dp->arg_index].a.a_int_fast16_t;
6296 SNPRINTF_BUF (arg);
6297 }
6298 break;
6299 case TYPE_UINT_FAST16_T:
6300 {
6301 uint_fast16_t arg = a.arg[dp->arg_index].a.a_uint_fast16_t;
6302 SNPRINTF_BUF (arg);
6303 }
6304 break;
6305 case TYPE_INT_FAST32_T:
6306 {
6307 int_fast32_t arg = a.arg[dp->arg_index].a.a_int_fast32_t;
6308 SNPRINTF_BUF (arg);
6309 }
6310 break;
6311 case TYPE_UINT_FAST32_T:
6312 {
6313 uint_fast32_t arg = a.arg[dp->arg_index].a.a_uint_fast32_t;
6314 SNPRINTF_BUF (arg);
6315 }
6316 break;
6317 case TYPE_INT_FAST64_T:
6318 {
6319 int_fast64_t arg = a.arg[dp->arg_index].a.a_int_fast64_t;
6320 SNPRINTF_BUF (arg);
6321 }
6322 break;
6323 case TYPE_UINT_FAST64_T:
6324 {
6325 uint_fast64_t arg = a.arg[dp->arg_index].a.a_uint_fast64_t;
6326 SNPRINTF_BUF (arg);
6327 }
6328 break;
5192 case TYPE_DOUBLE: 6329 case TYPE_DOUBLE:
5193 { 6330 {
5194 double arg = a.arg[dp->arg_index].a.a_double; 6331 double arg = a.arg[dp->arg_index].a.a_double;
@@ -5271,12 +6408,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5271 /* Look at the snprintf() return value. */ 6408 /* Look at the snprintf() return value. */
5272 if (retcount < 0) 6409 if (retcount < 0)
5273 { 6410 {
5274# if !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF 6411# if (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
5275 /* HP-UX 10.20 snprintf() is doubly deficient: 6412 /* HP-UX 10.20 snprintf() is doubly deficient:
5276 It doesn't understand the '%n' directive, 6413 It doesn't understand the '%n' directive,
5277 *and* it returns -1 (rather than the length 6414 *and* it returns -1 (rather than the length
5278 that would have been required) when the 6415 that would have been required) when the
5279 buffer is too small. 6416 buffer is too small.
6417 Likewise, in case of
6418 WIDE_CHAR_VERSION && DCHAR_IS_TCHAR, the
6419 functions snwprintf()/_snwprintf() (Windows)
6420 or swprintf() (Unix).
5280 But a failure at this point can also come 6421 But a failure at this point can also come
5281 from other reasons than a too small buffer, 6422 from other reasons than a too small buffer,
5282 such as an invalid wide string argument to 6423 such as an invalid wide string argument to
@@ -5312,7 +6453,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5312# endif 6453# endif
5313 } 6454 }
5314 else 6455 else
5315 count = retcount; 6456 {
6457 count = retcount;
6458# if WIDE_CHAR_VERSION && defined __MINGW32__
6459 if (count == 0 && dp->conversion == 'c')
6460 /* snwprintf returned 0 instead of 1. But it
6461 wrote a null wide character. */
6462 count = 1;
6463# endif
6464 }
5316 } 6465 }
5317 } 6466 }
5318#endif 6467#endif
@@ -5370,7 +6519,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5370 } 6519 }
5371#endif 6520#endif
5372 6521
5373#if NEED_PRINTF_UNBOUNDED_PRECISION 6522#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
5374 if (prec_ourselves) 6523 if (prec_ourselves)
5375 { 6524 {
5376 /* Handle the precision. */ 6525 /* Handle the precision. */
@@ -5430,6 +6579,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5430 6579
5431 count += insert; 6580 count += insert;
5432 } 6581 }
6582# if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO
6583 else if (precision == 0
6584 && move == 1
6585 && prec_ptr[prefix_count] == '0')
6586 {
6587 /* Replace the "0" result with an empty string. */
6588 count = prefix_count;
6589 }
6590# endif
5433 } 6591 }
5434#endif 6592#endif
5435 6593
@@ -5442,11 +6600,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5442 6600
5443#if !DCHAR_IS_TCHAR 6601#if !DCHAR_IS_TCHAR
5444 /* Convert from TCHAR_T[] to DCHAR_T[]. */ 6602 /* Convert from TCHAR_T[] to DCHAR_T[]. */
5445 if (dp->conversion == 'c' || dp->conversion == 's') 6603 if (dp->conversion == 'c' || dp->conversion == 's'
6604# if __GLIBC__ >= 2 && !defined __UCLIBC__
6605 || (flags & FLAG_LOCALIZED)
6606# endif
6607 )
5446 { 6608 {
5447 /* type = TYPE_CHAR or TYPE_WIDE_CHAR or TYPE_STRING 6609 /* The result string is not guaranteed to be ASCII. */
5448 TYPE_WIDE_STRING.
5449 The result string is not certainly ASCII. */
5450 const TCHAR_T *tmpsrc; 6610 const TCHAR_T *tmpsrc;
5451 DCHAR_T *tmpdst; 6611 DCHAR_T *tmpdst;
5452 size_t tmpdst_len; 6612 size_t tmpdst_len;
@@ -5457,6 +6617,56 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5457# else 6617# else
5458 tmpsrc = tmp; 6618 tmpsrc = tmp;
5459# endif 6619# endif
6620# if WIDE_CHAR_VERSION
6621 /* Convert tmpsrc[0..count-1] to a freshly allocated
6622 wide character array. */
6623 mbstate_t state;
6624
6625 mbszero (&state);
6626 tmpdst_len = 0;
6627 {
6628 const TCHAR_T *src = tmpsrc;
6629 size_t srclen = count;
6630
6631 for (; srclen > 0; tmpdst_len++)
6632 {
6633 /* Parse the next multibyte character. */
6634 size_t ret = mbrtowc (NULL, src, srclen, &state);
6635 if (ret == (size_t)(-2) || ret == (size_t)(-1))
6636 goto fail_with_EILSEQ;
6637 if (ret == 0)
6638 ret = 1;
6639 src += ret;
6640 srclen -= ret;
6641 }
6642 }
6643
6644 tmpdst =
6645 (wchar_t *) malloc ((tmpdst_len + 1) * sizeof (wchar_t));
6646 if (tmpdst == NULL)
6647 goto out_of_memory;
6648
6649 mbszero (&state);
6650 {
6651 DCHAR_T *destptr = tmpdst;
6652 const TCHAR_T *src = tmpsrc;
6653 size_t srclen = count;
6654
6655 for (; srclen > 0; destptr++)
6656 {
6657 /* Parse the next multibyte character. */
6658 size_t ret = mbrtowc (destptr, src, srclen, &state);
6659 if (ret == (size_t)(-2) || ret == (size_t)(-1))
6660 /* Should already have been caught in the first
6661 loop, above. */
6662 abort ();
6663 if (ret == 0)
6664 ret = 1;
6665 src += ret;
6666 srclen -= ret;
6667 }
6668 }
6669# else
5460 tmpdst = 6670 tmpdst =
5461 DCHAR_CONV_FROM_ENCODING (locale_charset (), 6671 DCHAR_CONV_FROM_ENCODING (locale_charset (),
5462 iconveh_question_mark, 6672 iconveh_question_mark,
@@ -5465,6 +6675,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5465 NULL, &tmpdst_len); 6675 NULL, &tmpdst_len);
5466 if (tmpdst == NULL) 6676 if (tmpdst == NULL)
5467 goto fail_with_errno; 6677 goto fail_with_errno;
6678# endif
5468 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len), 6679 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len),
5469 { free (tmpdst); goto out_of_memory; }); 6680 { free (tmpdst); goto out_of_memory; });
5470 DCHAR_CPY (result + length, tmpdst, tmpdst_len); 6681 DCHAR_CPY (result + length, tmpdst, tmpdst_len);
@@ -5531,7 +6742,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5531 /* Here count <= allocated - length. */ 6742 /* Here count <= allocated - length. */
5532 6743
5533 /* Perform padding. */ 6744 /* Perform padding. */
5534#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 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
5535 if (pad_ourselves && has_width) 6746 if (pad_ourselves && has_width)
5536 { 6747 {
5537 size_t w; 6748 size_t w;
@@ -5590,6 +6801,22 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5590 if ((*pad_ptr >= 'A' && *pad_ptr <= 'Z') 6801 if ((*pad_ptr >= 'A' && *pad_ptr <= 'Z')
5591 || (*pad_ptr >= 'a' && *pad_ptr <= 'z')) 6802 || (*pad_ptr >= 'a' && *pad_ptr <= 'z'))
5592 pad_ptr = NULL; 6803 pad_ptr = NULL;
6804 else
6805 /* Do the zero-padding after the "0x" or
6806 "0b" prefix, not before. */
6807 if (p - rp >= 2
6808 && *rp == '0'
6809 && (((dp->conversion == 'a'
6810 || dp->conversion == 'x')
6811 && rp[1] == 'x')
6812 || ((dp->conversion == 'A'
6813 || dp->conversion == 'X')
6814 && rp[1] == 'X')
6815 || (dp->conversion == 'b'
6816 && rp[1] == 'b')
6817 || (dp->conversion == 'B'
6818 && rp[1] == 'B')))
6819 pad_ptr += 2;
5593 } 6820 }
5594 /* The generated string now extends from rp to p, 6821 /* The generated string now extends from rp to p,
5595 with the zero padding insertion point being at 6822 with the zero padding insertion point being at
@@ -5603,7 +6830,22 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5603 for (; pad > 0; pad--) 6830 for (; pad > 0; pad--)
5604 *p++ = ' '; 6831 *p++ = ' ';
5605 } 6832 }
5606 else if ((flags & FLAG_ZERO) && pad_ptr != NULL) 6833 else if ((flags & FLAG_ZERO) && pad_ptr != NULL
6834 /* ISO C says: "For d, i, o, u, x, and X
6835 conversions, if a precision is
6836 specified, the 0 flag is ignored. */
6837 && !(has_precision
6838 && (dp->conversion == 'd'
6839 || dp->conversion == 'i'
6840 || dp->conversion == 'o'
6841 || dp->conversion == 'u'
6842 || dp->conversion == 'x'
6843 || dp->conversion == 'X'
6844 /* Although ISO C does not
6845 require it, treat 'b' and 'B'
6846 like 'x' and 'X'. */
6847 || dp->conversion == 'b'
6848 || dp->conversion == 'B')))
5607 { 6849 {
5608 /* Pad with zeroes. */ 6850 /* Pad with zeroes. */
5609 DCHAR_T *q = end; 6851 DCHAR_T *q = end;
@@ -5697,7 +6939,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5697 errno = ENOMEM; 6939 errno = ENOMEM;
5698 goto fail_with_errno; 6940 goto fail_with_errno;
5699 6941
5700#if ENABLE_UNISTDIO || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL) || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T) 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)
5701 fail_with_EILSEQ: 6943 fail_with_EILSEQ:
5702 errno = EILSEQ; 6944 errno = EILSEQ;
5703 goto fail_with_errno; 6945 goto fail_with_errno;
diff --git a/gl/vasnprintf.h b/gl/vasnprintf.h
index f69649fb..7ed9145c 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2002-2004, 2007-2024 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,6 +17,11 @@
17#ifndef _VASNPRINTF_H 17#ifndef _VASNPRINTF_H
18#define _VASNPRINTF_H 18#define _VASNPRINTF_H
19 19
20/* This file uses _GL_ATTRIBUTE_FORMAT. */
21#if !_GL_CONFIG_H_INCLUDED
22 #error "Please include config.h first."
23#endif
24
20/* Get va_list. */ 25/* Get va_list. */
21#include <stdarg.h> 26#include <stdarg.h>
22 27
diff --git a/gl/vasprintf.c b/gl/vasprintf.c
index d2878cd9..e52aaca5 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2002, 2006-2024 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/verify.h b/gl/verify.h
index b63cb264..08268c24 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2005-2006, 2009-2024 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
@@ -188,9 +188,9 @@ template <int w>
188 _gl_verify_type<(R) ? 1 : -1> 188 _gl_verify_type<(R) ? 1 : -1>
189#elif defined _GL_HAVE__STATIC_ASSERT 189#elif defined _GL_HAVE__STATIC_ASSERT
190# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \ 190# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
191 struct { \ 191 struct { \
192 _Static_assert (R, DIAGNOSTIC); \ 192 _Static_assert (R, DIAGNOSTIC); \
193 int _gl_dummy; \ 193 int _gl_dummy; \
194 } 194 }
195#else 195#else
196# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \ 196# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
@@ -212,8 +212,8 @@ template <int w>
212#elif defined _GL_HAVE__STATIC_ASSERT 212#elif defined _GL_HAVE__STATIC_ASSERT
213# define _GL_VERIFY(R, DIAGNOSTIC, ...) _Static_assert (R, DIAGNOSTIC) 213# define _GL_VERIFY(R, DIAGNOSTIC, ...) _Static_assert (R, DIAGNOSTIC)
214#else 214#else
215# define _GL_VERIFY(R, DIAGNOSTIC, ...) \ 215# define _GL_VERIFY(R, DIAGNOSTIC, ...) \
216 extern int (*_GL_GENSYM (_gl_verify_function) (void)) \ 216 extern int (*_GL_GENSYM (_gl_verify_function) (void)) \
217 [_GL_VERIFY_TRUE (R, DIAGNOSTIC)] 217 [_GL_VERIFY_TRUE (R, DIAGNOSTIC)]
218# if 4 < __GNUC__ + (6 <= __GNUC_MINOR__) 218# if 4 < __GNUC__ + (6 <= __GNUC_MINOR__)
219# pragma GCC diagnostic ignored "-Wnested-externs" 219# pragma GCC diagnostic ignored "-Wnested-externs"
@@ -222,22 +222,43 @@ template <int w>
222 222
223/* _GL_STATIC_ASSERT_H is defined if this code is copied into assert.h. */ 223/* _GL_STATIC_ASSERT_H is defined if this code is copied into assert.h. */
224#ifdef _GL_STATIC_ASSERT_H 224#ifdef _GL_STATIC_ASSERT_H
225# if !defined _GL_HAVE__STATIC_ASSERT1 && !defined _Static_assert 225/* Define _Static_assert if needed. */
226/* With clang ≥ 3.8.0 in C++ mode, _Static_assert already works and accepts
227 1 or 2 arguments. We better don't override it, because clang's standard
228 C++ library uses static_assert inside classes in several places, and our
229 replacement via _GL_VERIFY does not work in these contexts. */
230# if (defined __cplusplus && defined __clang__ \
231 && (4 <= __clang_major__ + (8 <= __clang_minor__)))
232# if 5 <= __clang_major__
233/* Avoid "warning: 'static_assert' with no message is a C++17 extension". */
234# pragma clang diagnostic ignored "-Wc++17-extensions"
235# else
236/* Avoid "warning: static_assert with no message is a C++1z extension". */
237# pragma clang diagnostic ignored "-Wc++1z-extensions"
238# endif
239# elif !defined _GL_HAVE__STATIC_ASSERT1 && !defined _Static_assert
226# if !defined _MSC_VER || defined __clang__ 240# if !defined _MSC_VER || defined __clang__
227# define _Static_assert(...) \ 241# define _Static_assert(...) \
228 _GL_VERIFY (__VA_ARGS__, "static assertion failed", -) 242 _GL_VERIFY (__VA_ARGS__, "static assertion failed", -)
229# else 243# else
230 /* Work around MSVC preprocessor incompatibility with ISO C; see 244# if defined __cplusplus && _MSC_VER >= 1910
231 <https://stackoverflow.com/questions/5134523/>. */ 245 /* In MSVC 14.1 or newer, static_assert accepts one or two arguments,
232# define _Static_assert(R, ...) \ 246 but _Static_assert is not defined. */
233 _GL_VERIFY ((R), "static assertion failed", -) 247# define _Static_assert static_assert
248# else
249 /* Work around MSVC preprocessor incompatibility with ISO C; see
250 <https://stackoverflow.com/questions/5134523/>. */
251# define _Static_assert(R, ...) \
252 _GL_VERIFY ((R), "static assertion failed", -)
253# endif
234# endif 254# endif
235# endif 255# endif
256/* Define static_assert if needed. */
236# if (!defined static_assert \ 257# if (!defined static_assert \
237 && __STDC_VERSION__ < 202311 \ 258 && __STDC_VERSION__ < 202311 \
238 && (!defined __cplusplus \ 259 && (!defined __cplusplus \
239 || (__cpp_static_assert < 201411 \ 260 || (__cpp_static_assert < 201411 \
240 && __GNUG__ < 6 && __clang_major__ < 6))) 261 && __GNUG__ < 6 && __clang_major__ < 6 && _MSC_VER < 1910)))
241# if defined __cplusplus && _MSC_VER >= 1900 && !defined __clang__ 262# if defined __cplusplus && _MSC_VER >= 1900 && !defined __clang__
242/* MSVC 14 in C++ mode supports the two-arguments static_assert but not 263/* MSVC 14 in C++ mode supports the two-arguments static_assert but not
243 the one-argument static_assert, and it does not support _Static_assert. 264 the one-argument static_assert, and it does not support _Static_assert.
@@ -250,6 +271,8 @@ template <int w>
250# define _GL_SA3 static_assert 271# define _GL_SA3 static_assert
251# define _GL_SA_PICK(x1,x2,x3,x4,...) x4 272# define _GL_SA_PICK(x1,x2,x3,x4,...) x4
252# define static_assert(...) _GL_EXPAND(_GL_SA_PICK(__VA_ARGS__,_GL_SA3,_GL_SA2,_GL_SA1)) (__VA_ARGS__) 273# define static_assert(...) _GL_EXPAND(_GL_SA_PICK(__VA_ARGS__,_GL_SA3,_GL_SA2,_GL_SA1)) (__VA_ARGS__)
274/* Avoid "fatal error C1189: #error: The C++ Standard Library forbids macroizing keywords." */
275# define _ALLOW_KEYWORD_MACROS 1
253# else 276# else
254# define static_assert _Static_assert /* C11 requires this #define. */ 277# define static_assert _Static_assert /* C11 requires this #define. */
255# endif 278# endif
@@ -268,14 +291,16 @@ template <int w>
268# define _GL_HAS_BUILTIN_TRAP 0 291# define _GL_HAS_BUILTIN_TRAP 0
269#endif 292#endif
270 293
271#if defined __clang_major__ && __clang_major__ < 5 294#ifndef _GL_HAS_BUILTIN_UNREACHABLE
272# define _GL_HAS_BUILTIN_UNREACHABLE 0 295# if defined __clang_major__ && __clang_major__ < 5
273#elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__) 296# define _GL_HAS_BUILTIN_UNREACHABLE 0
274# define _GL_HAS_BUILTIN_UNREACHABLE 1 297# elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__)
275#elif defined __has_builtin 298# define _GL_HAS_BUILTIN_UNREACHABLE 1
276# define _GL_HAS_BUILTIN_UNREACHABLE __has_builtin (__builtin_unreachable) 299# elif defined __has_builtin
277#else 300# define _GL_HAS_BUILTIN_UNREACHABLE __has_builtin (__builtin_unreachable)
278# define _GL_HAS_BUILTIN_UNREACHABLE 0 301# else
302# define _GL_HAS_BUILTIN_UNREACHABLE 0
303# endif
279#endif 304#endif
280 305
281/* Each of these macros verifies that its argument R is nonzero. To 306/* Each of these macros verifies that its argument R is nonzero. To
diff --git a/gl/vsnprintf.c b/gl/vsnprintf.c
index acd4e2d4..e6676a1f 100644
--- a/gl/vsnprintf.c
+++ b/gl/vsnprintf.c
@@ -1,5 +1,5 @@
1/* Formatted output to strings. 1/* Formatted output to strings.
2 Copyright (C) 2004, 2006-2023 Free Software Foundation, Inc. 2 Copyright (C) 2004, 2006-2024 Free Software Foundation, Inc.
3 Written by Simon Josefsson and Yoann Vandoorselaere <yoann@prelude-ids.org>. 3 Written by Simon Josefsson and Yoann Vandoorselaere <yoann@prelude-ids.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
diff --git a/gl/w32sock.h b/gl/w32sock.h
index 84e46e33..166a5f77 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2008-2024 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 30756034..701013a0 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2010-2024 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
@@ -32,6 +32,10 @@
32 _GL_WARN_ON_USE_ATTRIBUTE is for functions with 'static' or 'inline' 32 _GL_WARN_ON_USE_ATTRIBUTE is for functions with 'static' or 'inline'
33 linkage. 33 linkage.
34 34
35 _GL_WARN_ON_USE should not be used more than once for a given function
36 in a given compilation unit (because this may generate a warning even
37 if the function is never called).
38
35 However, one of the reasons that a function is a portability trap is 39 However, one of the reasons that a function is a portability trap is
36 if it has the wrong signature. Declaring FUNCTION with a different 40 if it has the wrong signature. Declaring FUNCTION with a different
37 signature in C is a compilation error, so this macro must use the 41 signature in C is a compilation error, so this macro must use the
diff --git a/gl/wchar.in.h b/gl/wchar.in.h
index 09c9185f..a33a10f7 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2007-2024 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
@@ -84,6 +84,13 @@
84#ifndef _@GUARD_PREFIX@_WCHAR_H 84#ifndef _@GUARD_PREFIX@_WCHAR_H
85#define _@GUARD_PREFIX@_WCHAR_H 85#define _@GUARD_PREFIX@_WCHAR_H
86 86
87/* This file uses _GL_ATTRIBUTE_DEALLOC, _GL_ATTRIBUTE_MALLOC,
88 _GL_ATTRIBUTE_NOTHROW, _GL_ATTRIBUTE_PURE, GNULIB_POSIXCHECK,
89 HAVE_RAW_DECL_*. */
90#if !_GL_CONFIG_H_INCLUDED
91 #error "Please include config.h first."
92#endif
93
87/* _GL_ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers 94/* _GL_ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers
88 that can be freed by passing them as the Ith argument to the 95 that can be freed by passing them as the Ith argument to the
89 function F. */ 96 function F. */
@@ -130,6 +137,28 @@
130# endif 137# endif
131#endif 138#endif
132 139
140/* _GL_ATTRIBUTE_NOTHROW declares that the function does not throw exceptions.
141 */
142#ifndef _GL_ATTRIBUTE_NOTHROW
143# if defined __cplusplus
144# if (__GNUC__ + (__GNUC_MINOR__ >= 8) > 2) || __clang_major >= 4
145# if __cplusplus >= 201103L
146# define _GL_ATTRIBUTE_NOTHROW noexcept (true)
147# else
148# define _GL_ATTRIBUTE_NOTHROW throw ()
149# endif
150# else
151# define _GL_ATTRIBUTE_NOTHROW
152# endif
153# else
154# if (__GNUC__ + (__GNUC_MINOR__ >= 3) > 3) || defined __clang__
155# define _GL_ATTRIBUTE_NOTHROW __attribute__ ((__nothrow__))
156# else
157# define _GL_ATTRIBUTE_NOTHROW
158# endif
159# endif
160#endif
161
133/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ 162/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
134 163
135/* The definition of _GL_ARG_NONNULL is copied here. */ 164/* The definition of _GL_ARG_NONNULL is copied here. */
@@ -188,7 +217,11 @@ typedef int rpl_mbstate_t;
188# if (@REPLACE_FREE@ && !defined free \ 217# if (@REPLACE_FREE@ && !defined free \
189 && !(defined __cplusplus && defined GNULIB_NAMESPACE)) 218 && !(defined __cplusplus && defined GNULIB_NAMESPACE))
190/* We can't do '#define free rpl_free' here. */ 219/* We can't do '#define free rpl_free' here. */
220# if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2)
221_GL_EXTERN_C void rpl_free (void *) _GL_ATTRIBUTE_NOTHROW;
222# else
191_GL_EXTERN_C void rpl_free (void *); 223_GL_EXTERN_C void rpl_free (void *);
224# endif
192# undef _GL_ATTRIBUTE_DEALLOC_FREE 225# undef _GL_ATTRIBUTE_DEALLOC_FREE
193# define _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC (rpl_free, 1) 226# define _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC (rpl_free, 1)
194# else 227# else
@@ -200,7 +233,7 @@ _GL_EXTERN_C
200 void __cdecl free (void *); 233 void __cdecl free (void *);
201# else 234# else
202# if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2) 235# if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2)
203_GL_EXTERN_C void free (void *) throw (); 236_GL_EXTERN_C void free (void *) _GL_ATTRIBUTE_NOTHROW;
204# else 237# else
205_GL_EXTERN_C void free (void *); 238_GL_EXTERN_C void free (void *);
206# endif 239# endif
@@ -215,13 +248,20 @@ _GL_EXTERN_C
215 void __cdecl free (void *); 248 void __cdecl free (void *);
216# else 249# else
217# if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2) 250# if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2)
218_GL_EXTERN_C void free (void *) throw (); 251_GL_EXTERN_C void free (void *) _GL_ATTRIBUTE_NOTHROW;
219# else 252# else
220_GL_EXTERN_C void free (void *); 253_GL_EXTERN_C void free (void *);
221# endif 254# endif
222# endif 255# endif
223#endif 256#endif
224 257
258
259#if @GNULIB_MBSZERO@
260/* Get memset(). */
261# include <string.h>
262#endif
263
264
225/* Convert a single-byte character to a wide character. */ 265/* Convert a single-byte character to a wide character. */
226#if @GNULIB_BTOWC@ 266#if @GNULIB_BTOWC@
227# if @REPLACE_BTOWC@ 267# if @REPLACE_BTOWC@
@@ -278,7 +318,7 @@ _GL_WARN_ON_USE (wctob, "wctob is unportable - "
278#endif 318#endif
279 319
280 320
281/* Test whether *PS is in the initial state. */ 321/* Test whether *PS is in an initial state. */
282#if @GNULIB_MBSINIT@ 322#if @GNULIB_MBSINIT@
283# if @REPLACE_MBSINIT@ 323# if @REPLACE_MBSINIT@
284# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 324# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -305,6 +345,208 @@ _GL_WARN_ON_USE (mbsinit, "mbsinit is unportable - "
305#endif 345#endif
306 346
307 347
348/* Put *PS into an initial state. */
349#if @GNULIB_MBSZERO@
350/* ISO C 23 § 7.31.6.(3) says that zeroing an mbstate_t is a way to put the
351 mbstate_t into an initial state. However, on many platforms an mbstate_t
352 is large, and it is possible - as an optimization - to get away with zeroing
353 only part of it. So, instead of
354
355 mbstate_t state = { 0 };
356
357 or
358
359 mbstate_t state;
360 memset (&state, 0, sizeof (mbstate_t));
361
362 we can write this faster code:
363
364 mbstate_t state;
365 mbszero (&state);
366 */
367/* _GL_MBSTATE_INIT_SIZE describes how mbsinit() behaves: It is the number of
368 bytes at the beginning of an mbstate_t that need to be zero, for mbsinit()
369 to return true.
370 _GL_MBSTATE_ZERO_SIZE is the number of bytes at the beginning of an mbstate_t
371 that need to be zero,
372 - for mbsinit() to return true, and
373 - for all other multibyte-aware functions to operate properly.
374 0 < _GL_MBSTATE_INIT_SIZE <= _GL_MBSTATE_ZERO_SIZE <= sizeof (mbstate_t).
375 These values are determined by source code inspection, where possible, and
376 by running the gnulib unit tests.
377 We need _GL_MBSTATE_INIT_SIZE because if we define _GL_MBSTATE_ZERO_SIZE
378 without considering what mbsinit() does, we get test failures such as
379 assertion "mbsinit (&iter->state)" failed
380 */
381# if GNULIB_defined_mbstate_t /* AIX, IRIX */
382/* mbstate_t has at least 4 bytes. They are used as coded in
383 gnulib/lib/mbrtowc.c. */
384# define _GL_MBSTATE_INIT_SIZE 1
385/* define _GL_MBSTATE_ZERO_SIZE 4
386 does not work: it causes test failures.
387 So, use the safe fallback value, below. */
388# elif __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2 /* glibc */
389/* mbstate_t is defined in <bits/types/__mbstate_t.h>.
390 For more details, see glibc/iconv/skeleton.c. */
391# define _GL_MBSTATE_INIT_SIZE 4 /* sizeof (((mbstate_t) {0}).__count) */
392# define _GL_MBSTATE_ZERO_SIZE /* 8 */ sizeof (mbstate_t)
393# elif defined MUSL_LIBC /* musl libc */
394/* mbstate_t is defined in <bits/alltypes.h>.
395 It is an opaque aligned 8-byte struct, of which at most the first
396 4 bytes are used.
397 For more details, see src/multibyte/mbrtowc.c. */
398# define _GL_MBSTATE_INIT_SIZE 4 /* sizeof (unsigned) */
399# define _GL_MBSTATE_ZERO_SIZE 4
400# elif defined __APPLE__ && defined __MACH__ /* macOS */
401/* On macOS, mbstate_t is defined in <machine/_types.h>.
402 It is an opaque aligned 128-byte struct, of which at most the first
403 12 bytes are used.
404 For more details, see the __mbsinit implementations in
405 Libc-<version>/locale/FreeBSD/
406 {ascii,none,euc,mskanji,big5,gb2312,gbk,gb18030,utf8,utf2}.c. */
407/* File INIT_SIZE ZERO_SIZE
408 ascii.c 0 0
409 none.c 0 0
410 euc.c 12 12
411 mskanji.c 4 4
412 big5.c 4 4
413 gb2312.c 4 6
414 gbk.c 4 4
415 gb18030.c 4 8
416 utf8.c 8 10
417 utf2.c 8 12 */
418# define _GL_MBSTATE_INIT_SIZE 12
419# define _GL_MBSTATE_ZERO_SIZE 12
420# elif defined __FreeBSD__ /* FreeBSD */
421/* On FreeBSD, mbstate_t is defined in src/sys/sys/_types.h.
422 It is an opaque aligned 128-byte struct, of which at most the first
423 12 bytes are used.
424 For more details, see the __mbsinit implementations in
425 src/lib/libc/locale/
426 {ascii,none,euc,mskanji,big5,gb2312,gbk,gb18030,utf8}.c. */
427/* File INIT_SIZE ZERO_SIZE
428 ascii.c 0 0
429 none.c 0 0
430 euc.c 12 12
431 mskanji.c 4 4
432 big5.c 4 4
433 gb2312.c 4 6
434 gbk.c 4 4
435 gb18030.c 4 8
436 utf8.c 8 12 */
437# define _GL_MBSTATE_INIT_SIZE 12
438# define _GL_MBSTATE_ZERO_SIZE 12
439# elif defined __NetBSD__ /* NetBSD */
440/* On NetBSD, mbstate_t is defined in src/sys/sys/ansi.h.
441 It is an opaque aligned 128-byte struct, of which at most the first
442 28 bytes are used.
443 For more details, see the *State types in
444 src/lib/libc/citrus/modules/citrus_*.c
445 (ignoring citrus_{hz,iso2022,utf7,viqr,zw}.c, since these implement
446 stateful encodings, not usable as locale encodings). */
447/* File ZERO_SIZE
448 citrus/citrus_none.c 0
449 citrus/modules/citrus_euc.c 8
450 citrus/modules/citrus_euctw.c 8
451 citrus/modules/citrus_mskanji.c 8
452 citrus/modules/citrus_big5.c 8
453 citrus/modules/citrus_gbk2k.c 8
454 citrus/modules/citrus_dechanyu.c 8
455 citrus/modules/citrus_johab.c 6
456 citrus/modules/citrus_utf8.c 12 */
457/* But 12 is not the correct value for _GL_MBSTATE_ZERO_SIZE: we get test
458 failures for values < 28. */
459# define _GL_MBSTATE_ZERO_SIZE 28
460# elif defined __OpenBSD__ /* OpenBSD */
461/* On OpenBSD, mbstate_t is defined in src/sys/sys/_types.h.
462 It is an opaque aligned 128-byte struct, of which at most the first
463 12 bytes are used.
464 For more details, see src/lib/libc/citrus/citrus_*.c. */
465/* File INIT_SIZE ZERO_SIZE
466 citrus_none.c 0 0
467 citrus_utf8.c 12 12 */
468# define _GL_MBSTATE_INIT_SIZE 12
469# define _GL_MBSTATE_ZERO_SIZE 12
470# elif defined __minix /* Minix */
471/* On Minix, mbstate_t is defined in sys/sys/ansi.h.
472 It is an opaque aligned 128-byte struct.
473 For more details, see the *State types in
474 lib/libc/citrus/citrus_*.c. */
475/* File INIT_SIZE ZERO_SIZE
476 citrus_none.c 0 0 */
477/* But 1 is not the correct value for _GL_MBSTATE_ZERO_SIZE: we get test
478 failures for values < 4. */
479# define _GL_MBSTATE_ZERO_SIZE 4
480# elif defined __sun /* Solaris */
481/* On Solaris, mbstate_t is defined in <wchar_impl.h>.
482 It is an opaque aligned 24-byte or 32-byte struct, of which at most the first
483 20 or 28 bytes are used.
484 For more details on OpenSolaris derivatives, see the *State types in
485 illumos-gate/usr/src/lib/libc/port/locale/
486 {none,euc,mskanji,big5,gb2312,gbk,gb18030,utf8}.c. */
487/* File INIT_SIZE ZERO_SIZE
488 none.c 0 0
489 euc.c 12 12
490 mskanji.c 4 4
491 big5.c 4 4
492 gb2312.c 4 6
493 gbk.c 4 4
494 gb18030.c 4 8
495 utf8.c 12 12 */
496/* But 12 is not the correct value for _GL_MBSTATE_ZERO_SIZE: we get test
497 failures
498 - in OpenIndiana and OmniOS: for values < 16,
499 - in Solaris 10 and 11: for values < 20 (in 32-bit mode)
500 or < 28 (in 64-bit mode).
501 Since we don't have a good way to distinguish the OpenSolaris derivatives
502 from the proprietary Solaris versions, and can't inspect the Solaris source
503 code, use the safe fallback values, below. */
504# elif defined __CYGWIN__ /* Cygwin */
505/* On Cygwin, mbstate_t is defined in <sys/_types.h>.
506 For more details, see newlib/libc/stdlib/mbtowc_r.c and
507 winsup/cygwin/strfuncs.cc. */
508# define _GL_MBSTATE_INIT_SIZE 4 /* sizeof (int) */
509# define _GL_MBSTATE_ZERO_SIZE 8
510# elif defined _WIN32 && !defined __CYGWIN__ /* Native Windows. */
511/* MSVC defines 'mbstate_t' as an aligned 8-byte struct.
512 On mingw, 'mbstate_t' is sometimes defined as 'int', sometimes defined
513 as an aligned 8-byte struct, of which the first 4 bytes matter.
514 Use the safe values, below. */
515# elif defined __ANDROID__ /* Android */
516/* Android defines 'mbstate_t' in <bits/mbstate_t.h>.
517 It is an opaque 4-byte or 8-byte struct.
518 For more details, see
519 bionic/libc/private/bionic_mbstate.h
520 bionic/libc/bionic/mbrtoc32.cpp
521 bionic/libc/bionic/mbrtoc16.cpp
522 */
523# define _GL_MBSTATE_INIT_SIZE 4
524# define _GL_MBSTATE_ZERO_SIZE 4
525# endif
526/* Use safe values as defaults. */
527# ifndef _GL_MBSTATE_INIT_SIZE
528# define _GL_MBSTATE_INIT_SIZE sizeof (mbstate_t)
529# endif
530# ifndef _GL_MBSTATE_ZERO_SIZE
531# define _GL_MBSTATE_ZERO_SIZE sizeof (mbstate_t)
532# endif
533_GL_BEGIN_C_LINKAGE
534# if defined IN_MBSZERO
535_GL_EXTERN_INLINE
536# else
537_GL_INLINE
538# endif
539_GL_ARG_NONNULL ((1)) void
540mbszero (mbstate_t *ps)
541{
542 memset (ps, 0, _GL_MBSTATE_ZERO_SIZE);
543}
544_GL_END_C_LINKAGE
545_GL_CXXALIAS_SYS (mbszero, void, (mbstate_t *ps));
546_GL_CXXALIASWARN (mbszero);
547#endif
548
549
308/* Convert a multibyte character to a wide character. */ 550/* Convert a multibyte character to a wide character. */
309#if @GNULIB_MBRTOWC@ 551#if @GNULIB_MBRTOWC@
310# if @REPLACE_MBRTOWC@ 552# if @REPLACE_MBRTOWC@
@@ -441,7 +683,9 @@ _GL_CXXALIAS_SYS (mbsnrtowcs, size_t,
441 const char **restrict srcp, size_t srclen, size_t len, 683 const char **restrict srcp, size_t srclen, size_t len,
442 mbstate_t *restrict ps)); 684 mbstate_t *restrict ps));
443# endif 685# endif
686# if __GLIBC__ >= 2
444_GL_CXXALIASWARN (mbsnrtowcs); 687_GL_CXXALIASWARN (mbsnrtowcs);
688# endif
445#elif defined GNULIB_POSIXCHECK 689#elif defined GNULIB_POSIXCHECK
446# undef mbsnrtowcs 690# undef mbsnrtowcs
447# if HAVE_RAW_DECL_MBSNRTOWCS 691# if HAVE_RAW_DECL_MBSNRTOWCS
@@ -629,13 +873,25 @@ _GL_WARN_ON_USE (wmemchr, "wmemchr is unportable - "
629 873
630/* Compare N wide characters of S1 and S2. */ 874/* Compare N wide characters of S1 and S2. */
631#if @GNULIB_WMEMCMP@ 875#if @GNULIB_WMEMCMP@
632# if !@HAVE_WMEMCMP@ 876# if @REPLACE_WMEMCMP@
877# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
878# undef wmemcmp
879# define wmemcmp rpl_wmemcmp
880# endif
881_GL_FUNCDECL_RPL (wmemcmp, int,
882 (const wchar_t *s1, const wchar_t *s2, size_t n)
883 _GL_ATTRIBUTE_PURE);
884_GL_CXXALIAS_RPL (wmemcmp, int,
885 (const wchar_t *s1, const wchar_t *s2, size_t n));
886# else
887# if !@HAVE_WMEMCMP@
633_GL_FUNCDECL_SYS (wmemcmp, int, 888_GL_FUNCDECL_SYS (wmemcmp, int,
634 (const wchar_t *s1, const wchar_t *s2, size_t n) 889 (const wchar_t *s1, const wchar_t *s2, size_t n)
635 _GL_ATTRIBUTE_PURE); 890 _GL_ATTRIBUTE_PURE);
636# endif 891# endif
637_GL_CXXALIAS_SYS (wmemcmp, int, 892_GL_CXXALIAS_SYS (wmemcmp, int,
638 (const wchar_t *s1, const wchar_t *s2, size_t n)); 893 (const wchar_t *s1, const wchar_t *s2, size_t n));
894# endif
639# if __GLIBC__ >= 2 895# if __GLIBC__ >= 2
640_GL_CXXALIASWARN (wmemcmp); 896_GL_CXXALIASWARN (wmemcmp);
641# endif 897# endif
@@ -694,14 +950,27 @@ _GL_WARN_ON_USE (wmemmove, "wmemmove is unportable - "
694/* Copy N wide characters of SRC to DEST. 950/* Copy N wide characters of SRC to DEST.
695 Return pointer to wide characters after the last written wide character. */ 951 Return pointer to wide characters after the last written wide character. */
696#if @GNULIB_WMEMPCPY@ 952#if @GNULIB_WMEMPCPY@
697# if !@HAVE_WMEMPCPY@ 953# if @REPLACE_WMEMPCPY@
954# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
955# undef wmempcpy
956# define wmempcpy rpl_wmempcpy
957# endif
958_GL_FUNCDECL_RPL (wmempcpy, wchar_t *,
959 (wchar_t *restrict dest,
960 const wchar_t *restrict src, size_t n));
961_GL_CXXALIAS_RPL (wmempcpy, wchar_t *,
962 (wchar_t *restrict dest,
963 const wchar_t *restrict src, size_t n));
964# else
965# if !@HAVE_WMEMPCPY@
698_GL_FUNCDECL_SYS (wmempcpy, wchar_t *, 966_GL_FUNCDECL_SYS (wmempcpy, wchar_t *,
699 (wchar_t *restrict dest, 967 (wchar_t *restrict dest,
700 const wchar_t *restrict src, size_t n)); 968 const wchar_t *restrict src, size_t n));
701# endif 969# endif
702_GL_CXXALIAS_SYS (wmempcpy, wchar_t *, 970_GL_CXXALIAS_SYS (wmempcpy, wchar_t *,
703 (wchar_t *restrict dest, 971 (wchar_t *restrict dest,
704 const wchar_t *restrict src, size_t n)); 972 const wchar_t *restrict src, size_t n));
973# endif
705# if __GLIBC__ >= 2 974# if __GLIBC__ >= 2
706_GL_CXXALIASWARN (wmempcpy); 975_GL_CXXALIASWARN (wmempcpy);
707# endif 976# endif
@@ -901,11 +1170,21 @@ _GL_WARN_ON_USE (wcsncat, "wcsncat is unportable - "
901 1170
902/* Compare S1 and S2. */ 1171/* Compare S1 and S2. */
903#if @GNULIB_WCSCMP@ 1172#if @GNULIB_WCSCMP@
904# if !@HAVE_WCSCMP@ 1173# if @REPLACE_WCSCMP@
1174# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1175# undef wcscmp
1176# define wcscmp rpl_wcscmp
1177# endif
1178_GL_FUNCDECL_RPL (wcscmp, int, (const wchar_t *s1, const wchar_t *s2)
1179 _GL_ATTRIBUTE_PURE);
1180_GL_CXXALIAS_RPL (wcscmp, int, (const wchar_t *s1, const wchar_t *s2));
1181# else
1182# if !@HAVE_WCSCMP@
905_GL_FUNCDECL_SYS (wcscmp, int, (const wchar_t *s1, const wchar_t *s2) 1183_GL_FUNCDECL_SYS (wcscmp, int, (const wchar_t *s1, const wchar_t *s2)
906 _GL_ATTRIBUTE_PURE); 1184 _GL_ATTRIBUTE_PURE);
907# endif 1185# endif
908_GL_CXXALIAS_SYS (wcscmp, int, (const wchar_t *s1, const wchar_t *s2)); 1186_GL_CXXALIAS_SYS (wcscmp, int, (const wchar_t *s1, const wchar_t *s2));
1187# endif
909# if __GLIBC__ >= 2 1188# if __GLIBC__ >= 2
910_GL_CXXALIASWARN (wcscmp); 1189_GL_CXXALIASWARN (wcscmp);
911# endif 1190# endif
@@ -920,13 +1199,25 @@ _GL_WARN_ON_USE (wcscmp, "wcscmp is unportable - "
920 1199
921/* Compare no more than N wide characters of S1 and S2. */ 1200/* Compare no more than N wide characters of S1 and S2. */
922#if @GNULIB_WCSNCMP@ 1201#if @GNULIB_WCSNCMP@
923# if !@HAVE_WCSNCMP@ 1202# if @REPLACE_WCSNCMP@
1203# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1204# undef wcsncmp
1205# define wcsncmp rpl_wcsncmp
1206# endif
1207_GL_FUNCDECL_RPL (wcsncmp, int,
1208 (const wchar_t *s1, const wchar_t *s2, size_t n)
1209 _GL_ATTRIBUTE_PURE);
1210_GL_CXXALIAS_RPL (wcsncmp, int,
1211 (const wchar_t *s1, const wchar_t *s2, size_t n));
1212# else
1213# if !@HAVE_WCSNCMP@
924_GL_FUNCDECL_SYS (wcsncmp, int, 1214_GL_FUNCDECL_SYS (wcsncmp, int,
925 (const wchar_t *s1, const wchar_t *s2, size_t n) 1215 (const wchar_t *s1, const wchar_t *s2, size_t n)
926 _GL_ATTRIBUTE_PURE); 1216 _GL_ATTRIBUTE_PURE);
927# endif 1217# endif
928_GL_CXXALIAS_SYS (wcsncmp, int, 1218_GL_CXXALIAS_SYS (wcsncmp, int,
929 (const wchar_t *s1, const wchar_t *s2, size_t n)); 1219 (const wchar_t *s1, const wchar_t *s2, size_t n));
1220# endif
930# if __GLIBC__ >= 2 1221# if __GLIBC__ >= 2
931_GL_CXXALIASWARN (wcsncmp); 1222_GL_CXXALIASWARN (wcsncmp);
932# endif 1223# endif
@@ -1035,9 +1326,16 @@ _GL_CXXALIAS_MDA (wcsdup, wchar_t *, (const wchar_t *s));
1035 namespace, not in the global namespace. So, force a declaration in 1326 namespace, not in the global namespace. So, force a declaration in
1036 the global namespace. */ 1327 the global namespace. */
1037# if !@HAVE_WCSDUP@ || (defined __sun && defined __cplusplus) || __GNUC__ >= 11 1328# if !@HAVE_WCSDUP@ || (defined __sun && defined __cplusplus) || __GNUC__ >= 11
1329# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
1330_GL_FUNCDECL_SYS (wcsdup, wchar_t *,
1331 (const wchar_t *s)
1332 _GL_ATTRIBUTE_NOTHROW
1333 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
1334# else
1038_GL_FUNCDECL_SYS (wcsdup, wchar_t *, 1335_GL_FUNCDECL_SYS (wcsdup, wchar_t *,
1039 (const wchar_t *s) 1336 (const wchar_t *s)
1040 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 1337 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
1338# endif
1041# endif 1339# endif
1042_GL_CXXALIAS_SYS (wcsdup, wchar_t *, (const wchar_t *s)); 1340_GL_CXXALIAS_SYS (wcsdup, wchar_t *, (const wchar_t *s));
1043# endif 1341# endif
@@ -1045,9 +1343,16 @@ _GL_CXXALIASWARN (wcsdup);
1045#else 1343#else
1046# if __GNUC__ >= 11 && !defined wcsdup 1344# if __GNUC__ >= 11 && !defined wcsdup
1047/* For -Wmismatched-dealloc: Associate wcsdup with free or rpl_free. */ 1345/* For -Wmismatched-dealloc: Associate wcsdup with free or rpl_free. */
1346# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
1048_GL_FUNCDECL_SYS (wcsdup, wchar_t *, 1347_GL_FUNCDECL_SYS (wcsdup, wchar_t *,
1049 (const wchar_t *s) 1348 (const wchar_t *s)
1349 _GL_ATTRIBUTE_NOTHROW
1050 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 1350 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
1351# else
1352_GL_FUNCDECL_SYS (wcsdup, wchar_t *,
1353 (const wchar_t *s)
1354 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
1355# endif
1051# endif 1356# endif
1052# if defined GNULIB_POSIXCHECK 1357# if defined GNULIB_POSIXCHECK
1053# undef wcsdup 1358# undef wcsdup
@@ -1066,9 +1371,16 @@ _GL_WARN_ON_USE (wcsdup, "wcsdup is unportable - "
1066# endif 1371# endif
1067_GL_CXXALIAS_MDA (wcsdup, wchar_t *, (const wchar_t *s)); 1372_GL_CXXALIAS_MDA (wcsdup, wchar_t *, (const wchar_t *s));
1068# else 1373# else
1374# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
1069_GL_FUNCDECL_SYS (wcsdup, wchar_t *, 1375_GL_FUNCDECL_SYS (wcsdup, wchar_t *,
1070 (const wchar_t *s) 1376 (const wchar_t *s)
1377 _GL_ATTRIBUTE_NOTHROW
1071 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE); 1378 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
1379# else
1380_GL_FUNCDECL_SYS (wcsdup, wchar_t *,
1381 (const wchar_t *s)
1382 _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
1383# endif
1072# if @HAVE_DECL_WCSDUP@ 1384# if @HAVE_DECL_WCSDUP@
1073_GL_CXXALIAS_SYS (wcsdup, wchar_t *, (const wchar_t *s)); 1385_GL_CXXALIAS_SYS (wcsdup, wchar_t *, (const wchar_t *s));
1074# endif 1386# endif
@@ -1140,7 +1452,7 @@ _GL_WARN_ON_USE (wcsrchr, "wcsrchr is unportable - "
1140#endif 1452#endif
1141 1453
1142 1454
1143/* Return the length of the initial segmet of WCS which consists entirely 1455/* Return the length of the initial segment of WCS which consists entirely
1144 of wide characters not in REJECT. */ 1456 of wide characters not in REJECT. */
1145#if @GNULIB_WCSCSPN@ 1457#if @GNULIB_WCSCSPN@
1146# if !@HAVE_WCSCSPN@ 1458# if !@HAVE_WCSCSPN@
@@ -1160,7 +1472,7 @@ _GL_WARN_ON_USE (wcscspn, "wcscspn is unportable - "
1160#endif 1472#endif
1161 1473
1162 1474
1163/* Return the length of the initial segmet of WCS which consists entirely 1475/* Return the length of the initial segment of WCS which consists entirely
1164 of wide characters in ACCEPT. */ 1476 of wide characters in ACCEPT. */
1165#if @GNULIB_WCSSPN@ 1477#if @GNULIB_WCSSPN@
1166# if !@HAVE_WCSSPN@ 1478# if !@HAVE_WCSSPN@
@@ -1215,12 +1527,25 @@ _GL_WARN_ON_USE (wcspbrk, "wcspbrk is unportable - "
1215 1527
1216/* Find the first occurrence of NEEDLE in HAYSTACK. */ 1528/* Find the first occurrence of NEEDLE in HAYSTACK. */
1217#if @GNULIB_WCSSTR@ 1529#if @GNULIB_WCSSTR@
1218# if !@HAVE_WCSSTR@ 1530# if @REPLACE_WCSSTR@
1531# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
1532# undef wcsstr
1533# define wcsstr rpl_wcsstr
1534# endif
1535_GL_FUNCDECL_RPL (wcsstr, wchar_t *,
1536 (const wchar_t *restrict haystack,
1537 const wchar_t *restrict needle)
1538 _GL_ATTRIBUTE_PURE);
1539_GL_CXXALIAS_RPL (wcsstr, wchar_t *,
1540 (const wchar_t *restrict haystack,
1541 const wchar_t *restrict needle));
1542# else
1543# if !@HAVE_WCSSTR@
1219_GL_FUNCDECL_SYS (wcsstr, wchar_t *, 1544_GL_FUNCDECL_SYS (wcsstr, wchar_t *,
1220 (const wchar_t *restrict haystack, 1545 (const wchar_t *restrict haystack,
1221 const wchar_t *restrict needle) 1546 const wchar_t *restrict needle)
1222 _GL_ATTRIBUTE_PURE); 1547 _GL_ATTRIBUTE_PURE);
1223# endif 1548# endif
1224 /* On some systems, this function is defined as an overloaded function: 1549 /* On some systems, this function is defined as an overloaded function:
1225 extern "C++" { 1550 extern "C++" {
1226 const wchar_t * std::wcsstr (const wchar_t *, const wchar_t *); 1551 const wchar_t * std::wcsstr (const wchar_t *, const wchar_t *);
@@ -1231,6 +1556,7 @@ _GL_CXXALIAS_SYS_CAST2 (wcsstr,
1231 (const wchar_t *restrict, const wchar_t *restrict), 1556 (const wchar_t *restrict, const wchar_t *restrict),
1232 const wchar_t *, 1557 const wchar_t *,
1233 (const wchar_t *restrict, const wchar_t *restrict)); 1558 (const wchar_t *restrict, const wchar_t *restrict));
1559# endif
1234# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \ 1560# if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 10) && !defined __UCLIBC__) \
1235 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) 1561 && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4))
1236_GL_CXXALIASWARN1 (wcsstr, wchar_t *, 1562_GL_CXXALIASWARN1 (wcsstr, wchar_t *,
@@ -1358,6 +1684,24 @@ _GL_WARN_ON_USE (wcsftime, "wcsftime is unportable - "
1358#endif 1684#endif
1359 1685
1360 1686
1687#if @GNULIB_WGETCWD@ && (defined _WIN32 && !defined __CYGWIN__)
1688/* Gets the name of the current working directory.
1689 (a) If BUF is non-NULL, it is assumed to have room for SIZE wide characters.
1690 This function stores the working directory (NUL-terminated) in BUF and
1691 returns BUF.
1692 (b) If BUF is NULL, an array is allocated with 'malloc'. The array is SIZE
1693 wide characters long, unless SIZE == 0, in which case it is as big as
1694 necessary.
1695 If the directory couldn't be determined or SIZE was too small, this function
1696 returns NULL and sets errno. For a directory of length LEN, SIZE should be
1697 >= LEN + 3 in case (a) or >= LEN + 1 in case (b).
1698 Possible errno values include:
1699 - ERANGE if SIZE is too small.
1700 - ENOMEM if the memory could no be allocated. */
1701_GL_FUNCDECL_SYS (wgetcwd, wchar_t *, (wchar_t *buf, size_t size));
1702#endif
1703
1704
1361#endif /* _@GUARD_PREFIX@_WCHAR_H */ 1705#endif /* _@GUARD_PREFIX@_WCHAR_H */
1362#endif /* _@GUARD_PREFIX@_WCHAR_H */ 1706#endif /* _@GUARD_PREFIX@_WCHAR_H */
1363#endif 1707#endif
diff --git a/gl/wcrtomb.c b/gl/wcrtomb.c
index 48a6c8eb..197b020e 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2008-2024 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
@@ -29,7 +29,7 @@ wcrtomb (char *s, wchar_t wc, mbstate_t *ps)
29#undef wcrtomb 29#undef wcrtomb
30{ 30{
31 /* This implementation of wcrtomb supports only stateless encodings. 31 /* This implementation of wcrtomb supports only stateless encodings.
32 ps must be in the initial state. */ 32 ps must be in an initial state. */
33 if (ps != NULL && !mbsinit (ps)) 33 if (ps != NULL && !mbsinit (ps))
34 { 34 {
35 errno = EINVAL; 35 errno = EINVAL;
diff --git a/gl/wctype-h.c b/gl/wctype-h.c
index 7d3e14a6..7e4ff13a 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2012-2024 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,4 +20,4 @@
20#include <config.h> 20#include <config.h>
21 21
22#define _GL_WCTYPE_INLINE _GL_EXTERN_INLINE 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
new file mode 100644
index 00000000..26d68b41
--- /dev/null
+++ b/gl/wctype-impl.h
@@ -0,0 +1,96 @@
1/* Get descriptor for a wide character property.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2011.
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
18wctype_t
19wctype (const char* name)
20{
21 switch (name[0])
22 {
23 case 'a':
24 switch (name[1])
25 {
26 case 'l':
27 switch (name[2])
28 {
29 case 'n':
30 if (strcmp (name + 3, "um") == 0)
31 return (wctype_t) iswalnum;
32 break;
33 case 'p':
34 if (strcmp (name + 3, "ha") == 0)
35 return (wctype_t) iswalpha;
36 break;
37 default:
38 break;
39 }
40 break;
41 default:
42 break;
43 }
44 break;
45 case 'b':
46 if (strcmp (name + 1, "lank") == 0)
47 return (wctype_t) iswblank;
48 break;
49 case 'c':
50 if (strcmp (name + 1, "ntrl") == 0)
51 return (wctype_t) iswcntrl;
52 break;
53 case 'd':
54 if (strcmp (name + 1, "igit") == 0)
55 return (wctype_t) iswdigit;
56 break;
57 case 'g':
58 if (strcmp (name + 1, "raph") == 0)
59 return (wctype_t) iswgraph;
60 break;
61 case 'l':
62 if (strcmp (name + 1, "ower") == 0)
63 return (wctype_t) iswlower;
64 break;
65 case 'p':
66 switch (name[1])
67 {
68 case 'r':
69 if (strcmp (name + 2, "int") == 0)
70 return (wctype_t) iswprint;
71 break;
72 case 'u':
73 if (strcmp (name + 2, "nct") == 0)
74 return (wctype_t) iswpunct;
75 break;
76 default:
77 break;
78 }
79 break;
80 case 's':
81 if (strcmp (name + 1, "pace") == 0)
82 return (wctype_t) iswspace;
83 break;
84 case 'u':
85 if (strcmp (name + 1, "pper") == 0)
86 return (wctype_t) iswupper;
87 break;
88 case 'x':
89 if (strcmp (name + 1, "digit") == 0)
90 return (wctype_t) iswxdigit;
91 break;
92 default:
93 break;
94 }
95 return NULL;
96}
diff --git a/gl/wctype.c b/gl/wctype.c
new file mode 100644
index 00000000..914f6847
--- /dev/null
+++ b/gl/wctype.c
@@ -0,0 +1,25 @@
1/* Get descriptor for a wide character property.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2011.
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 <wctype.h>
22
23#include <string.h>
24
25#include "wctype-impl.h"
diff --git a/gl/wctype.in.h b/gl/wctype.in.h
index f6e474d3..851c4f4e 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2006-2024 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
@@ -44,6 +44,12 @@
44 44
45#ifndef _@GUARD_PREFIX@_WCTYPE_H 45#ifndef _@GUARD_PREFIX@_WCTYPE_H
46 46
47/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE, GNULIB_POSIXCHECK,
48 HAVE_RAW_DECL_*. */
49#if !_GL_CONFIG_H_INCLUDED
50 #error "Please include config.h first."
51#endif
52
47#if @HAVE_WINT_T@ 53#if @HAVE_WINT_T@
48/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */ 54/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
49# include <wchar.h> 55# include <wchar.h>
@@ -68,9 +74,6 @@
68#ifndef _@GUARD_PREFIX@_WCTYPE_H 74#ifndef _@GUARD_PREFIX@_WCTYPE_H
69#define _@GUARD_PREFIX@_WCTYPE_H 75#define _@GUARD_PREFIX@_WCTYPE_H
70 76
71#ifndef _GL_INLINE_HEADER_BEGIN
72 #error "Please include config.h first."
73#endif
74_GL_INLINE_HEADER_BEGIN 77_GL_INLINE_HEADER_BEGIN
75#ifndef _GL_WCTYPE_INLINE 78#ifndef _GL_WCTYPE_INLINE
76# define _GL_WCTYPE_INLINE _GL_INLINE 79# define _GL_WCTYPE_INLINE _GL_INLINE
@@ -78,6 +81,8 @@ _GL_INLINE_HEADER_BEGIN
78 81
79/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ 82/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
80 83
84/* The definition of _GL_ARG_NONNULL is copied here. */
85
81/* The definition of _GL_WARN_ON_USE is copied here. */ 86/* The definition of _GL_WARN_ON_USE is copied here. */
82 87
83/* Solaris 2.6 <wctype.h> includes <widec.h> which includes <euc.h> which 88/* Solaris 2.6 <wctype.h> includes <widec.h> which includes <euc.h> which
@@ -127,7 +132,8 @@ typedef unsigned int rpl_wint_t;
127/* FreeBSD 4.4 to 4.11 has <wctype.h> but lacks the functions. 132/* FreeBSD 4.4 to 4.11 has <wctype.h> but lacks the functions.
128 Linux libc5 has <wctype.h> and the functions but they are broken. 133 Linux libc5 has <wctype.h> and the functions but they are broken.
129 mingw and MSVC have <wctype.h> and the functions but they take a wchar_t 134 mingw and MSVC have <wctype.h> and the functions but they take a wchar_t
130 as argument, not an rpl_wint_t. 135 as argument, not an rpl_wint_t. Additionally, the mingw iswprint function
136 and the Android iswpunct function are broken.
131 Assume all 11 functions (all isw* except iswblank) are implemented the 137 Assume all 11 functions (all isw* except iswblank) are implemented the
132 same way, or not at all. */ 138 same way, or not at all. */
133# if ! @HAVE_ISWCNTRL@ || @REPLACE_ISWCNTRL@ 139# if ! @HAVE_ISWCNTRL@ || @REPLACE_ISWCNTRL@
@@ -179,7 +185,11 @@ rpl_iswlower (wint_t wc)
179_GL_WCTYPE_INLINE int 185_GL_WCTYPE_INLINE int
180rpl_iswprint (wint_t wc) 186rpl_iswprint (wint_t wc)
181{ 187{
188# ifdef __MINGW32__
189 return ((wchar_t) wc == wc ? wc == ' ' || iswgraph ((wchar_t) wc) : 0);
190# else
182 return ((wchar_t) wc == wc ? iswprint ((wchar_t) wc) : 0); 191 return ((wchar_t) wc == wc ? iswprint ((wchar_t) wc) : 0);
192# endif
183} 193}
184 194
185_GL_WCTYPE_INLINE int 195_GL_WCTYPE_INLINE int
@@ -484,6 +494,16 @@ _GL_FUNCDECL_RPL (iswdigit, int, (wint_t wc));
484# endif 494# endif
485# endif 495# endif
486 496
497# if @GNULIB_ISWPUNCT@
498# if @REPLACE_ISWPUNCT@
499# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
500# undef iswpunct
501# define iswpunct rpl_iswpunct
502# endif
503_GL_FUNCDECL_RPL (iswpunct, int, (wint_t wc));
504# endif
505# endif
506
487# if @GNULIB_ISWXDIGIT@ 507# if @GNULIB_ISWXDIGIT@
488# if @REPLACE_ISWXDIGIT@ 508# if @REPLACE_ISWXDIGIT@
489# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 509# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -623,14 +643,32 @@ _GL_CXXALIASWARN (iswblank);
623typedef void * wctype_t; 643typedef void * wctype_t;
624# define GNULIB_defined_wctype_t 1 644# define GNULIB_defined_wctype_t 1
625# endif 645# endif
646#elif @REPLACE_WCTYPE@
647# if !GNULIB_defined_wctype_t
648typedef void *rpl_wctype_t;
649# undef wctype_t
650# define wctype_t rpl_wctype_t
651# define GNULIB_defined_wctype_t 1
652# endif
626#endif 653#endif
627 654
628/* Get a descriptor for a wide character property. */ 655/* Get a descriptor for a wide character property. */
629#if @GNULIB_WCTYPE@ 656#if @GNULIB_WCTYPE@
630# if !@HAVE_WCTYPE_T@ 657# if @REPLACE_WCTYPE@
631_GL_FUNCDECL_SYS (wctype, wctype_t, (const char *name)); 658# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
632# endif 659# undef wctype
660# define wctype rpl_wctype
661# endif
662_GL_FUNCDECL_RPL (wctype, wctype_t, (const char *name)
663 _GL_ARG_NONNULL ((1)));
664_GL_CXXALIAS_RPL (wctype, wctype_t, (const char *name));
665# else
666# if !@HAVE_WCTYPE_T@
667_GL_FUNCDECL_SYS (wctype, wctype_t, (const char *name)
668 _GL_ARG_NONNULL ((1)));
669# endif
633_GL_CXXALIAS_SYS (wctype, wctype_t, (const char *name)); 670_GL_CXXALIAS_SYS (wctype, wctype_t, (const char *name));
671# endif
634# if __GLIBC__ >= 2 672# if __GLIBC__ >= 2
635_GL_CXXALIASWARN (wctype); 673_GL_CXXALIASWARN (wctype);
636# endif 674# endif
@@ -646,7 +684,7 @@ _GL_WARN_ON_USE (wctype, "wctype is unportable - "
646 The argument WC must be either a wchar_t value or WEOF. 684 The argument WC must be either a wchar_t value or WEOF.
647 The argument DESC must have been returned by the wctype() function. */ 685 The argument DESC must have been returned by the wctype() function. */
648#if @GNULIB_ISWCTYPE@ 686#if @GNULIB_ISWCTYPE@
649# if @GNULIBHEADERS_OVERRIDE_WINT_T@ 687# if @GNULIBHEADERS_OVERRIDE_WINT_T@ || @REPLACE_WCTYPE@
650# if !(defined __cplusplus && defined GNULIB_NAMESPACE) 688# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
651# undef iswctype 689# undef iswctype
652# define iswctype rpl_iswctype 690# define iswctype rpl_iswctype
@@ -687,14 +725,32 @@ _GL_CXXALIASWARN (towupper);
687typedef void * wctrans_t; 725typedef void * wctrans_t;
688# define GNULIB_defined_wctrans_t 1 726# define GNULIB_defined_wctrans_t 1
689# endif 727# endif
728#elif @REPLACE_WCTRANS@
729# if !GNULIB_defined_wctrans_t
730typedef void *rpl_wctrans_t;
731# undef wctrans_t
732# define wctrans_t rpl_wctrans_t
733# define GNULIB_defined_wctrans_t 1
734# endif
690#endif 735#endif
691 736
692/* Get a descriptor for a wide character case conversion. */ 737/* Get a descriptor for a wide character case conversion. */
693#if @GNULIB_WCTRANS@ 738#if @GNULIB_WCTRANS@
694# if !@HAVE_WCTRANS_T@ 739# if @REPLACE_WCTRANS@
695_GL_FUNCDECL_SYS (wctrans, wctrans_t, (const char *name)); 740# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
696# endif 741# undef wctrans
742# define wctrans rpl_wctrans
743# endif
744_GL_FUNCDECL_RPL (wctrans, wctrans_t, (const char *name)
745 _GL_ARG_NONNULL ((1)));
746_GL_CXXALIAS_RPL (wctrans, wctrans_t, (const char *name));
747# else
748# if !@HAVE_WCTRANS_T@
749_GL_FUNCDECL_SYS (wctrans, wctrans_t, (const char *name)
750 _GL_ARG_NONNULL ((1)));
751# endif
697_GL_CXXALIAS_SYS (wctrans, wctrans_t, (const char *name)); 752_GL_CXXALIAS_SYS (wctrans, wctrans_t, (const char *name));
753# endif
698# if __GLIBC__ >= 2 754# if __GLIBC__ >= 2
699_GL_CXXALIASWARN (wctrans); 755_GL_CXXALIASWARN (wctrans);
700# endif 756# endif
@@ -710,10 +766,19 @@ _GL_WARN_ON_USE (wctrans, "wctrans is unportable - "
710 The argument WC must be either a wchar_t value or WEOF. 766 The argument WC must be either a wchar_t value or WEOF.
711 The argument DESC must have been returned by the wctrans() function. */ 767 The argument DESC must have been returned by the wctrans() function. */
712#if @GNULIB_TOWCTRANS@ 768#if @GNULIB_TOWCTRANS@
713# if !@HAVE_WCTRANS_T@ 769# if @REPLACE_WCTRANS@
770# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
771# undef towctrans
772# define towctrans rpl_towctrans
773# endif
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));
776# else
777# if !@HAVE_WCTRANS_T@
714_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));
715# endif 779# endif
716_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
717# if __GLIBC__ >= 2 782# if __GLIBC__ >= 2
718_GL_CXXALIASWARN (towctrans); 783_GL_CXXALIASWARN (towctrans);
719# endif 784# endif
diff --git a/gl/windows-initguard.h b/gl/windows-initguard.h
index 9d36f53c..6bace3f0 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2005-2024 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 ab7258c9..b112e13b 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2005-2024 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.h b/gl/windows-mutex.h
index 039eb707..88de4bdc 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2005-2024 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-once.c b/gl/windows-once.c
index 0d28281f..17854f5c 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2005-2024 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-once.h b/gl/windows-once.h
index 54885680..c5bbcd57 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2005-2024 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.c b/gl/windows-recmutex.c
index a8ce9a04..e5672baf 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2005-2024 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 08ff4597..9fa445b3 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2005-2024 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 7cbd7bb1..e60c4efc 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2005-2024 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 fe8381e8..08d67750 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-2023 Free Software Foundation, Inc. 2 Copyright (C) 2005-2024 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 7605eee1..c053c7a8 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-2023 Free Software 3 Copyright (C) 1997-2000, 2002-2004, 2006, 2009-2024 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
@@ -22,7 +22,7 @@
22 22
23#include <stdlib.h> 23#include <stdlib.h>
24 24
25#include "error.h" 25#include <error.h>
26#include "exitfail.h" 26#include "exitfail.h"
27 27
28#include "gettext.h" 28#include "gettext.h"
diff --git a/gl/xalloc-oversized.h b/gl/xalloc-oversized.h
index 5dbdfb55..7f30f83e 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 1990-2000, 2003-2004, 2006-2024 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 is SIZE_MAX - 1. */ 29 is SIZE_MAX - 1. */
30#define __xalloc_oversized(n, s) \ 30#define __xalloc_oversized(n, s) \
31 ((s) != 0 \ 31 ((s) != 0 \
32 && ((size_t) (PTRDIFF_MAX < SIZE_MAX ? PTRDIFF_MAX : SIZE_MAX - 1) / (s) \ 32 && (PTRDIFF_MAX < SIZE_MAX ? PTRDIFF_MAX : SIZE_MAX - 1) / (s) < (n))
33 < (n)))
34 33
35/* Return 1 if and only if an array of N objects, each of size S, 34/* Return 1 if and only if an array of N objects, each of size S,
36 cannot exist reliably because its total size in bytes would exceed 35 cannot exist reliably because its total size in bytes would exceed
@@ -48,13 +47,13 @@
48#if 7 <= __GNUC__ && !defined __clang__ && PTRDIFF_MAX < SIZE_MAX 47#if 7 <= __GNUC__ && !defined __clang__ && PTRDIFF_MAX < SIZE_MAX
49# define xalloc_oversized(n, s) \ 48# define xalloc_oversized(n, s) \
50 __builtin_mul_overflow_p (n, s, (ptrdiff_t) 1) 49 __builtin_mul_overflow_p (n, s, (ptrdiff_t) 1)
51#elif (5 <= __GNUC__ && !defined __ICC && !__STRICT_ANSI__ \ 50#elif 5 <= __GNUC__ && !defined __ICC && PTRDIFF_MAX < SIZE_MAX
52 && PTRDIFF_MAX < SIZE_MAX)
53# define xalloc_oversized(n, s) \ 51# define xalloc_oversized(n, s) \
54 (__builtin_constant_p (n) && __builtin_constant_p (s) \ 52 (__builtin_constant_p (n) && __builtin_constant_p (s) \
55 ? __xalloc_oversized (n, s) \ 53 ? __xalloc_oversized (n, s) \
56 : ({ ptrdiff_t __xalloc_count; \ 54 : __extension__ \
57 __builtin_mul_overflow (n, s, &__xalloc_count); })) 55 ({ ptrdiff_t __xalloc_count; \
56 __builtin_mul_overflow (n, s, &__xalloc_count); }))
58 57
59/* Other compilers use integer division; this may be slower but is 58/* Other compilers use integer division; this may be slower but is
60 more portable. */ 59 more portable. */
diff --git a/gl/xalloc.h b/gl/xalloc.h
index f373c2fe..75a5db30 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 1990-2000, 2003-2004, 2006-2024 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
@@ -18,6 +18,13 @@
18#ifndef XALLOC_H_ 18#ifndef XALLOC_H_
19#define XALLOC_H_ 19#define XALLOC_H_
20 20
21/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE, _Noreturn,
22 _GL_ATTRIBUTE_ALLOC_SIZE, _GL_ATTRIBUTE_MALLOC,
23 _GL_ATTRIBUTE_RETURNS_NONNULL. */
24#if !_GL_CONFIG_H_INCLUDED
25 #error "Please include config.h first."
26#endif
27
21#include <stddef.h> 28#include <stddef.h>
22#include <stdlib.h> 29#include <stdlib.h>
23 30
@@ -25,9 +32,6 @@
25# include "idx.h" 32# include "idx.h"
26#endif 33#endif
27 34
28#ifndef _GL_INLINE_HEADER_BEGIN
29 #error "Please include config.h first."
30#endif
31_GL_INLINE_HEADER_BEGIN 35_GL_INLINE_HEADER_BEGIN
32#ifndef XALLOC_INLINE 36#ifndef XALLOC_INLINE
33# define XALLOC_INLINE _GL_INLINE 37# define XALLOC_INLINE _GL_INLINE
@@ -46,7 +50,7 @@ extern "C" {
46 or by using gnulib's xalloc-die module. This is the 50 or by using gnulib's xalloc-die module. This is the
47 function to call when one wants the program to die because of a 51 function to call when one wants the program to die because of a
48 memory allocation failure. */ 52 memory allocation failure. */
49/*extern*/ _Noreturn void xalloc_die (void); 53_Noreturn void xalloc_die (void);
50 54
51#endif /* GNULIB_XALLOC_DIE */ 55#endif /* GNULIB_XALLOC_DIE */
52 56
diff --git a/gl/xmalloc.c b/gl/xmalloc.c
index 289cbd05..5befdab7 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 1990-2000, 2002-2006, 2008-2024 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
@@ -30,7 +30,7 @@
30#include <string.h> 30#include <string.h>
31 31
32static void * _GL_ATTRIBUTE_PURE 32static void * _GL_ATTRIBUTE_PURE
33nonnull (void *p) 33check_nonnull (void *p)
34{ 34{
35 if (!p) 35 if (!p)
36 xalloc_die (); 36 xalloc_die ();
@@ -42,13 +42,13 @@ nonnull (void *p)
42void * 42void *
43xmalloc (size_t s) 43xmalloc (size_t s)
44{ 44{
45 return nonnull (malloc (s)); 45 return check_nonnull (malloc (s));
46} 46}
47 47
48void * 48void *
49ximalloc (idx_t s) 49ximalloc (idx_t s)
50{ 50{
51 return nonnull (imalloc (s)); 51 return check_nonnull (imalloc (s));
52} 52}
53 53
54char * 54char *
@@ -72,7 +72,7 @@ xrealloc (void *p, size_t s)
72void * 72void *
73xirealloc (void *p, idx_t s) 73xirealloc (void *p, idx_t s)
74{ 74{
75 return nonnull (irealloc (p, s)); 75 return check_nonnull (irealloc (p, s));
76} 76}
77 77
78/* Change the size of an allocated block of memory P to an array of N 78/* Change the size of an allocated block of memory P to an array of N
@@ -90,7 +90,7 @@ xreallocarray (void *p, size_t n, size_t s)
90void * 90void *
91xireallocarray (void *p, idx_t n, idx_t s) 91xireallocarray (void *p, idx_t n, idx_t s)
92{ 92{
93 return nonnull (ireallocarray (p, n, s)); 93 return check_nonnull (ireallocarray (p, n, s));
94} 94}
95 95
96/* Allocate an array of N objects, each with S bytes of memory, 96/* Allocate an array of N objects, each with S bytes of memory,
@@ -295,13 +295,13 @@ xizalloc (idx_t s)
295void * 295void *
296xcalloc (size_t n, size_t s) 296xcalloc (size_t n, size_t s)
297{ 297{
298 return nonnull (calloc (n, s)); 298 return check_nonnull (calloc (n, s));
299} 299}
300 300
301void * 301void *
302xicalloc (idx_t n, idx_t s) 302xicalloc (idx_t n, idx_t s)
303{ 303{
304 return nonnull (icalloc (n, s)); 304 return check_nonnull (icalloc (n, s));
305} 305}
306 306
307/* Clone an object P of size S, with error checking. There's no need 307/* Clone an object P of size S, with error checking. There's no need
diff --git a/gl/xsize.c b/gl/xsize.c
index 279ae824..87744675 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2012-2024 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 1ec78e77..619c0edc 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-2023 Free Software Foundation, Inc. 3 Copyright (C) 2003, 2008-2024 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
@@ -18,6 +18,11 @@
18#ifndef _XSIZE_H 18#ifndef _XSIZE_H
19#define _XSIZE_H 19#define _XSIZE_H
20 20
21/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE, HAVE_STDINT_H. */
22#if !_GL_CONFIG_H_INCLUDED
23 #error "Please include config.h first."
24#endif
25
21/* Get size_t. */ 26/* Get size_t. */
22#include <stddef.h> 27#include <stddef.h>
23 28
@@ -30,14 +35,16 @@
30/* Get ATTRIBUTE_PURE. */ 35/* Get ATTRIBUTE_PURE. */
31#include "attribute.h" 36#include "attribute.h"
32 37
33#ifndef _GL_INLINE_HEADER_BEGIN
34 #error "Please include config.h first."
35#endif
36_GL_INLINE_HEADER_BEGIN 38_GL_INLINE_HEADER_BEGIN
37#ifndef XSIZE_INLINE 39#ifndef XSIZE_INLINE
38# define XSIZE_INLINE _GL_INLINE 40# define XSIZE_INLINE _GL_INLINE
39#endif 41#endif
40 42
43#ifdef __cplusplus
44extern "C" {
45#endif
46
47
41/* The size of memory objects is often computed through expressions of 48/* The size of memory objects is often computed through expressions of
42 type size_t. Example: 49 type size_t. Example:
43 void* p = malloc (header_size + n * element_size). 50 void* p = malloc (header_size + n * element_size).
@@ -103,6 +110,11 @@ xmax (size_t size1, size_t size2)
103#define size_in_bounds_p(SIZE) \ 110#define size_in_bounds_p(SIZE) \
104 ((SIZE) != SIZE_MAX) 111 ((SIZE) != SIZE_MAX)
105 112
113
114#ifdef __cplusplus
115}
116#endif
117
106_GL_INLINE_HEADER_END 118_GL_INLINE_HEADER_END
107 119
108#endif /* _XSIZE_H */ 120#endif /* _XSIZE_H */
diff --git a/lib/Makefile.am b/lib/Makefile.am
index dc3ee893..a9f3ff40 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -7,8 +7,20 @@ noinst_LIBRARIES = libmonitoringplug.a
7AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \ 7AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \
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 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
11EXTRA_DIST = utils_base.h utils_disk.h utils_tcp.h utils_cmd.h parse_ini.h extra_opts.h maxfd.h 11
12EXTRA_DIST = utils_base.h \
13 utils_tcp.h \
14 utils_cmd.h \
15 parse_ini.h \
16 extra_opts.h \
17 maxfd.h \
18 perfdata.h \
19 output.h \
20 thresholds.h \
21 states.h \
22 vendor/cJSON/cJSON.h \
23 monitoringplug.h
12 24
13if USE_PARSE_INI 25if USE_PARSE_INI
14libmonitoringplug_a_SOURCES += parse_ini.c extra_opts.c 26libmonitoringplug_a_SOURCES += parse_ini.c extra_opts.c
@@ -16,4 +28,3 @@ endif USE_PARSE_INI
16 28
17test test-debug: 29test test-debug:
18 cd tests && make $@ 30 cd tests && make $@
19
diff --git a/lib/extra_opts.c b/lib/extra_opts.c
index 771621d8..88787336 100644
--- a/lib/extra_opts.c
+++ b/lib/extra_opts.c
@@ -1,24 +1,24 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring Plugins extra_opts library 3 * Monitoring Plugins extra_opts library
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2007 Monitoring Plugins Development Team 6 * Copyright (c) 2007 - 2024 Monitoring Plugins Development Team
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#include "common.h" 23#include "common.h"
24#include "utils_base.h" 24#include "utils_base.h"
@@ -26,110 +26,115 @@
26#include "extra_opts.h" 26#include "extra_opts.h"
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{
31 if (!str) 30 if (!str)
32 return false; 31 return false;
33 else if (strspn (str, "-") == 1 || strspn (str, "-") == 2) 32 else if (strspn(str, "-") == 1 || strspn(str, "-") == 2)
34 return true; 33 return true;
35 else 34 else
36 return false; 35 return false;
37} 36}
38 37
39/* this is the externally visible function used by plugins */ 38/* this is the externally visible function used by plugins */
40char **np_extra_opts(int *argc, char **argv, const char *plugin_name){ 39char **np_extra_opts(int *argc, char **argv, const char *plugin_name) {
41 np_arg_list *extra_args=NULL, *ea1=NULL, *ea_tmp=NULL; 40 np_arg_list *extra_args = NULL, *ea1 = NULL, *ea_tmp = NULL;
42 char **argv_new=NULL; 41 char **argv_new = NULL;
43 char *argptr=NULL; 42 char *argptr = NULL;
44 int i, j, optfound, argc_new, ea_num=*argc; 43 int i, j, optfound, argc_new, ea_num = *argc;
45 44
46 if(*argc<2) { 45 if (*argc < 2) {
47 /* No arguments provided */ 46 /* No arguments provided */
48 return argv; 47 return argv;
49 } 48 }
50 49
51 for(i=1; i<*argc; i++){ 50 for (i = 1; i < *argc; i++) {
52 argptr=NULL; 51 argptr = NULL;
53 optfound=0; 52 optfound = 0;
54 53
55 /* Do we have an extra-opts parameter? */ 54 /* Do we have an extra-opts parameter? */
56 if(strncmp(argv[i], "--extra-opts=", 13)==0){ 55 if (strncmp(argv[i], "--extra-opts=", 13) == 0) {
57 /* It is a single argument with value */ 56 /* It is a single argument with value */
58 argptr=argv[i]+13; 57 argptr = argv[i] + 13;
59 /* Delete the extra opts argument */ 58 /* Delete the extra opts argument */
60 for(j=i;j<*argc;j++) argv[j]=argv[j+1]; 59 for (j = i; j < *argc; j++)
60 argv[j] = argv[j + 1];
61 i--; 61 i--;
62 *argc-=1; 62 *argc -= 1;
63 }else if(strcmp(argv[i], "--extra-opts")==0){ 63 } else if (strcmp(argv[i], "--extra-opts") == 0) {
64 if((i+1<*argc)&&!is_option2(argv[i+1])){ 64 if ((i + 1 < *argc) && !is_option2(argv[i + 1])) {
65 /* It is a argument with separate value */ 65 /* It is a argument with separate value */
66 argptr=argv[i+1]; 66 argptr = argv[i + 1];
67 /* Delete the extra-opts argument/value */ 67 /* Delete the extra-opts argument/value */
68 for(j=i;j<*argc-1;j++) argv[j]=argv[j+2]; 68 for (j = i; j < *argc - 1; j++)
69 i-=2; 69 argv[j] = argv[j + 2];
70 *argc-=2; 70 i -= 2;
71 *argc -= 2;
71 ea_num--; 72 ea_num--;
72 }else{ 73 } else {
73 /* It has no value */ 74 /* It has no value */
74 optfound=1; 75 optfound = 1;
75 /* Delete the extra opts argument */ 76 /* Delete the extra opts argument */
76 for(j=i;j<*argc;j++) argv[j]=argv[j+1]; 77 for (j = i; j < *argc; j++)
78 argv[j] = argv[j + 1];
77 i--; 79 i--;
78 *argc-=1; 80 *argc -= 1;
79 } 81 }
80 } 82 }
81 83
82 /* If we found extra-opts, expand them and store them for later*/ 84 /* If we found extra-opts, expand them and store them for later*/
83 if(argptr||optfound){ 85 if (argptr || optfound) {
84 /* Process ini section, returning a linked list of arguments */ 86 /* Process ini section, returning a linked list of arguments */
85 ea1=np_get_defaults(argptr, plugin_name); 87 ea1 = np_get_defaults(argptr, plugin_name);
86 if(ea1==NULL) { 88 if (ea1 == NULL) {
87 /* no extra args (empty section)? */ 89 /* no extra args (empty section)? */
88 ea_num--; 90 ea_num--;
89 continue; 91 continue;
90 } 92 }
91 93
92 /* append the list to extra_args */ 94 /* append the list to extra_args */
93 if(extra_args==NULL){ 95 if (extra_args == NULL) {
94 extra_args=ea1; 96 extra_args = ea1;
95 while((ea1 = ea1->next)) ea_num++; 97 while ((ea1 = ea1->next))
96 }else{ 98 ea_num++;
97 ea_tmp=extra_args; 99 } else {
98 while(ea_tmp->next) { 100 ea_tmp = extra_args;
99 ea_tmp=ea_tmp->next; 101 while (ea_tmp->next) {
102 ea_tmp = ea_tmp->next;
100 } 103 }
101 ea_tmp->next=ea1; 104 ea_tmp->next = ea1;
102 while((ea1 = ea1->next)) ea_num++; 105 while ((ea1 = ea1->next))
106 ea_num++;
103 } 107 }
104 ea1=ea_tmp=NULL; 108 ea1 = ea_tmp = NULL;
105 } 109 }
106 } /* lather, rince, repeat */ 110 } /* lather, rince, repeat */
107 111
108 if(ea_num==*argc && extra_args==NULL){ 112 if (ea_num == *argc && extra_args == NULL) {
109 /* No extra-opts */ 113 /* No extra-opts */
110 return argv; 114 return argv;
111 } 115 }
112 116
113 /* done processing arguments. now create a new argv array... */ 117 /* done processing arguments. now create a new argv array... */
114 argv_new=(char**)malloc((ea_num+1)*sizeof(char**)); 118 argv_new = (char **)malloc((ea_num + 1) * sizeof(char **));
115 if(argv_new==NULL) die(STATE_UNKNOWN, _("malloc() failed!\n")); 119 if (argv_new == NULL)
120 die(STATE_UNKNOWN, _("malloc() failed!\n"));
116 121
117 /* starting with program name */ 122 /* starting with program name */
118 argv_new[0]=argv[0]; 123 argv_new[0] = argv[0];
119 argc_new=1; 124 argc_new = 1;
120 /* then parsed ini opts (frying them up in the same run) */ 125 /* then parsed ini opts (frying them up in the same run) */
121 while(extra_args){ 126 while (extra_args) {
122 argv_new[argc_new++]=extra_args->arg; 127 argv_new[argc_new++] = extra_args->arg;
123 ea1=extra_args; 128 ea1 = extra_args;
124 extra_args=extra_args->next; 129 extra_args = extra_args->next;
125 free(ea1); 130 free(ea1);
126 } 131 }
127 /* finally the rest of the argv array */ 132 /* finally the rest of the argv array */
128 for (i=1; i<*argc; i++) argv_new[argc_new++]=argv[i]; 133 for (i = 1; i < *argc; i++)
129 *argc=argc_new; 134 argv_new[argc_new++] = argv[i];
135 *argc = argc_new;
130 /* and terminate. */ 136 /* and terminate. */
131 argv_new[argc_new]=NULL; 137 argv_new[argc_new] = NULL;
132 138
133 return argv_new; 139 return argv_new;
134} 140}
135
diff --git a/lib/extra_opts.h b/lib/extra_opts.h
index 8ff14a16..3f64360f 100644
--- a/lib/extra_opts.h
+++ b/lib/extra_opts.h
@@ -20,4 +20,3 @@
20char **np_extra_opts(int *argc, char **argv, const char *plugin_name); 20char **np_extra_opts(int *argc, char **argv, const char *plugin_name);
21 21
22#endif /* _EXTRA_OPTS_H_ */ 22#endif /* _EXTRA_OPTS_H_ */
23
diff --git a/lib/maxfd.c b/lib/maxfd.c
index 529b3568..ca5b6e54 100644
--- a/lib/maxfd.c
+++ b/lib/maxfd.c
@@ -1,7 +1,27 @@
1/*****************************************************************************
2 *
3 * License: GPL
4 * Copyright (c) 2024 Monitoring Plugins Development Team
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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 General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 *****************************************************************************/
20
1#include "./maxfd.h" 21#include "./maxfd.h"
2#include <errno.h> 22#include <errno.h>
3 23
4long mp_open_max (void) { 24long mp_open_max(void) {
5 long maxfd = 0L; 25 long maxfd = 0L;
6 /* Try sysconf(_SC_OPEN_MAX) first, as it can be higher than OPEN_MAX. 26 /* Try sysconf(_SC_OPEN_MAX) first, as it can be higher than OPEN_MAX.
7 * If that fails and the macro isn't defined, we fall back to an educated 27 * If that fails and the macro isn't defined, we fall back to an educated
@@ -10,17 +30,17 @@ long mp_open_max (void) {
10 30
11#ifdef _SC_OPEN_MAX 31#ifdef _SC_OPEN_MAX
12 errno = 0; 32 errno = 0;
13 if ((maxfd = sysconf (_SC_OPEN_MAX)) < 0) { 33 if ((maxfd = sysconf(_SC_OPEN_MAX)) < 0) {
14 if (errno == 0) 34 if (errno == 0)
15 maxfd = DEFAULT_MAXFD; /* it's indeterminate */ 35 maxfd = DEFAULT_MAXFD; /* it's indeterminate */
16 else 36 else
17 die (STATE_UNKNOWN, _("sysconf error for _SC_OPEN_MAX\n")); 37 die(STATE_UNKNOWN, _("sysconf error for _SC_OPEN_MAX\n"));
18 } 38 }
19#elif defined(OPEN_MAX) 39#elif defined(OPEN_MAX)
20 return OPEN_MAX 40 return OPEN_MAX
21#else /* sysconf macro unavailable, so guess (may be wildly inaccurate) */ 41#else /* sysconf macro unavailable, so guess (may be wildly inaccurate) */
22 return DEFAULT_MAXFD; 42 return DEFAULT_MAXFD;
23#endif 43#endif
24 44
25 return(maxfd); 45 return (maxfd);
26} 46}
diff --git a/lib/maxfd.h b/lib/maxfd.h
index 45218d0f..8fcd62d3 100644
--- a/lib/maxfd.h
+++ b/lib/maxfd.h
@@ -1,9 +1,9 @@
1#ifndef _MAXFD_ 1#ifndef _MAXFD_
2#define _MAXFD_ 2#define _MAXFD_
3 3
4#define DEFAULT_MAXFD 256 /* fallback value if no max open files value is set */ 4#define DEFAULT_MAXFD 256 /* fallback value if no max open files value is set */
5#define MAXFD_LIMIT 8192 /* upper limit of open files */ 5#define MAXFD_LIMIT 8192 /* upper limit of open files */
6 6
7long mp_open_max (void); 7long mp_open_max(void);
8 8
9#endif // _MAXFD_ 9#endif // _MAXFD_
diff --git a/lib/monitoringplug.h b/lib/monitoringplug.h
new file mode 100644
index 00000000..a555d736
--- /dev/null
+++ b/lib/monitoringplug.h
@@ -0,0 +1,7 @@
1#pragma once
2
3#include "./states.h"
4#include "./utils_base.h"
5#include "./thresholds.h"
6#include "./maxfd.h"
7#include "./output.h"
diff --git a/lib/output.c b/lib/output.c
new file mode 100644
index 00000000..34ff7dab
--- /dev/null
+++ b/lib/output.c
@@ -0,0 +1,633 @@
1#include "./output.h"
2#include "./utils_base.h"
3#include "../plugins/utils.h"
4
5#include <assert.h>
6#include <stdlib.h>
7#include <string.h>
8#include <strings.h>
9// #include <cjson/cJSON.h>
10#include "./vendor/cJSON/cJSON.h"
11#include "perfdata.h"
12#include "states.h"
13
14// == Global variables
15static mp_output_format output_format = MP_FORMAT_DEFAULT;
16static mp_output_detail_level level_of_detail = MP_DETAIL_ALL;
17
18// == Prototypes ==
19static char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check,
20 unsigned int indentation);
21static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck);
22
23// == Implementation ==
24
25/*
26 * Generate output string for a mp_subcheck object
27 */
28static inline char *fmt_subcheck_perfdata(mp_subcheck check) {
29 char *result = strdup("");
30 int added = 0;
31
32 if (check.perfdata != NULL) {
33 added = asprintf(&result, "%s", pd_list_to_string(*check.perfdata));
34 }
35
36 if (check.subchecks == NULL) {
37 // No subchecks, return here
38 return result;
39 }
40
41 mp_subcheck_list *subchecks = check.subchecks;
42
43 while (subchecks != NULL) {
44 if (added > 0) {
45 added = asprintf(&result, "%s%s", result, fmt_subcheck_perfdata(subchecks->subcheck));
46 } else {
47 // TODO free previous result here?
48 added = asprintf(&result, "%s", fmt_subcheck_perfdata(subchecks->subcheck));
49 }
50
51 subchecks = subchecks->next;
52 }
53
54 return result;
55}
56
57/*
58 * Initialiser for a mp_check object. Always use this to get a new one!
59 * It sets useful defaults
60 */
61mp_check mp_check_init(void) {
62 mp_check check = {
63 .evaluation_function = &mp_eval_check_default,
64 };
65 return check;
66}
67
68/*
69 * Initialiser for a mp_subcheck object. Always use this to get a new one!
70 * It sets useful defaults
71 */
72mp_subcheck mp_subcheck_init(void) {
73 mp_subcheck tmp = {0};
74 tmp.default_state = STATE_UNKNOWN; // Default state is unknown
75 tmp.state_set_explicitly = false;
76 return tmp;
77}
78
79/*
80 * Add a subcheck to a (the one and only) check object
81 */
82int mp_add_subcheck_to_check(mp_check check[static 1], mp_subcheck subcheck) {
83 assert(subcheck.output != NULL); // There must be output in a subcheck
84
85 mp_subcheck_list *tmp = NULL;
86
87 if (check->subchecks == NULL) {
88 check->subchecks = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list));
89 if (check->subchecks == NULL) {
90 die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed");
91 }
92
93 check->subchecks->subcheck = subcheck;
94 check->subchecks->next = NULL;
95 } else {
96 // Search for the end
97 tmp = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list));
98 if (tmp == NULL) {
99 die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed");
100 }
101
102 tmp->subcheck = subcheck;
103 tmp->next = check->subchecks;
104
105 check->subchecks = tmp;
106 }
107
108 return 0;
109}
110
111/*
112 * Add a mp_perfdata data point to a mp_subcheck object
113 */
114void mp_add_perfdata_to_subcheck(mp_subcheck check[static 1], const mp_perfdata perfData) {
115 if (check->perfdata == NULL) {
116 check->perfdata = pd_list_init();
117 }
118 pd_list_append(check->perfdata, perfData);
119}
120
121/*
122 * Add a mp_subcheck object to another one. The seconde mp_subcheck (argument) is the lower in the
123 * hierarchy
124 */
125int mp_add_subcheck_to_subcheck(mp_subcheck check[static 1], mp_subcheck subcheck) {
126 if (subcheck.output == NULL) {
127 die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__,
128 "Sub check output is NULL");
129 }
130
131 mp_subcheck_list *tmp = NULL;
132
133 if (check->subchecks == NULL) {
134 check->subchecks = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list));
135 if (check->subchecks == NULL) {
136 die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed");
137 }
138
139 tmp = check->subchecks;
140 } else {
141 // Search for the end
142 tmp = check->subchecks;
143
144 while (tmp->next != NULL) {
145 tmp = tmp->next;
146 }
147
148 tmp->next = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list));
149 if (tmp->next == NULL) {
150 die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed");
151 }
152
153 tmp = tmp->next;
154 }
155
156 tmp->subcheck = subcheck;
157
158 return 0;
159}
160
161/*
162 * Add a manual summary to a mp_check object, effectively replacing
163 * the autogenerated one
164 */
165void mp_add_summary(mp_check check[static 1], char *summary) { check->summary = summary; }
166
167/*
168 * Generate the summary string of a mp_check object based on it's subchecks
169 */
170char *get_subcheck_summary(mp_check check) {
171 mp_subcheck_list *subchecks = check.subchecks;
172
173 unsigned int ok = 0;
174 unsigned int warning = 0;
175 unsigned int critical = 0;
176 unsigned int unknown = 0;
177 while (subchecks != NULL) {
178 switch (subchecks->subcheck.state) {
179 case STATE_OK:
180 ok++;
181 break;
182 case STATE_WARNING:
183 warning++;
184 break;
185 case STATE_CRITICAL:
186 critical++;
187 break;
188 case STATE_UNKNOWN:
189 unknown++;
190 break;
191 default:
192 die(STATE_UNKNOWN, "Unknown state in get_subcheck_summary");
193 }
194 subchecks = subchecks->next;
195 }
196 char *result = NULL;
197 asprintf(&result, "ok=%d, warning=%d, critical=%d, unknown=%d", ok, warning, critical, unknown);
198 return result;
199}
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
208/*
209 * Generate the result state of a mp_subcheck object based on its own state and its subchecks
210 * states
211 */
212mp_state_enum mp_eval_subcheck_default(mp_subcheck subcheck) {
213 if (subcheck.evaluation_function != NULL) {
214 return subcheck.evaluation_function(subcheck);
215 }
216
217 if (subcheck.state_set_explicitly) {
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;
228
229 while (scl != NULL) {
230 result = max_state_alt(result, mp_compute_subcheck_state(scl->subcheck));
231 scl = scl->next;
232 }
233
234 return result;
235}
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
245/*
246 * Generate the result state of a mp_check object based on it's own state and it's subchecks states
247 */
248mp_state_enum mp_eval_check_default(const mp_check check) {
249 assert(check.subchecks != NULL); // a mp_check without subchecks is invalid, die here
250
251 mp_subcheck_list *scl = check.subchecks;
252 mp_state_enum result = STATE_OK;
253
254 while (scl != NULL) {
255 result = max_state_alt(result, mp_compute_subcheck_state(scl->subcheck));
256 scl = scl->next;
257 }
258
259 return result;
260}
261
262/*
263 * Generate output string for a mp_check object
264 * Non static to be available for testing functions
265 */
266char *mp_fmt_output(mp_check check) {
267 char *result = NULL;
268
269 switch (output_format) {
270 case MP_FORMAT_MULTI_LINE: {
271 if (check.summary == NULL) {
272 check.summary = get_subcheck_summary(check);
273 }
274
275 asprintf(&result, "[%s] - %s", state_text(mp_compute_check_state(check)), check.summary);
276
277 mp_subcheck_list *subchecks = check.subchecks;
278
279 while (subchecks != NULL) {
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 }
285 subchecks = subchecks->next;
286 }
287
288 char *pd_string = NULL;
289 subchecks = check.subchecks;
290
291 while (subchecks != NULL) {
292 if (pd_string == NULL) {
293 asprintf(&pd_string, "%s", fmt_subcheck_perfdata(subchecks->subcheck));
294 } else {
295 asprintf(&pd_string, "%s %s", pd_string,
296 fmt_subcheck_perfdata(subchecks->subcheck));
297 }
298
299 subchecks = subchecks->next;
300 }
301
302 if (pd_string != NULL && strlen(pd_string) > 0) {
303 asprintf(&result, "%s|%s", result, pd_string);
304 }
305
306 break;
307 }
308 case MP_FORMAT_TEST_JSON: {
309 cJSON *resultObject = cJSON_CreateObject();
310 if (resultObject == NULL) {
311 die(STATE_UNKNOWN, "cJSON_CreateObject failed");
312 }
313
314 cJSON *resultState = cJSON_CreateString(state_text(mp_compute_check_state(check)));
315 cJSON_AddItemToObject(resultObject, "state", resultState);
316
317 if (check.summary == NULL) {
318 check.summary = get_subcheck_summary(check);
319 }
320
321 cJSON *summary = cJSON_CreateString(check.summary);
322 cJSON_AddItemToObject(resultObject, "summary", summary);
323
324 if (check.subchecks != NULL) {
325 cJSON *subchecks = cJSON_CreateArray();
326
327 mp_subcheck_list *sc = check.subchecks;
328
329 while (sc != NULL) {
330 cJSON *sc_json = json_serialize_subcheck(sc->subcheck);
331 cJSON_AddItemToArray(subchecks, sc_json);
332 sc = sc->next;
333 }
334
335 cJSON_AddItemToObject(resultObject, "checks", subchecks);
336 }
337
338 result = cJSON_PrintUnformatted(resultObject);
339 break;
340 }
341 default:
342 die(STATE_UNKNOWN, "Invalid format");
343 }
344
345 return result;
346}
347
348/*
349 * Helper function to properly indent the output lines when using multiline
350 * formats
351 */
352static char *generate_indentation_string(unsigned int indentation) {
353 char *result = calloc(indentation + 1, sizeof(char));
354
355 for (unsigned int i = 0; i < indentation; i++) {
356 result[i] = '\t';
357 }
358
359 return result;
360}
361
362/*
363 * Helper function to generate the output string of mp_subcheck
364 */
365static inline char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check,
366 unsigned int indentation) {
367 char *result = NULL;
368 mp_subcheck_list *subchecks = NULL;
369
370 switch (output_format) {
371 case MP_FORMAT_MULTI_LINE: {
372 char *tmp_string = NULL;
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, generate_indentation_string(indentation+1)); // one more indentation to make it look better
381
382 if (*(tmp_string + 1) != '\0') {
383 check.output = tmp_string + 1;
384 have_residual_chars = true;
385 } else {
386 // Null after the \n, so this is the end
387 have_residual_chars = false;
388 break;
389 }
390
391 tmp_string = strchr(check.output, '\n');
392 }
393
394 // add the rest (if any)
395 if (have_residual_chars) {
396 char *tmp = check.output;
397 xasprintf(&check.output, "%s\n%s%s", intermediate_string, generate_indentation_string(indentation+1), tmp);
398 } else {
399 check.output = intermediate_string;
400 }
401 }
402 asprintf(&result, "%s\\_[%s] - %s", generate_indentation_string(indentation), state_text(mp_compute_subcheck_state(check)),
403 check.output);
404
405 subchecks = check.subchecks;
406
407 while (subchecks != NULL) {
408 asprintf(&result, "%s\n%s", result,
409 fmt_subcheck_output(output_format, subchecks->subcheck, indentation + 1));
410 subchecks = subchecks->next;
411 }
412 return result;
413 }
414 default:
415 die(STATE_UNKNOWN, "Invalid format");
416 }
417}
418
419static inline cJSON *json_serialise_pd_value(mp_perfdata_value value) {
420 cJSON *result = cJSON_CreateObject();
421
422 switch (value.type) {
423 case PD_TYPE_DOUBLE:
424 cJSON_AddStringToObject(result, "type", "double");
425 break;
426 case PD_TYPE_INT:
427 cJSON_AddStringToObject(result, "type", "int");
428 break;
429 case PD_TYPE_UINT:
430 cJSON_AddStringToObject(result, "type", "uint");
431 break;
432 case PD_TYPE_NONE:
433 die(STATE_UNKNOWN, "Perfdata type was None in json_serialise_pd_value");
434 }
435 cJSON_AddStringToObject(result, "value", pd_value_to_string(value));
436
437 return result;
438}
439
440static inline cJSON *json_serialise_range(mp_range range) {
441 cJSON *result = cJSON_CreateObject();
442
443 if (range.alert_on_inside_range) {
444 cJSON_AddBoolToObject(result, "alert_on_inside", true);
445 } else {
446 cJSON_AddBoolToObject(result, "alert_on_inside", false);
447 }
448
449 if (range.end_infinity) {
450 cJSON_AddStringToObject(result, "end", "inf");
451 } else {
452 cJSON_AddItemToObject(result, "end", json_serialise_pd_value(range.end));
453 }
454
455 if (range.start_infinity) {
456 cJSON_AddStringToObject(result, "start", "inf");
457 } else {
458 cJSON_AddItemToObject(result, "start", json_serialise_pd_value(range.end));
459 }
460
461 return result;
462}
463
464static inline cJSON *json_serialise_pd(mp_perfdata pd_val) {
465 cJSON *result = cJSON_CreateObject();
466
467 // Label
468 cJSON_AddStringToObject(result, "label", pd_val.label);
469
470 // Value
471 cJSON_AddItemToObject(result, "value", json_serialise_pd_value(pd_val.value));
472
473 // Uom
474 cJSON_AddStringToObject(result, "uom", pd_val.uom);
475
476 // Warn/Crit
477 if (pd_val.warn_present) {
478 cJSON *warn = json_serialise_range(pd_val.warn);
479 cJSON_AddItemToObject(result, "warn", warn);
480 }
481 if (pd_val.crit_present) {
482 cJSON *crit = json_serialise_range(pd_val.crit);
483 cJSON_AddItemToObject(result, "crit", crit);
484 }
485
486 if (pd_val.min_present) {
487 cJSON_AddItemToObject(result, "min", json_serialise_pd_value(pd_val.min));
488 }
489 if (pd_val.max_present) {
490 cJSON_AddItemToObject(result, "max", json_serialise_pd_value(pd_val.max));
491 }
492
493 return result;
494}
495
496static inline cJSON *json_serialise_pd_list(pd_list *list) {
497 cJSON *result = cJSON_CreateArray();
498
499 do {
500 cJSON *pd_value = json_serialise_pd(list->data);
501 cJSON_AddItemToArray(result, pd_value);
502 list = list->next;
503 } while (list != NULL);
504
505 return result;
506}
507
508static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck) {
509 cJSON *result = cJSON_CreateObject();
510
511 // Human readable output
512 cJSON *output = cJSON_CreateString(subcheck.output);
513 cJSON_AddItemToObject(result, "output", output);
514
515 // Test state (aka Exit Code)
516 cJSON *state = cJSON_CreateString(state_text(mp_compute_subcheck_state(subcheck)));
517 cJSON_AddItemToObject(result, "state", state);
518
519 // Perfdata
520 if (subcheck.perfdata != NULL) {
521 cJSON *perfdata = json_serialise_pd_list(subcheck.perfdata);
522 cJSON_AddItemToObject(result, "perfdata", perfdata);
523 }
524
525 if (subcheck.subchecks != NULL) {
526 cJSON *subchecks = cJSON_CreateArray();
527
528 mp_subcheck_list *sc = subcheck.subchecks;
529
530 while (sc != NULL) {
531 cJSON *sc_json = json_serialize_subcheck(sc->subcheck);
532 cJSON_AddItemToArray(subchecks, sc_json);
533 sc = sc->next;
534 }
535
536 cJSON_AddItemToObject(result, "checks", subchecks);
537 }
538
539 return result;
540}
541
542/*
543 * Wrapper function to print the output string of a mp_check object
544 * Use this in concrete plugins.
545 */
546void mp_print_output(mp_check check) { puts(mp_fmt_output(check)); }
547
548/*
549 * Convenience function to print the output string of a mp_check object and exit
550 * the program with the resulting state.
551 * Intended to be used to exit a monitoring plugin.
552 */
553void mp_exit(mp_check check) {
554 mp_print_output(check);
555 if (output_format == MP_FORMAT_TEST_JSON) {
556 exit(0);
557 }
558
559 exit(mp_compute_check_state(check));
560}
561
562/*
563 * Function to set the result state of a mp_subcheck object explicitly.
564 * This will overwrite the default state AND states derived from it's subchecks
565 */
566mp_subcheck mp_set_subcheck_state(mp_subcheck check, mp_state_enum state) {
567 check.state = state;
568 check.state_set_explicitly = true;
569 return check;
570}
571
572/*
573 * Function to set the default result state of a mp_subcheck object. This state
574 * will be used if neither an explicit state is set (see *mp_set_subcheck_state*)
575 * nor does it include other subchecks
576 */
577mp_subcheck mp_set_subcheck_default_state(mp_subcheck check, mp_state_enum state) {
578 check.default_state = state;
579 return check;
580}
581
582char *mp_output_format_map[] = {
583 [MP_FORMAT_MULTI_LINE] = "multi-line",
584 [MP_FORMAT_TEST_JSON] = "mp-test-json",
585};
586
587/*
588 * Function to parse the output from a string
589 */
590parsed_output_format mp_parse_output_format(char *format_string) {
591 parsed_output_format result = {
592 .parsing_success = false,
593 .output_format = MP_FORMAT_DEFAULT,
594 };
595
596 for (mp_output_format i = 0; i < (sizeof(mp_output_format_map) / sizeof(char *)); i++) {
597 if (strcasecmp(mp_output_format_map[i], format_string) == 0) {
598 result.parsing_success = true;
599 result.output_format = i;
600 break;
601 }
602 }
603
604 return result;
605}
606
607void mp_set_format(mp_output_format format) { output_format = format; }
608
609mp_output_format mp_get_format(void) { return output_format; }
610
611void mp_set_level_of_detail(mp_output_detail_level level) { level_of_detail = level; }
612
613mp_output_detail_level mp_get_level_of_detail(void) { return level_of_detail; }
614
615mp_state_enum mp_eval_ok(mp_check overall) {
616 (void)overall;
617 return STATE_OK;
618}
619
620mp_state_enum mp_eval_warning(mp_check overall) {
621 (void)overall;
622 return STATE_WARNING;
623}
624
625mp_state_enum mp_eval_critical(mp_check overall) {
626 (void)overall;
627 return STATE_CRITICAL;
628}
629
630mp_state_enum mp_eval_unknown(mp_check overall) {
631 (void)overall;
632 return STATE_UNKNOWN;
633}
diff --git a/lib/output.h b/lib/output.h
new file mode 100644
index 00000000..c63c8e3f
--- /dev/null
+++ b/lib/output.h
@@ -0,0 +1,117 @@
1#pragma once
2
3#include "../config.h"
4#include "./perfdata.h"
5#include "./states.h"
6
7/*
8 * A partial check result
9 */
10typedef struct mp_subcheck mp_subcheck;
11struct mp_subcheck {
12 mp_state_enum state; // OK, Warning, Critical ... set explicitly
13 mp_state_enum default_state; // OK, Warning, Critical .. if not set explicitly
14 bool state_set_explicitly; // was the state set explicitly (or should it be derived from
15 // subchecks)
16
17 char *output; // Text output for humans ("Filesystem xyz is fine", "Could not create TCP
18 // connection to..")
19 pd_list *perfdata; // Performance data for this check
20 struct subcheck_list *subchecks; // subchecks deeper in the hierarchy
21
22 // the evaluation_functions computes the state of subcheck
23 mp_state_enum (*evaluation_function)(mp_subcheck);
24};
25
26/*
27 * A list of subchecks, used in subchecks and the main check
28 */
29typedef struct subcheck_list {
30 mp_subcheck subcheck;
31 struct subcheck_list *next;
32} mp_subcheck_list;
33
34/*
35 * Possible output formats
36 */
37typedef enum output_format {
38 MP_FORMAT_MULTI_LINE,
39 MP_FORMAT_TEST_JSON,
40} mp_output_format;
41
42#define MP_FORMAT_DEFAULT MP_FORMAT_MULTI_LINE
43
44/*
45 * Format related functions
46 */
47void mp_set_format(mp_output_format format);
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);
59
60/*
61 * The main state object of a plugin. Exists only ONCE per plugin.
62 * This is the "root" of a tree of singular checks.
63 * The final result is always derived from the children and the "worst" state
64 * in the first layer of subchecks
65 */
66typedef struct mp_check mp_check;
67struct mp_check {
68 char *summary; // Overall summary, if not set a summary will be automatically generated
69 mp_subcheck_list *subchecks;
70
71 // the evaluation_functions computes the state of check
72 mp_state_enum (*evaluation_function)(mp_check);
73};
74
75mp_check mp_check_init(void);
76mp_subcheck mp_subcheck_init(void);
77
78mp_subcheck mp_set_subcheck_state(mp_subcheck, mp_state_enum);
79mp_subcheck mp_set_subcheck_default_state(mp_subcheck, mp_state_enum);
80
81int mp_add_subcheck_to_check(mp_check check[static 1], mp_subcheck);
82int mp_add_subcheck_to_subcheck(mp_subcheck check[static 1], mp_subcheck);
83
84void mp_add_perfdata_to_subcheck(mp_subcheck check[static 1], mp_perfdata);
85
86void mp_add_summary(mp_check check[static 1], char *summary);
87
88mp_state_enum mp_compute_check_state(mp_check);
89mp_state_enum mp_compute_subcheck_state(mp_subcheck);
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
98typedef struct {
99 bool parsing_success;
100 mp_output_format output_format;
101} parsed_output_format;
102parsed_output_format mp_parse_output_format(char *format_string);
103
104// TODO free and stuff
105// void mp_cleanup_check(mp_check check[static 1]);
106
107char *mp_fmt_output(mp_check);
108
109void mp_print_output(mp_check);
110
111/*
112 * ==================
113 * Exit functionality
114 * ==================
115 */
116
117void mp_exit(mp_check) __attribute__((noreturn));
diff --git a/lib/parse_ini.c b/lib/parse_ini.c
index 09c0dc4f..1289aae2 100644
--- a/lib/parse_ini.c
+++ b/lib/parse_ini.c
@@ -1,25 +1,25 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring Plugins parse_ini library 3 * Monitoring Plugins parse_ini library
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2007 Monitoring Plugins Development Team 6 * Copyright (c) 2007 - 2024 Monitoring Plugins Development Team
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#include "common.h" 24#include "common.h"
25#include "idpriv.h" 25#include "idpriv.h"
@@ -40,31 +40,20 @@ typedef struct {
40 char *stanza; 40 char *stanza;
41} np_ini_info; 41} np_ini_info;
42 42
43static char *default_ini_file_names[] = { 43static char *default_ini_file_names[] = {"monitoring-plugins.ini", "plugins.ini", "nagios-plugins.ini", NULL};
44 "monitoring-plugins.ini",
45 "plugins.ini",
46 "nagios-plugins.ini",
47 NULL
48};
49 44
50static char *default_ini_path_names[] = { 45static char *default_ini_path_names[] = {
51 "/usr/local/etc/monitoring-plugins/monitoring-plugins.ini", 46 "/usr/local/etc/monitoring-plugins/monitoring-plugins.ini", "/usr/local/etc/monitoring-plugins.ini",
52 "/usr/local/etc/monitoring-plugins.ini", 47 "/etc/monitoring-plugins/monitoring-plugins.ini", "/etc/monitoring-plugins.ini",
53 "/etc/monitoring-plugins/monitoring-plugins.ini",
54 "/etc/monitoring-plugins.ini",
55 /* deprecated path names (for backward compatibility): */ 48 /* deprecated path names (for backward compatibility): */
56 "/etc/nagios/plugins.ini", 49 "/etc/nagios/plugins.ini", "/usr/local/nagios/etc/plugins.ini", "/usr/local/etc/nagios/plugins.ini", "/etc/opt/nagios/plugins.ini",
57 "/usr/local/nagios/etc/plugins.ini", 50 "/etc/nagios-plugins.ini", "/usr/local/etc/nagios-plugins.ini", "/etc/opt/nagios-plugins.ini", NULL};
58 "/usr/local/etc/nagios/plugins.ini",
59 "/etc/opt/nagios/plugins.ini",
60 "/etc/nagios-plugins.ini",
61 "/usr/local/etc/nagios-plugins.ini",
62 "/etc/opt/nagios-plugins.ini",
63 NULL
64};
65 51
66/* eat all characters from a FILE pointer until n is encountered */ 52/* eat all characters from a FILE pointer until n is encountered */
67#define GOBBLE_TO(f, c, n) do { (c)=fgetc((f)); } while((c)!=EOF && (c)!=(n)) 53#define GOBBLE_TO(f, c, n) \
54 do { \
55 (c) = fgetc((f)); \
56 } while ((c) != EOF && (c) != (n))
68 57
69/* internal function that returns the constructed defaults options */ 58/* internal function that returns the constructed defaults options */
70static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts); 59static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts);
@@ -81,9 +70,7 @@ static char *default_file_in_path(void);
81 * [stanza][@filename] 70 * [stanza][@filename]
82 * into its separate parts. 71 * into its separate parts.
83 */ 72 */
84static void 73static void parse_locator(const char *locator, const char *def_stanza, np_ini_info *i) {
85parse_locator(const char *locator, const char *def_stanza, np_ini_info *i)
86{
87 size_t locator_len = 0, stanza_len = 0; 74 size_t locator_len = 0, stanza_len = 0;
88 75
89 /* if locator is NULL we'll use default values */ 76 /* if locator is NULL we'll use default values */
@@ -96,7 +83,7 @@ parse_locator(const char *locator, const char *def_stanza, np_ini_info *i)
96 i->stanza = malloc(sizeof(char) * (stanza_len + 1)); 83 i->stanza = malloc(sizeof(char) * (stanza_len + 1));
97 strncpy(i->stanza, locator, stanza_len); 84 strncpy(i->stanza, locator, stanza_len);
98 i->stanza[stanza_len] = '\0'; 85 i->stanza[stanza_len] = '\0';
99 } else {/* otherwise we use the default stanza */ 86 } else { /* otherwise we use the default stanza */
100 i->stanza = strdup(def_stanza); 87 i->stanza = strdup(def_stanza);
101 } 88 }
102 89
@@ -105,7 +92,7 @@ parse_locator(const char *locator, const char *def_stanza, np_ini_info *i)
105 92
106 /* check whether there's an @file part */ 93 /* check whether there's an @file part */
107 if (stanza_len == locator_len) { 94 if (stanza_len == locator_len) {
108 i->file = default_file(); 95 i->file = default_file();
109 i->file_string_on_heap = false; 96 i->file_string_on_heap = false;
110 } else { 97 } else {
111 i->file = strdup(&(locator[stanza_len + 1])); 98 i->file = strdup(&(locator[stanza_len + 1]));
@@ -113,35 +100,28 @@ parse_locator(const char *locator, const char *def_stanza, np_ini_info *i)
113 } 100 }
114 101
115 if (i->file == NULL || i->file[0] == '\0') 102 if (i->file == NULL || i->file[0] == '\0')
116 die(STATE_UNKNOWN, 103 die(STATE_UNKNOWN, _("Cannot find config file in any standard location.\n"));
117 _("Cannot find config file in any standard location.\n"));
118} 104}
119 105
120/* 106/*
121 * This is the externally visible function used by extra_opts. 107 * This is the externally visible function used by extra_opts.
122 */ 108 */
123np_arg_list * 109np_arg_list *np_get_defaults(const char *locator, const char *default_section) {
124np_get_defaults(const char *locator, const char *default_section)
125{
126 FILE *inifile = NULL; 110 FILE *inifile = NULL;
127 np_arg_list *defaults = NULL; 111 np_arg_list *defaults = NULL;
128 np_ini_info i; 112 np_ini_info i;
129 int is_suid_plugin = mp_suid(); 113 int is_suid_plugin = mp_suid();
130 114
131 if (is_suid_plugin && idpriv_temp_drop() == -1) 115 if (is_suid_plugin && idpriv_temp_drop() == -1)
132 die(STATE_UNKNOWN, _("Cannot drop privileges: %s\n"), 116 die(STATE_UNKNOWN, _("Cannot drop privileges: %s\n"), strerror(errno));
133 strerror(errno));
134 117
135 parse_locator(locator, default_section, &i); 118 parse_locator(locator, default_section, &i);
136 inifile = strcmp(i.file, "-") == 0 ? stdin : fopen(i.file, "r"); 119 inifile = strcmp(i.file, "-") == 0 ? stdin : fopen(i.file, "r");
137 120
138 if (inifile == NULL) 121 if (inifile == NULL)
139 die(STATE_UNKNOWN, _("Can't read config file: %s\n"), 122 die(STATE_UNKNOWN, _("Can't read config file: %s\n"), strerror(errno));
140 strerror(errno));
141 if (!read_defaults(inifile, i.stanza, &defaults)) 123 if (!read_defaults(inifile, i.stanza, &defaults))
142 die(STATE_UNKNOWN, 124 die(STATE_UNKNOWN, _("Invalid section '%s' in config file '%s'\n"), i.stanza, i.file);
143 _("Invalid section '%s' in config file '%s'\n"), i.stanza,
144 i.file);
145 125
146 if (i.file_string_on_heap) { 126 if (i.file_string_on_heap) {
147 free(i.file); 127 free(i.file);
@@ -151,8 +131,7 @@ np_get_defaults(const char *locator, const char *default_section)
151 fclose(inifile); 131 fclose(inifile);
152 free(i.stanza); 132 free(i.stanza);
153 if (is_suid_plugin && idpriv_temp_restore() == -1) 133 if (is_suid_plugin && idpriv_temp_restore() == -1)
154 die(STATE_UNKNOWN, _("Cannot restore privileges: %s\n"), 134 die(STATE_UNKNOWN, _("Cannot restore privileges: %s\n"), strerror(errno));
155 strerror(errno));
156 135
157 return defaults; 136 return defaults;
158} 137}
@@ -164,13 +143,15 @@ np_get_defaults(const char *locator, const char *default_section)
164 * be extra careful about user-supplied input (i.e. avoiding possible 143 * be extra careful about user-supplied input (i.e. avoiding possible
165 * format string vulnerabilities, etc). 144 * format string vulnerabilities, etc).
166 */ 145 */
167static int 146static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts) {
168read_defaults(FILE *f, const char *stanza, np_arg_list **opts)
169{
170 int c = 0; 147 int c = 0;
171 bool status = false; 148 bool status = false;
172 size_t i, stanza_len; 149 size_t i, stanza_len;
173 enum { NOSTANZA, WRONGSTANZA, RIGHTSTANZA } stanzastate = NOSTANZA; 150 enum {
151 NOSTANZA,
152 WRONGSTANZA,
153 RIGHTSTANZA
154 } stanzastate = NOSTANZA;
174 155
175 stanza_len = strlen(stanza); 156 stanza_len = strlen(stanza);
176 157
@@ -217,8 +198,7 @@ read_defaults(FILE *f, const char *stanza, np_arg_list **opts)
217 * we're dealing with a config error 198 * we're dealing with a config error
218 */ 199 */
219 case NOSTANZA: 200 case NOSTANZA:
220 die(STATE_UNKNOWN, "%s\n", 201 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
221 _("Config file error"));
222 /* we're in a stanza, but for a different plugin */ 202 /* we're in a stanza, but for a different plugin */
223 case WRONGSTANZA: 203 case WRONGSTANZA:
224 GOBBLE_TO(f, c, '\n'); 204 GOBBLE_TO(f, c, '\n');
@@ -227,8 +207,7 @@ read_defaults(FILE *f, const char *stanza, np_arg_list **opts)
227 case RIGHTSTANZA: 207 case RIGHTSTANZA:
228 ungetc(c, f); 208 ungetc(c, f);
229 if (add_option(f, opts)) { 209 if (add_option(f, opts)) {
230 die(STATE_UNKNOWN, "%s\n", 210 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
231 _("Config file error"));
232 } 211 }
233 status = true; 212 status = true;
234 break; 213 break;
@@ -246,9 +225,7 @@ read_defaults(FILE *f, const char *stanza, np_arg_list **opts)
246 * --option[=value] 225 * --option[=value]
247 * appending it to the linked list optbuf. 226 * appending it to the linked list optbuf.
248 */ 227 */
249static int 228static int add_option(FILE *f, np_arg_list **optlst) {
250add_option(FILE *f, np_arg_list **optlst)
251{
252 np_arg_list *opttmp = *optlst, *optnew; 229 np_arg_list *opttmp = *optlst, *optnew;
253 char *linebuf = NULL, *lineend = NULL, *optptr = NULL, *optend = NULL; 230 char *linebuf = NULL, *lineend = NULL, *optptr = NULL, *optend = NULL;
254 char *eqptr = NULL, *valptr = NULL, *valend = NULL; 231 char *eqptr = NULL, *valptr = NULL, *valend = NULL;
@@ -295,8 +272,7 @@ add_option(FILE *f, np_arg_list **optlst)
295 if (optptr == eqptr) 272 if (optptr == eqptr)
296 die(STATE_UNKNOWN, "%s\n", _("Config file error")); 273 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
297 /* continue from '=' to start of value or EOL */ 274 /* continue from '=' to start of value or EOL */
298 for (valptr = eqptr + 1; valptr < lineend && isspace(*valptr); 275 for (valptr = eqptr + 1; valptr < lineend && isspace(*valptr); valptr++)
299 valptr++)
300 continue; 276 continue;
301 /* continue to the end of value */ 277 /* continue to the end of value */
302 for (valend = valptr; valend < lineend; valend++) 278 for (valend = valptr; valend < lineend; valend++)
@@ -365,13 +341,10 @@ add_option(FILE *f, np_arg_list **optlst)
365 return 0; 341 return 0;
366} 342}
367 343
368static char * 344static char *default_file(void) {
369default_file(void) 345 char *ini_file;
370{
371 char *ini_file;
372 346
373 if ((ini_file = getenv("MP_CONFIG_FILE")) != NULL || 347 if ((ini_file = getenv("MP_CONFIG_FILE")) != NULL || (ini_file = default_file_in_path()) != NULL) {
374 (ini_file = default_file_in_path()) != NULL) {
375 return ini_file; 348 return ini_file;
376 } 349 }
377 350
@@ -383,9 +356,7 @@ default_file(void)
383 return NULL; 356 return NULL;
384} 357}
385 358
386static char * 359static char *default_file_in_path(void) {
387default_file_in_path(void)
388{
389 char *config_path, **file; 360 char *config_path, **file;
390 char *dir, *ini_file, *tokens; 361 char *dir, *ini_file, *tokens;
391 362
diff --git a/lib/parse_ini.h b/lib/parse_ini.h
index e37601b5..d17409e3 100644
--- a/lib/parse_ini.h
+++ b/lib/parse_ini.h
@@ -19,4 +19,3 @@ typedef struct np_arg_el {
19np_arg_list *np_get_defaults(const char *locator, const char *default_section); 19np_arg_list *np_get_defaults(const char *locator, const char *default_section);
20 20
21#endif /* _PARSE_INI_H_ */ 21#endif /* _PARSE_INI_H_ */
22
diff --git a/lib/perfdata.c b/lib/perfdata.c
new file mode 100644
index 00000000..b87de7e0
--- /dev/null
+++ b/lib/perfdata.c
@@ -0,0 +1,605 @@
1#include "./perfdata.h"
2#include "../plugins/common.h"
3#include "../plugins/utils.h"
4#include "utils_base.h"
5
6#include <assert.h>
7#include <limits.h>
8#include <stdlib.h>
9
10char *pd_value_to_string(const mp_perfdata_value pd) {
11 char *result = NULL;
12
13 assert(pd.type != PD_TYPE_NONE);
14
15 switch (pd.type) {
16 case PD_TYPE_INT:
17 asprintf(&result, "%lli", pd.pd_int);
18 break;
19 case PD_TYPE_UINT:
20 asprintf(&result, "%llu", pd.pd_int);
21 break;
22 case PD_TYPE_DOUBLE:
23 asprintf(&result, "%f", pd.pd_double);
24 break;
25 default:
26 // die here
27 die(STATE_UNKNOWN, "Invalid mp_perfdata mode\n");
28 }
29
30 return result;
31}
32
33char *pd_to_string(mp_perfdata pd) {
34 assert(pd.label != NULL);
35 char *result = NULL;
36 asprintf(&result, "'%s'=", pd.label);
37
38 asprintf(&result, "%s%s", result, pd_value_to_string(pd.value));
39
40 if (pd.uom != NULL) {
41 asprintf(&result, "%s%s", result, pd.uom);
42 }
43
44 if (pd.warn_present) {
45 asprintf(&result, "%s;%s", result, mp_range_to_string(pd.warn));
46 } else {
47 asprintf(&result, "%s;", result);
48 }
49
50 if (pd.crit_present) {
51 asprintf(&result, "%s;%s", result, mp_range_to_string(pd.crit));
52 } else {
53 asprintf(&result, "%s;", result);
54 }
55 if (pd.min_present) {
56 asprintf(&result, "%s;%s", result, pd_value_to_string(pd.min));
57 } else {
58 asprintf(&result, "%s;", result);
59 }
60
61 if (pd.max_present) {
62 asprintf(&result, "%s;%s", result, pd_value_to_string(pd.max));
63 }
64
65 /*printf("pd_to_string: %s\n", result); */
66
67 return result;
68}
69
70char *pd_list_to_string(const pd_list pd) {
71 char *result = pd_to_string(pd.data);
72
73 for (pd_list *elem = pd.next; elem != NULL; elem = elem->next) {
74 asprintf(&result, "%s %s", result, pd_to_string(elem->data));
75 }
76
77 return result;
78}
79
80mp_perfdata perfdata_init() {
81 mp_perfdata pd = {};
82 return pd;
83}
84
85pd_list *pd_list_init() {
86 pd_list *tmp = (pd_list *)calloc(1, sizeof(pd_list));
87 if (tmp == NULL) {
88 die(STATE_UNKNOWN, "calloc failed\n");
89 }
90 tmp->next = NULL;
91 return tmp;
92}
93
94mp_range mp_range_init() {
95 mp_range result = {
96 .alert_on_inside_range = OUTSIDE,
97 .start = {},
98 .start_infinity = true,
99 .end = {},
100 .end_infinity = true,
101 };
102
103 return result;
104}
105
106mp_range mp_range_set_start(mp_range input, mp_perfdata_value perf_val) {
107 input.start = perf_val;
108 input.start_infinity = false;
109 return input;
110}
111
112mp_range mp_range_set_end(mp_range input, mp_perfdata_value perf_val) {
113 input.end = perf_val;
114 input.end_infinity = false;
115 return input;
116}
117
118void pd_list_append(pd_list pdl[1], const mp_perfdata pd) {
119 assert(pdl != NULL);
120
121 if (pdl->data.value.type == PD_TYPE_NONE) {
122 // first entry is still empty
123 pdl->data = pd;
124 } else {
125 // find last element in the list
126 pd_list *curr = pdl;
127 pd_list *next = pdl->next;
128
129 while (next != NULL) {
130 curr = next;
131 next = next->next;
132 }
133
134 if (curr->data.value.type == PD_TYPE_NONE) {
135 // still empty
136 curr->data = pd;
137 } else {
138 // new a new one
139 curr->next = pd_list_init();
140 curr->next->data = pd;
141 }
142 }
143}
144
145void pd_list_free(pd_list pdl[1]) {
146 while (pdl != NULL) {
147 pd_list *old = pdl;
148 pdl = pdl->next;
149 free(old);
150 }
151}
152
153/*
154 * returns -1 if a < b, 0 if a == b, 1 if a > b
155 */
156int cmp_perfdata_value(const mp_perfdata_value a, const mp_perfdata_value b) {
157 // Test if types are different
158 if (a.type == b.type) {
159
160 switch (a.type) {
161 case PD_TYPE_UINT:
162 if (a.pd_uint < b.pd_uint) {
163 return -1;
164 } else if (a.pd_uint == b.pd_uint) {
165 return 0;
166 } else {
167 return 1;
168 }
169 break;
170 case PD_TYPE_INT:
171 if (a.pd_int < b.pd_int) {
172 return -1;
173 } else if (a.pd_int == b.pd_int) {
174 return 0;
175 } else {
176 return 1;
177 }
178 break;
179 case PD_TYPE_DOUBLE:
180 if (a.pd_int < b.pd_int) {
181 return -1;
182 } else if (a.pd_int == b.pd_int) {
183 return 0;
184 } else {
185 return 1;
186 }
187 break;
188 default:
189 die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__);
190 }
191 }
192
193 // Get dirty here
194 long double floating_a = 0;
195
196 switch (a.type) {
197 case PD_TYPE_UINT:
198 floating_a = a.pd_uint;
199 break;
200 case PD_TYPE_INT:
201 floating_a = a.pd_int;
202 break;
203 case PD_TYPE_DOUBLE:
204 floating_a = a.pd_double;
205 break;
206 default:
207 die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__);
208 }
209
210 long double floating_b = 0;
211 switch (b.type) {
212 case PD_TYPE_UINT:
213 floating_b = b.pd_uint;
214 break;
215 case PD_TYPE_INT:
216 floating_b = b.pd_int;
217 break;
218 case PD_TYPE_DOUBLE:
219 floating_b = b.pd_double;
220 break;
221 default:
222 die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__);
223 }
224
225 if (floating_a < floating_b) {
226 return -1;
227 }
228 if (floating_a == floating_b) {
229 return 0;
230 }
231 return 1;
232}
233
234char *mp_range_to_string(const mp_range input) {
235 char *result = "";
236 if (input.alert_on_inside_range == INSIDE) {
237 asprintf(&result, "@");
238 }
239
240 if (input.start_infinity) {
241 asprintf(&result, "%s~:", result);
242 } else {
243 asprintf(&result, "%s%s:", result, pd_value_to_string(input.start));
244 }
245
246 if (!input.end_infinity) {
247 asprintf(&result, "%s%s", result, pd_value_to_string(input.end));
248 }
249 return result;
250}
251
252mp_perfdata mp_set_pd_value_float(mp_perfdata pd, float value) { return mp_set_pd_value_double(pd, value); }
253
254mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) {
255 pd.value.pd_double = value;
256 pd.value.type = PD_TYPE_DOUBLE;
257 return pd;
258}
259
260mp_perfdata mp_set_pd_value_char(mp_perfdata pd, char value) { return mp_set_pd_value_long_long(pd, (long long)value); }
261
262mp_perfdata mp_set_pd_value_u_char(mp_perfdata pd, unsigned char value) { return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); }
263
264mp_perfdata mp_set_pd_value_int(mp_perfdata pd, int value) { return mp_set_pd_value_long_long(pd, (long long)value); }
265
266mp_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); }
267
268mp_perfdata mp_set_pd_value_long(mp_perfdata pd, long value) { return mp_set_pd_value_long_long(pd, (long long)value); }
269
270mp_perfdata mp_set_pd_value_u_long(mp_perfdata pd, unsigned long value) {
271 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value);
272}
273
274mp_perfdata mp_set_pd_value_long_long(mp_perfdata pd, long long value) {
275 pd.value.pd_int = value;
276 pd.value.type = PD_TYPE_INT;
277 return pd;
278}
279
280mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata pd, unsigned long long value) {
281 pd.value.pd_uint = value;
282 pd.value.type = PD_TYPE_UINT;
283 return pd;
284}
285
286mp_perfdata_value mp_create_pd_value_double(double value) {
287 mp_perfdata_value res = {0};
288 res.type = PD_TYPE_DOUBLE;
289 res.pd_double = value;
290 return res;
291}
292
293mp_perfdata_value mp_create_pd_value_float(float value) { return mp_create_pd_value_double((double)value); }
294
295mp_perfdata_value mp_create_pd_value_char(char value) { return mp_create_pd_value_long_long((long long)value); }
296
297mp_perfdata_value mp_create_pd_value_u_char(unsigned char value) { return mp_create_pd_value_u_long_long((unsigned long long)value); }
298
299mp_perfdata_value mp_create_pd_value_int(int value) { return mp_create_pd_value_long_long((long long)value); }
300
301mp_perfdata_value mp_create_pd_value_u_int(unsigned int value) { return mp_create_pd_value_u_long_long((unsigned long long)value); }
302
303mp_perfdata_value mp_create_pd_value_long(long value) { return mp_create_pd_value_long_long((long long)value); }
304
305mp_perfdata_value mp_create_pd_value_u_long(unsigned long value) { return mp_create_pd_value_u_long_long((unsigned long long)value); }
306
307mp_perfdata_value mp_create_pd_value_long_long(long long value) {
308 mp_perfdata_value res = {0};
309 res.type = PD_TYPE_INT;
310 res.pd_int = value;
311 return res;
312}
313
314mp_perfdata_value mp_create_pd_value_u_long_long(unsigned long long value) {
315 mp_perfdata_value res = {0};
316 res.type = PD_TYPE_UINT;
317 res.pd_uint = value;
318 return res;
319}
320
321char *fmt_range(range foo) { return foo.text; }
322
323typedef struct integer_parser_wrapper {
324 int error;
325 mp_perfdata_value value;
326} integer_parser_wrapper;
327
328typedef struct double_parser_wrapper {
329 int error;
330 mp_perfdata_value value;
331} double_parser_wrapper;
332
333typedef struct perfdata_value_parser_wrapper {
334 int error;
335 mp_perfdata_value value;
336} perfdata_value_parser_wrapper;
337
338double_parser_wrapper parse_double(const char *input);
339integer_parser_wrapper parse_integer(const char *input);
340perfdata_value_parser_wrapper parse_pd_value(const char *input);
341
342mp_range_parsed mp_parse_range_string(const char *input) {
343 if (input == NULL) {
344 mp_range_parsed result = {
345 .error = MP_RANGE_PARSING_FAILURE,
346 };
347 return result;
348 }
349
350 if (strlen(input) == 0) {
351 mp_range_parsed result = {
352 .error = MP_RANGE_PARSING_FAILURE,
353 };
354 return result;
355 }
356
357 mp_range_parsed result = {
358 .range = mp_range_init(),
359 .error = MP_PARSING_SUCCES,
360 };
361
362 if (input[0] == '@') {
363 // found an '@' at beginning, so invert the range logic
364 result.range.alert_on_inside_range = INSIDE;
365
366 // advance the pointer one symbol
367 input++;
368 }
369
370 char *working_copy = strdup(input);
371 input = working_copy;
372
373 char *separator = index(working_copy, ':');
374 if (separator != NULL) {
375 // Found a separator
376 // set the separator to 0, so we have two different strings
377 *separator = '\0';
378
379 if (input[0] == '~') {
380 // the beginning starts with '~', so it might be infinity
381 if (&input[1] != separator) {
382 // the next symbol after '~' is not the separator!
383 // so input is probably wrong
384 result.error = MP_RANGE_PARSING_FAILURE;
385 free(working_copy);
386 return result;
387 }
388
389 result.range.start_infinity = true;
390 } else {
391 // No '~' at the beginning, so this should be a number
392 result.range.start_infinity = false;
393 perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input);
394
395 if (parsed_pd.error != MP_PARSING_SUCCES) {
396 result.error = parsed_pd.error;
397 free(working_copy);
398 return result;
399 }
400
401 result.range.start = parsed_pd.value;
402 result.range.start_infinity = false;
403 }
404 // got the first part now
405 // advance the pointer
406 input = separator + 1;
407 }
408
409 // End part or no separator
410 if (input[0] == '\0') {
411 // the end is infinite
412 result.range.end_infinity = true;
413 } else {
414 perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input);
415
416 if (parsed_pd.error != MP_PARSING_SUCCES) {
417 result.error = parsed_pd.error;
418 return result;
419 }
420 result.range.end = parsed_pd.value;
421 result.range.end_infinity = false;
422 }
423 free(working_copy);
424 return result;
425}
426
427double_parser_wrapper parse_double(const char *input) {
428 double_parser_wrapper result = {
429 .error = MP_PARSING_SUCCES,
430 };
431
432 if (input == NULL) {
433 result.error = MP_PARSING_FAILURE;
434 return result;
435 }
436
437 char *endptr = NULL;
438 errno = 0;
439 double tmp = strtod(input, &endptr);
440
441 if (input == endptr) {
442 // man 3 strtod says, no conversion performed
443 result.error = MP_PARSING_FAILURE;
444 return result;
445 }
446
447 if (errno) {
448 // some other error
449 // TODO maybe differentiate a little bit
450 result.error = MP_PARSING_FAILURE;
451 return result;
452 }
453
454 result.value = mp_create_pd_value(tmp);
455 return result;
456}
457
458integer_parser_wrapper parse_integer(const char *input) {
459 integer_parser_wrapper result = {
460 .error = MP_PARSING_SUCCES,
461 };
462
463 if (input == NULL) {
464 result.error = MP_PARSING_FAILURE;
465 return result;
466 }
467
468 char *endptr = NULL;
469 errno = 0;
470 long long tmp = strtoll(input, &endptr, 0);
471
472 // validating *sigh*
473 if (*endptr != '\0') {
474 // something went wrong in strtoll
475 if (tmp == LLONG_MIN) {
476 // underflow
477 result.error = MP_RANGE_PARSING_UNDERFLOW;
478 return result;
479 }
480
481 if (tmp == LLONG_MAX) {
482 // overflow
483 result.error = MP_RANGE_PARSING_OVERFLOW;
484 return result;
485 }
486
487 // still wrong, but not sure why, probably invalid characters
488 if (errno == EINVAL) {
489 result.error = MP_RANGE_PARSING_INVALID_CHAR;
490 return result;
491 }
492
493 // some other error, do catch all here
494 result.error = MP_RANGE_PARSING_FAILURE;
495 return result;
496 }
497
498 // no error, should be fine
499 result.value = mp_create_pd_value(tmp);
500 return result;
501}
502
503perfdata_value_parser_wrapper parse_pd_value(const char *input) {
504 // try integer first
505 integer_parser_wrapper tmp_int = parse_integer(input);
506
507 if (tmp_int.error == MP_PARSING_SUCCES) {
508 perfdata_value_parser_wrapper result = {
509 .error = tmp_int.error,
510 .value = tmp_int.value,
511 };
512 return result;
513 }
514
515 double_parser_wrapper tmp_double = parse_double(input);
516 perfdata_value_parser_wrapper result = {};
517 if (tmp_double.error == MP_PARSING_SUCCES) {
518 result.error = tmp_double.error;
519 result.value = tmp_double.value;
520 } else {
521 result.error = tmp_double.error;
522 }
523 return result;
524}
525
526mp_perfdata mp_set_pd_max_value(mp_perfdata perfdata, mp_perfdata_value value) {
527 perfdata.max = value;
528 perfdata.max_present = true;
529 return perfdata;
530}
531
532mp_perfdata mp_set_pd_min_value(mp_perfdata perfdata, mp_perfdata_value value) {
533 perfdata.min = value;
534 perfdata.min_present = true;
535 return perfdata;
536}
537
538double mp_get_pd_value(mp_perfdata_value value) {
539 assert(value.type != PD_TYPE_NONE);
540 switch (value.type) {
541 case PD_TYPE_DOUBLE:
542 return value.pd_double;
543 case PD_TYPE_INT:
544 return (double)value.pd_int;
545 case PD_TYPE_UINT:
546 return (double)value.pd_uint;
547 default:
548 return 0; // just to make the compiler happy
549 }
550}
551
552mp_perfdata_value mp_pd_value_multiply(mp_perfdata_value left, mp_perfdata_value right) {
553 if (left.type == right.type) {
554 switch (left.type) {
555 case PD_TYPE_DOUBLE:
556 left.pd_double *= right.pd_double;
557 return left;
558 case PD_TYPE_INT:
559 left.pd_int *= right.pd_int;
560 return left;
561 case PD_TYPE_UINT:
562 left.pd_uint *= right.pd_uint;
563 return left;
564 default:
565 // what to here?
566 return left;
567 }
568 }
569
570 // Different types, oh boy, just do the lazy thing for now and switch to double
571 switch (left.type) {
572 case PD_TYPE_INT:
573 left.pd_double = (double)left.pd_int;
574 left.type = PD_TYPE_DOUBLE;
575 break;
576 case PD_TYPE_UINT:
577 left.pd_double = (double)left.pd_uint;
578 left.type = PD_TYPE_DOUBLE;
579 break;
580 }
581
582 switch (right.type) {
583 case PD_TYPE_INT:
584 right.pd_double = (double)right.pd_int;
585 right.type = PD_TYPE_DOUBLE;
586 break;
587 case PD_TYPE_UINT:
588 right.pd_double = (double)right.pd_uint;
589 right.type = PD_TYPE_DOUBLE;
590 break;
591 }
592
593 left.pd_double *= right.pd_double;
594 return left;
595}
596
597mp_range mp_range_multiply(mp_range range, mp_perfdata_value factor) {
598 if (!range.end_infinity) {
599 range.end = mp_pd_value_multiply(range.end, factor);
600 }
601 if (!range.start_infinity) {
602 range.start = mp_pd_value_multiply(range.start, factor);
603 }
604 return range;
605}
diff --git a/lib/perfdata.h b/lib/perfdata.h
new file mode 100644
index 00000000..7fd908a9
--- /dev/null
+++ b/lib/perfdata.h
@@ -0,0 +1,219 @@
1#pragma once
2
3#include "../config.h"
4
5#include <inttypes.h>
6#include <stdbool.h>
7
8// Enum for the specific type of a perfdata_value
9typedef enum pd_value_type {
10 PD_TYPE_NONE = 0,
11 PD_TYPE_INT,
12 PD_TYPE_UINT,
13 PD_TYPE_DOUBLE
14} pd_value_type;
15
16typedef struct {
17 enum pd_value_type type;
18 union {
19 long long pd_int;
20 unsigned long long pd_uint;
21 double pd_double;
22 };
23} mp_perfdata_value;
24
25#define MP_OUTSIDE false
26#define MP_INSIDE true
27
28/*
29 * New range type with generic numerical values
30 */
31typedef struct mp_range_struct {
32 mp_perfdata_value start;
33 bool start_infinity; /* false (default) or true */
34
35 mp_perfdata_value end;
36 bool end_infinity;
37
38 bool alert_on_inside_range; /* OUTSIDE (default) or INSIDE */
39} mp_range;
40
41/*
42 * Old range type with floating point values
43 */
44typedef struct range_struct {
45 double start;
46 bool start_infinity;
47 double end;
48 int end_infinity;
49 int alert_on; /* OUTSIDE (default) or INSIDE */
50 char *text; /* original unparsed text input */
51} range;
52
53/*
54 * Perfdata type for storing perfdata output
55 */
56typedef struct perfdata_struct {
57 char *label;
58 char *uom;
59 mp_perfdata_value value;
60
61 bool warn_present;
62 mp_range warn;
63
64 bool crit_present;
65 mp_range crit;
66
67 bool min_present;
68 mp_perfdata_value min;
69
70 bool max_present;
71 mp_perfdata_value max;
72} mp_perfdata;
73
74/*
75 * List of mp_perfdata values
76 */
77typedef struct pd_list_struct {
78 mp_perfdata data;
79 struct pd_list_struct *next;
80} pd_list;
81
82/*
83 * ============
84 * Initializers
85 * ============
86 */
87/*
88 * Initialize mp_perfdata value. Always use this to generate a new one
89 */
90mp_perfdata perfdata_init(void);
91
92/*
93 * Initialize pd_list value. Always use this to generate a new one
94 */
95pd_list *pd_list_init(void);
96
97/*
98 * Initialize a new mp_range value, with unset values (start and end are infinite
99 */
100mp_range mp_range_init(void);
101
102/*
103 * Worker functions
104 */
105
106mp_range mp_range_set_start(mp_range, mp_perfdata_value);
107mp_range mp_range_set_end(mp_range, mp_perfdata_value);
108
109/*
110 * Parsing a range from a string
111 */
112
113typedef enum {
114 MP_PARSING_SUCCES = 0,
115 MP_PARSING_FAILURE,
116 MP_RANGE_PARSING_FAILURE,
117 MP_RANGE_PARSING_UNDERFLOW,
118 MP_RANGE_PARSING_OVERFLOW,
119 MP_RANGE_PARSING_INVALID_CHAR,
120} mp_range_parser_error;
121
122typedef struct mp_range_parsed {
123 mp_range_parser_error error;
124 mp_range range;
125} mp_range_parsed;
126
127mp_range_parsed mp_parse_range_string(const char * /*input*/);
128
129/*
130 * Appends a mp_perfdata value to a pd_list
131 */
132void pd_list_append(pd_list[1], mp_perfdata);
133
134#define mp_set_pd_value(P, V) \
135 _Generic((V), \
136 float: mp_set_pd_value_float, \
137 double: mp_set_pd_value_double, \
138 int: mp_set_pd_value_int, \
139 unsigned int: mp_set_pd_value_u_int, \
140 long: mp_set_pd_value_long, \
141 unsigned long: mp_set_pd_value_u_long, \
142 long long: mp_set_pd_value_long_long, \
143 unsigned long long: mp_set_pd_value_u_long_long)(P, V)
144
145mp_perfdata mp_set_pd_value_float(mp_perfdata, float);
146mp_perfdata mp_set_pd_value_double(mp_perfdata, double);
147mp_perfdata mp_set_pd_value_int(mp_perfdata, int);
148mp_perfdata mp_set_pd_value_u_int(mp_perfdata, unsigned int);
149mp_perfdata mp_set_pd_value_long(mp_perfdata, long);
150mp_perfdata mp_set_pd_value_u_long(mp_perfdata, unsigned 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);
153
154#define mp_create_pd_value(V) \
155 _Generic((V), \
156 float: mp_create_pd_value_float, \
157 double: mp_create_pd_value_double, \
158 char: mp_create_pd_value_char, \
159 unsigned char: mp_create_pd_value_u_char, \
160 int: mp_create_pd_value_int, \
161 unsigned int: mp_create_pd_value_u_int, \
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, \
165 unsigned long long: mp_create_pd_value_u_long_long)(V)
166
167mp_perfdata_value mp_create_pd_value_float(float);
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);
171mp_perfdata_value mp_create_pd_value_int(int);
172mp_perfdata_value mp_create_pd_value_u_int(unsigned int);
173mp_perfdata_value mp_create_pd_value_long(long);
174mp_perfdata_value mp_create_pd_value_u_long(unsigned long);
175mp_perfdata_value mp_create_pd_value_long_long(long long);
176mp_perfdata_value mp_create_pd_value_u_long_long(unsigned long long);
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
183/*
184 * Free the memory used by a pd_list
185 */
186void pd_list_free(pd_list[1]);
187
188int cmp_perfdata_value(mp_perfdata_value, mp_perfdata_value);
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
197// =================
198// String formatters
199// =================
200/*
201 * Generate string from mp_perfdata value
202 */
203char *pd_to_string(mp_perfdata);
204
205/*
206 * Generate string from perfdata_value value
207 */
208char *pd_value_to_string(mp_perfdata_value);
209
210/*
211 * Generate string from pd_list value for the final output
212 */
213char *pd_list_to_string(pd_list);
214
215/*
216 * Generate string from a mp_range value
217 */
218char *mp_range_to_string(mp_range);
219char *fmt_range(range);
diff --git a/lib/states.h b/lib/states.h
new file mode 100644
index 00000000..4a170caa
--- /dev/null
+++ b/lib/states.h
@@ -0,0 +1,71 @@
1#ifndef _MP_STATES_
2#define _MP_STATES_
3
4#include "../config.h"
5#include <sys/param.h>
6
7typedef enum state_enum {
8 STATE_OK,
9 STATE_WARNING,
10 STATE_CRITICAL,
11 STATE_UNKNOWN,
12 STATE_DEPENDENT
13} mp_state_enum;
14
15/* **************************************************************************
16 * max_state(STATE_x, STATE_y)
17 * compares STATE_x to STATE_y and returns result based on the following
18 * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL
19 *
20 * Note that numerically the above does not hold
21 ****************************************************************************/
22
23static inline mp_state_enum max_state(mp_state_enum a, mp_state_enum b) {
24 if (a == STATE_CRITICAL || b == STATE_CRITICAL) {
25 return STATE_CRITICAL;
26 }
27 if (a == STATE_WARNING || b == STATE_WARNING) {
28 return STATE_WARNING;
29 }
30 if (a == STATE_OK || b == STATE_OK) {
31 return STATE_OK;
32 }
33 if (a == STATE_UNKNOWN || b == STATE_UNKNOWN) {
34 return STATE_UNKNOWN;
35 }
36 if (a == STATE_DEPENDENT || b == STATE_DEPENDENT) {
37 return STATE_DEPENDENT;
38 }
39 return MAX(a, b);
40}
41
42/* **************************************************************************
43 * max_state_alt(STATE_x, STATE_y)
44 * compares STATE_x to STATE_y and returns result based on the following
45 * STATE_OK < STATE_DEPENDENT < STATE_UNKNOWN < STATE_WARNING < STATE_CRITICAL
46 *
47 * The main difference between max_state_alt and max_state it that it doesn't
48 * allow setting a default to UNKNOWN. It will instead prioritixe any valid
49 * non-OK state.
50 ****************************************************************************/
51
52static inline mp_state_enum max_state_alt(mp_state_enum a, mp_state_enum b) {
53 if (a == STATE_CRITICAL || b == STATE_CRITICAL) {
54 return STATE_CRITICAL;
55 }
56 if (a == STATE_WARNING || b == STATE_WARNING) {
57 return STATE_WARNING;
58 }
59 if (a == STATE_UNKNOWN || b == STATE_UNKNOWN) {
60 return STATE_UNKNOWN;
61 }
62 if (a == STATE_DEPENDENT || b == STATE_DEPENDENT) {
63 return STATE_DEPENDENT;
64 }
65 if (a == STATE_OK || b == STATE_OK) {
66 return STATE_OK;
67 }
68 return MAX(a, b);
69}
70
71#endif
diff --git a/lib/tests/Makefile.am b/lib/tests/Makefile.am
index 31d79df6..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 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 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 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 05dd7943..94cb5aa9 100644
--- a/lib/tests/test_base64.c
+++ b/lib/tests/test_base64.c
@@ -1,29 +1,27 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* This program is free software: you can redistribute it and/or modify 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 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 5 * the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version. 6 * (at your option) any later version.
7* 7 *
8* This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details. 11 * GNU General Public License for more details.
12* 12 *
13* You should have received a copy of the GNU General Public License 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/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15* 15 *
16* 16 *
17*****************************************************************************/ 17 *****************************************************************************/
18 18
19#include "common.h" 19#include "common.h"
20#include "gl/base64.h" 20#include "gl/base64.h"
21#include "tap.h" 21#include "tap.h"
22 22
23int 23int main(int argc, char **argv) {
24main (int argc, char **argv) 24#if 0 /* The current base64 function doesn't work on 8bit data */
25{
26#if 0 /* The current base64 function doesn't work on 8bit data */
27 char random[1024] = { 25 char random[1024] = {
28 0x8b,0xb0,0xc4,0xe2,0xfc,0x22,0x9f,0x0d,0x85,0xe7,0x2c,0xaa,0x39,0xa1,0x46,0x88, 26 0x8b,0xb0,0xc4,0xe2,0xfc,0x22,0x9f,0x0d,0x85,0xe7,0x2c,0xaa,0x39,0xa1,0x46,0x88,
29 0x50,0xe6,0x34,0x37,0x0b,0x45,0x4b,0xb8,0xb2,0x86,0x7a,0x3e,0x7f,0x0c,0x40,0x18, 27 0x50,0xe6,0x34,0x37,0x0b,0x45,0x4b,0xb8,0xb2,0x86,0x7a,0x3e,0x7f,0x0c,0x40,0x18,
@@ -182,168 +180,124 @@ main (int argc, char **argv)
182#endif 180#endif
183 181
184 char random[1024] = { 182 char random[1024] = {
185 0x0b,0x30,0x44,0x62,0x7c,0x22,0x1f,0x0d,0x05,0x67,0x2c,0x2a,0x39,0x21,0x46,0x08, 183 0x0b, 0x30, 0x44, 0x62, 0x7c, 0x22, 0x1f, 0x0d, 0x05, 0x67, 0x2c, 0x2a, 0x39, 0x21, 0x46, 0x08, 0x50, 0x66, 0x34, 0x37, 0x0b, 0x45,
186 0x50,0x66,0x34,0x37,0x0b,0x45,0x4b,0x38,0x32,0x06,0x7a,0x3e,0x7f,0x0c,0x40,0x18, 184 0x4b, 0x38, 0x32, 0x06, 0x7a, 0x3e, 0x7f, 0x0c, 0x40, 0x18, 0x6b, 0x2d, 0x60, 0x4c, 0x60, 0x0c, 0x23, 0x43, 0x3b, 0x3e, 0x1b, 0x16,
187 0x6b,0x2d,0x60,0x4c,0x60,0x0c,0x23,0x43,0x3b,0x3e,0x1b,0x16,0x04,0x46,0x58,0x3f, 185 0x04, 0x46, 0x58, 0x3f, 0x40, 0x6a, 0x11, 0x05, 0x63, 0x71, 0x14, 0x35, 0x47, 0x79, 0x13, 0x6f, 0x6b, 0x27, 0x18, 0x5b, 0x48, 0x27,
188 0x40,0x6a,0x11,0x05,0x63,0x71,0x14,0x35,0x47,0x79,0x13,0x6f,0x6b,0x27,0x18,0x5b, 186 0x3e, 0x6f, 0x15, 0x33, 0x4f, 0x3e, 0x5e, 0x51, 0x73, 0x68, 0x25, 0x0f, 0x06, 0x5b, 0x7c, 0x72, 0x75, 0x3e, 0x3f, 0x1b, 0x5c, 0x6d,
189 0x48,0x27,0x3e,0x6f,0x15,0x33,0x4f,0x3e,0x5e,0x51,0x73,0x68,0x25,0x0f,0x06,0x5b, 187 0x6a, 0x39, 0x7c, 0x63, 0x63, 0x60, 0x6c, 0x7a, 0x33, 0x76, 0x52, 0x13, 0x25, 0x33, 0x7d, 0x65, 0x23, 0x27, 0x11, 0x06, 0x06, 0x47,
190 0x7c,0x72,0x75,0x3e,0x3f,0x1b,0x5c,0x6d,0x6a,0x39,0x7c,0x63,0x63,0x60,0x6c,0x7a, 188 0x71, 0x1e, 0x14, 0x74, 0x63, 0x70, 0x2d, 0x15, 0x27, 0x18, 0x51, 0x06, 0x05, 0x33, 0x11, 0x2c, 0x6b, 0x00, 0x2d, 0x77, 0x20, 0x48,
191 0x33,0x76,0x52,0x13,0x25,0x33,0x7d,0x65,0x23,0x27,0x11,0x06,0x06,0x47,0x71,0x1e, 189 0x0d, 0x73, 0x51, 0x45, 0x25, 0x7f, 0x7f, 0x35, 0x26, 0x2e, 0x26, 0x53, 0x24, 0x68, 0x1e, 0x0e, 0x58, 0x3a, 0x59, 0x50, 0x56, 0x37,
192 0x14,0x74,0x63,0x70,0x2d,0x15,0x27,0x18,0x51,0x06,0x05,0x33,0x11,0x2c,0x6b,0x00, 190 0x5f, 0x66, 0x01, 0x4c, 0x5a, 0x64, 0x32, 0x50, 0x7b, 0x6a, 0x20, 0x72, 0x2b, 0x1d, 0x7e, 0x43, 0x7b, 0x61, 0x42, 0x0b, 0x61, 0x73,
193 0x2d,0x77,0x20,0x48,0x0d,0x73,0x51,0x45,0x25,0x7f,0x7f,0x35,0x26,0x2e,0x26,0x53, 191 0x24, 0x79, 0x3a, 0x6b, 0x4a, 0x79, 0x6e, 0x09, 0x0f, 0x27, 0x2d, 0x0c, 0x5e, 0x32, 0x4b, 0x0d, 0x79, 0x46, 0x39, 0x21, 0x0a, 0x26,
194 0x24,0x68,0x1e,0x0e,0x58,0x3a,0x59,0x50,0x56,0x37,0x5f,0x66,0x01,0x4c,0x5a,0x64, 192 0x5f, 0x3a, 0x00, 0x26, 0x3f, 0x13, 0x2e, 0x7e, 0x50, 0x2b, 0x67, 0x46, 0x72, 0x3f, 0x3b, 0x01, 0x46, 0x1b, 0x0b, 0x35, 0x49, 0x39,
195 0x32,0x50,0x7b,0x6a,0x20,0x72,0x2b,0x1d,0x7e,0x43,0x7b,0x61,0x42,0x0b,0x61,0x73, 193 0x19, 0x70, 0x3d, 0x02, 0x41, 0x0e, 0x38, 0x05, 0x76, 0x65, 0x4f, 0x31, 0x6c, 0x5e, 0x17, 0x04, 0x15, 0x36, 0x26, 0x64, 0x34, 0x14,
196 0x24,0x79,0x3a,0x6b,0x4a,0x79,0x6e,0x09,0x0f,0x27,0x2d,0x0c,0x5e,0x32,0x4b,0x0d, 194 0x17, 0x7c, 0x0e, 0x0b, 0x5b, 0x55, 0x53, 0x6b, 0x00, 0x42, 0x41, 0x4f, 0x02, 0x5c, 0x13, 0x0a, 0x2c, 0x2c, 0x3e, 0x10, 0x14, 0x33,
197 0x79,0x46,0x39,0x21,0x0a,0x26,0x5f,0x3a,0x00,0x26,0x3f,0x13,0x2e,0x7e,0x50,0x2b, 195 0x45, 0x7c, 0x7a, 0x5a, 0x31, 0x61, 0x39, 0x08, 0x22, 0x6a, 0x1e, 0x0f, 0x6f, 0x1b, 0x6c, 0x13, 0x5e, 0x79, 0x20, 0x79, 0x50, 0x62,
198 0x67,0x46,0x72,0x3f,0x3b,0x01,0x46,0x1b,0x0b,0x35,0x49,0x39,0x19,0x70,0x3d,0x02, 196 0x06, 0x2c, 0x76, 0x17, 0x04, 0x2b, 0x2a, 0x75, 0x1f, 0x0c, 0x37, 0x4e, 0x0f, 0x7b, 0x2d, 0x34, 0x75, 0x60, 0x31, 0x74, 0x2e, 0x0a,
199 0x41,0x0e,0x38,0x05,0x76,0x65,0x4f,0x31,0x6c,0x5e,0x17,0x04,0x15,0x36,0x26,0x64, 197 0x4a, 0x11, 0x6c, 0x49, 0x25, 0x01, 0x3a, 0x3d, 0x22, 0x1e, 0x6d, 0x18, 0x51, 0x78, 0x2d, 0x62, 0x31, 0x4c, 0x50, 0x40, 0x17, 0x4b,
200 0x34,0x14,0x17,0x7c,0x0e,0x0b,0x5b,0x55,0x53,0x6b,0x00,0x42,0x41,0x4f,0x02,0x5c, 198 0x6f, 0x22, 0x00, 0x7f, 0x61, 0x2a, 0x34, 0x3e, 0x00, 0x5f, 0x2f, 0x5f, 0x2f, 0x14, 0x2a, 0x55, 0x27, 0x1f, 0x46, 0x1f, 0x12, 0x46,
201 0x13,0x0a,0x2c,0x2c,0x3e,0x10,0x14,0x33,0x45,0x7c,0x7a,0x5a,0x31,0x61,0x39,0x08, 199 0x5e, 0x1e, 0x0c, 0x7c, 0x38, 0x01, 0x61, 0x64, 0x76, 0x22, 0x6e, 0x08, 0x20, 0x38, 0x4f, 0x73, 0x72, 0x55, 0x12, 0x42, 0x19, 0x50,
202 0x22,0x6a,0x1e,0x0f,0x6f,0x1b,0x6c,0x13,0x5e,0x79,0x20,0x79,0x50,0x62,0x06,0x2c, 200 0x61, 0x43, 0x77, 0x7d, 0x41, 0x2e, 0x35, 0x4f, 0x3d, 0x31, 0x28, 0x58, 0x67, 0x1b, 0x03, 0x51, 0x20, 0x32, 0x1c, 0x08, 0x6e, 0x37,
203 0x76,0x17,0x04,0x2b,0x2a,0x75,0x1f,0x0c,0x37,0x4e,0x0f,0x7b,0x2d,0x34,0x75,0x60, 201 0x75, 0x37, 0x44, 0x4f, 0x68, 0x19, 0x07, 0x64, 0x14, 0x28, 0x25, 0x2b, 0x69, 0x35, 0x18, 0x27, 0x26, 0x14, 0x13, 0x70, 0x42, 0x19,
204 0x31,0x74,0x2e,0x0a,0x4a,0x11,0x6c,0x49,0x25,0x01,0x3a,0x3d,0x22,0x1e,0x6d,0x18, 202 0x12, 0x75, 0x3e, 0x02, 0x5d, 0x7c, 0x13, 0x1f, 0x16, 0x53, 0x3b, 0x74, 0x48, 0x3c, 0x5e, 0x39, 0x6c, 0x1c, 0x1c, 0x74, 0x39, 0x1f,
205 0x51,0x78,0x2d,0x62,0x31,0x4c,0x50,0x40,0x17,0x4b,0x6f,0x22,0x00,0x7f,0x61,0x2a, 203 0x00, 0x1b, 0x06, 0x0a, 0x68, 0x3b, 0x52, 0x4f, 0x1e, 0x6e, 0x3c, 0x35, 0x0c, 0x38, 0x0e, 0x0b, 0x3b, 0x1a, 0x76, 0x23, 0x29, 0x53,
206 0x34,0x3e,0x00,0x5f,0x2f,0x5f,0x2f,0x14,0x2a,0x55,0x27,0x1f,0x46,0x1f,0x12,0x46, 204 0x1e, 0x5f, 0x41, 0x0c, 0x4b, 0x0a, 0x65, 0x28, 0x78, 0x67, 0x48, 0x59, 0x26, 0x6d, 0x31, 0x76, 0x23, 0x70, 0x61, 0x64, 0x3b, 0x38,
207 0x5e,0x1e,0x0c,0x7c,0x38,0x01,0x61,0x64,0x76,0x22,0x6e,0x08,0x20,0x38,0x4f,0x73, 205 0x79, 0x66, 0x74, 0x53, 0x2c, 0x64, 0x64, 0x54, 0x03, 0x54, 0x65, 0x44, 0x4c, 0x18, 0x4f, 0x48, 0x20, 0x4f, 0x72, 0x10, 0x3f, 0x0c,
208 0x72,0x55,0x12,0x42,0x19,0x50,0x61,0x43,0x77,0x7d,0x41,0x2e,0x35,0x4f,0x3d,0x31, 206 0x52, 0x2d, 0x03, 0x14, 0x03, 0x51, 0x42, 0x10, 0x77, 0x6a, 0x34, 0x06, 0x32, 0x03, 0x72, 0x14, 0x7c, 0x08, 0x5d, 0x52, 0x1a, 0x62,
209 0x28,0x58,0x67,0x1b,0x03,0x51,0x20,0x32,0x1c,0x08,0x6e,0x37,0x75,0x37,0x44,0x4f, 207 0x7c, 0x3e, 0x30, 0x7e, 0x5f, 0x7f, 0x54, 0x0f, 0x44, 0x49, 0x5d, 0x5e, 0x10, 0x6a, 0x06, 0x2b, 0x06, 0x53, 0x10, 0x39, 0x37, 0x32,
210 0x68,0x19,0x07,0x64,0x14,0x28,0x25,0x2b,0x69,0x35,0x18,0x27,0x26,0x14,0x13,0x70, 208 0x4a, 0x4e, 0x3d, 0x2b, 0x65, 0x38, 0x39, 0x07, 0x72, 0x54, 0x64, 0x4d, 0x56, 0x6a, 0x03, 0x22, 0x70, 0x7b, 0x5f, 0x60, 0x0b, 0x2a,
211 0x42,0x19,0x12,0x75,0x3e,0x02,0x5d,0x7c,0x13,0x1f,0x16,0x53,0x3b,0x74,0x48,0x3c, 209 0x0b, 0x6b, 0x10, 0x64, 0x14, 0x05, 0x22, 0x00, 0x73, 0x40, 0x23, 0x5b, 0x51, 0x1f, 0x2b, 0x1a, 0x5d, 0x69, 0x7a, 0x46, 0x0c, 0x5f,
212 0x5e,0x39,0x6c,0x1c,0x1c,0x74,0x39,0x1f,0x00,0x1b,0x06,0x0a,0x68,0x3b,0x52,0x4f, 210 0x32, 0x4b, 0x4a, 0x28, 0x52, 0x79, 0x5b, 0x12, 0x42, 0x18, 0x00, 0x5d, 0x27, 0x31, 0x53, 0x3c, 0x4c, 0x36, 0x4e, 0x38, 0x3f, 0x72,
213 0x1e,0x6e,0x3c,0x35,0x0c,0x38,0x0e,0x0b,0x3b,0x1a,0x76,0x23,0x29,0x53,0x1e,0x5f, 211 0x03, 0x71, 0x02, 0x5b, 0x36, 0x59, 0x7f, 0x75, 0x6e, 0x08, 0x54, 0x0d, 0x34, 0x1c, 0x34, 0x57, 0x5d, 0x69, 0x48, 0x00, 0x3b, 0x05,
214 0x41,0x0c,0x4b,0x0a,0x65,0x28,0x78,0x67,0x48,0x59,0x26,0x6d,0x31,0x76,0x23,0x70, 212 0x07, 0x6e, 0x27, 0x65, 0x6e, 0x40, 0x3d, 0x3a, 0x4f, 0x72, 0x5d, 0x39, 0x16, 0x0f, 0x63, 0x12, 0x12, 0x15, 0x3a, 0x70, 0x0d, 0x57,
215 0x61,0x64,0x3b,0x38,0x79,0x66,0x74,0x53,0x2c,0x64,0x64,0x54,0x03,0x54,0x65,0x44, 213 0x18, 0x0d, 0x5e, 0x3d, 0x22, 0x68, 0x68, 0x7c, 0x6d, 0x4f, 0x0c, 0x7b, 0x09, 0x2d, 0x4a, 0x73, 0x20, 0x47, 0x07, 0x57, 0x75, 0x5d,
216 0x4c,0x18,0x4f,0x48,0x20,0x4f,0x72,0x10,0x3f,0x0c,0x52,0x2d,0x03,0x14,0x03,0x51, 214 0x53, 0x70, 0x34, 0x21, 0x40, 0x57, 0x51, 0x5e, 0x49, 0x44, 0x00, 0x54, 0x27, 0x04, 0x68, 0x7e, 0x59, 0x56, 0x58, 0x74, 0x14, 0x3c,
217 0x42,0x10,0x77,0x6a,0x34,0x06,0x32,0x03,0x72,0x14,0x7c,0x08,0x5d,0x52,0x1a,0x62, 215 0x16, 0x33, 0x41, 0x16, 0x4b, 0x2f, 0x49, 0x37, 0x0a, 0x54, 0x08, 0x08, 0x1f, 0x39, 0x67, 0x76, 0x28, 0x28, 0x07, 0x1d, 0x61, 0x47,
218 0x7c,0x3e,0x30,0x7e,0x5f,0x7f,0x54,0x0f,0x44,0x49,0x5d,0x5e,0x10,0x6a,0x06,0x2b, 216 0x51, 0x4d, 0x75, 0x26, 0x52, 0x47, 0x47, 0x0c, 0x57, 0x58, 0x74, 0x3e, 0x62, 0x6c, 0x58, 0x3a, 0x44, 0x1e, 0x16, 0x2e, 0x21, 0x1c,
219 0x06,0x53,0x10,0x39,0x37,0x32,0x4a,0x4e,0x3d,0x2b,0x65,0x38,0x39,0x07,0x72,0x54, 217 0x73, 0x45, 0x67, 0x74, 0x4f, 0x33, 0x66, 0x0e, 0x74, 0x66, 0x26, 0x1f, 0x2e, 0x38, 0x44, 0x40, 0x7e, 0x2a, 0x50, 0x52, 0x5e, 0x43,
220 0x64,0x4d,0x56,0x6a,0x03,0x22,0x70,0x7b,0x5f,0x60,0x0b,0x2a,0x0b,0x6b,0x10,0x64, 218 0x01, 0x7a, 0x38, 0x49, 0x3c, 0x55, 0x4d, 0x5a, 0x44, 0x08, 0x26, 0x59, 0x4d, 0x45, 0x0b, 0x48, 0x0a, 0x33, 0x5e, 0x4a, 0x4d, 0x75,
221 0x14,0x05,0x22,0x00,0x73,0x40,0x23,0x5b,0x51,0x1f,0x2b,0x1a,0x5d,0x69,0x7a,0x46, 219 0x16, 0x17, 0x63, 0x46, 0x01, 0x2a, 0x55, 0x7b, 0x0f, 0x02, 0x73, 0x6a, 0x4b, 0x7f, 0x75, 0x65, 0x3c, 0x4c, 0x33, 0x39, 0x6c, 0x74,
222 0x0c,0x5f,0x32,0x4b,0x4a,0x28,0x52,0x79,0x5b,0x12,0x42,0x18,0x00,0x5d,0x27,0x31, 220 0x05, 0x60, 0x0f, 0x7f, 0x2d, 0x41, 0x4d, 0x4d, 0x46, 0x71, 0x09, 0x6f, 0x4f, 0x60, 0x15, 0x0f, 0x46, 0x73, 0x63, 0x4c, 0x5e, 0x74,
223 0x53,0x3c,0x4c,0x36,0x4e,0x38,0x3f,0x72,0x03,0x71,0x02,0x5b,0x36,0x59,0x7f,0x75, 221 0x30, 0x0d, 0x28, 0x43, 0x08, 0x72, 0x32, 0x04, 0x2e, 0x31, 0x29, 0x27, 0x44, 0x6d, 0x13, 0x17, 0x48, 0x0f, 0x49, 0x52, 0x10, 0x13,
224 0x6e,0x08,0x54,0x0d,0x34,0x1c,0x34,0x57,0x5d,0x69,0x48,0x00,0x3b,0x05,0x07,0x6e, 222 0x7f, 0x17, 0x16, 0x62, 0x79, 0x35, 0x78, 0x3e, 0x01, 0x7c, 0x2e, 0x0f, 0x76, 0x3e, 0x5e, 0x53, 0x6c, 0x5b, 0x5f, 0x7c, 0x19, 0x41,
225 0x27,0x65,0x6e,0x40,0x3d,0x3a,0x4f,0x72,0x5d,0x39,0x16,0x0f,0x63,0x12,0x12,0x15, 223 0x02, 0x2f, 0x17, 0x64, 0x41, 0x75, 0x10, 0x04, 0x47, 0x7c, 0x3d, 0x4b, 0x52, 0x00, 0x10, 0x5d, 0x51, 0x4e, 0x7a, 0x27, 0x25, 0x55,
226 0x3a,0x70,0x0d,0x57,0x18,0x0d,0x5e,0x3d,0x22,0x68,0x68,0x7c,0x6d,0x4f,0x0c,0x7b, 224 0x40, 0x12, 0x35, 0x60, 0x05, 0x1b, 0x34, 0x2d, 0x04, 0x7a, 0x6a, 0x69, 0x02, 0x79, 0x03, 0x3a, 0x2f, 0x06, 0x0a, 0x79, 0x7b, 0x12,
227 0x09,0x2d,0x4a,0x73,0x20,0x47,0x07,0x57,0x75,0x5d,0x53,0x70,0x34,0x21,0x40,0x57, 225 0x5d, 0x7c, 0x52, 0x29, 0x47, 0x58, 0x12, 0x73, 0x3f, 0x27, 0x56, 0x05, 0x0c, 0x48, 0x32, 0x58, 0x6b, 0x57, 0x5c, 0x03, 0x64, 0x56,
228 0x51,0x5e,0x49,0x44,0x00,0x54,0x27,0x04,0x68,0x7e,0x59,0x56,0x58,0x74,0x14,0x3c, 226 0x11, 0x52, 0x7a, 0x30, 0x36, 0x29, 0x17, 0x3b, 0x68, 0x7a, 0x7c, 0x05, 0x6b, 0x6b, 0x13, 0x6a, 0x24, 0x5c, 0x68, 0x42, 0x18, 0x32,
229 0x16,0x33,0x41,0x16,0x4b,0x2f,0x49,0x37,0x0a,0x54,0x08,0x08,0x1f,0x39,0x67,0x76, 227 0x03, 0x73, 0x6e, 0x04, 0x21, 0x2e, 0x01, 0x04, 0x63, 0x7d, 0x44, 0x41, 0x12, 0x31, 0x0b, 0x15, 0x1f, 0x70, 0x00, 0x2e, 0x66, 0x14,
230 0x28,0x28,0x07,0x1d,0x61,0x47,0x51,0x4d,0x75,0x26,0x52,0x47,0x47,0x0c,0x57,0x58, 228 0x3c, 0x7f, 0x2b, 0x00, 0x1f, 0x0c, 0x28, 0x59, 0x0a, 0x16, 0x49, 0x5a, 0x5c, 0x64, 0x65, 0x4b, 0x11, 0x29, 0x15, 0x36, 0x5a, 0x65,
231 0x74,0x3e,0x62,0x6c,0x58,0x3a,0x44,0x1e,0x16,0x2e,0x21,0x1c,0x73,0x45,0x67,0x74, 229 0x19, 0x4f, 0x60, 0x23, 0x3a, 0x3a, 0x13, 0x25, 0x02, 0x78, 0x4c, 0x54};
232 0x4f,0x33,0x66,0x0e,0x74,0x66,0x26,0x1f,0x2e,0x38,0x44,0x40,0x7e,0x2a,0x50,0x52, 230 char b64_known[1369] = {
233 0x5e,0x43,0x01,0x7a,0x38,0x49,0x3c,0x55,0x4d,0x5a,0x44,0x08,0x26,0x59,0x4d,0x45, 231 0x43, 0x7a, 0x42, 0x45, 0x59, 0x6e, 0x77, 0x69, 0x48, 0x77, 0x30, 0x46, 0x5a, 0x79, 0x77, 0x71, 0x4f, 0x53, 0x46, 0x47, 0x43, 0x46,
234 0x0b,0x48,0x0a,0x33,0x5e,0x4a,0x4d,0x75,0x16,0x17,0x63,0x46,0x01,0x2a,0x55,0x7b, 232 0x42, 0x6d, 0x4e, 0x44, 0x63, 0x4c, 0x52, 0x55, 0x73, 0x34, 0x4d, 0x67, 0x5a, 0x36, 0x50, 0x6e, 0x38, 0x4d, 0x51, 0x42, 0x68, 0x72,
235 0x0f,0x02,0x73,0x6a,0x4b,0x7f,0x75,0x65,0x3c,0x4c,0x33,0x39,0x6c,0x74,0x05,0x60, 233 0x4c, 0x57, 0x42, 0x4d, 0x59, 0x41, 0x77, 0x6a, 0x51, 0x7a, 0x73, 0x2b, 0x47, 0x78, 0x59, 0x45, 0x52, 0x6c, 0x67, 0x2f, 0x51, 0x47,
236 0x0f,0x7f,0x2d,0x41,0x4d,0x4d,0x46,0x71,0x09,0x6f,0x4f,0x60,0x15,0x0f,0x46,0x73, 234 0x6f, 0x52, 0x42, 0x57, 0x4e, 0x78, 0x46, 0x44, 0x56, 0x48, 0x65, 0x52, 0x4e, 0x76, 0x61, 0x79, 0x63, 0x59, 0x57, 0x30, 0x67, 0x6e,
237 0x63,0x4c,0x5e,0x74,0x30,0x0d,0x28,0x43,0x08,0x72,0x32,0x04,0x2e,0x31,0x29,0x27, 235 0x50, 0x6d, 0x38, 0x56, 0x4d, 0x30, 0x38, 0x2b, 0x58, 0x6c, 0x46, 0x7a, 0x61, 0x43, 0x55, 0x50, 0x42, 0x6c, 0x74, 0x38, 0x63, 0x6e,
238 0x44,0x6d,0x13,0x17,0x48,0x0f,0x49,0x52,0x10,0x13,0x7f,0x17,0x16,0x62,0x79,0x35, 236 0x55, 0x2b, 0x50, 0x78, 0x74, 0x63, 0x62, 0x57, 0x6f, 0x35, 0x66, 0x47, 0x4e, 0x6a, 0x59, 0x47, 0x78, 0x36, 0x4d, 0x33, 0x5a, 0x53,
239 0x78,0x3e,0x01,0x7c,0x2e,0x0f,0x76,0x3e,0x5e,0x53,0x6c,0x5b,0x5f,0x7c,0x19,0x41, 237 0x45, 0x79, 0x55, 0x7a, 0x66, 0x57, 0x55, 0x6a, 0x4a, 0x78, 0x45, 0x47, 0x42, 0x6b, 0x64, 0x78, 0x48, 0x68, 0x52, 0x30, 0x59, 0x33,
240 0x02,0x2f,0x17,0x64,0x41,0x75,0x10,0x04,0x47,0x7c,0x3d,0x4b,0x52,0x00,0x10,0x5d, 238 0x41, 0x74, 0x46, 0x53, 0x63, 0x59, 0x55, 0x51, 0x59, 0x46, 0x4d, 0x78, 0x45, 0x73, 0x61, 0x77, 0x41, 0x74, 0x64, 0x79, 0x42, 0x49,
241 0x51,0x4e,0x7a,0x27,0x25,0x55,0x40,0x12,0x35,0x60,0x05,0x1b,0x34,0x2d,0x04,0x7a, 239 0x44, 0x58, 0x4e, 0x52, 0x52, 0x53, 0x56, 0x2f, 0x66, 0x7a, 0x55, 0x6d, 0x4c, 0x69, 0x5a, 0x54, 0x4a, 0x47, 0x67, 0x65, 0x44, 0x6c,
242 0x6a,0x69,0x02,0x79,0x03,0x3a,0x2f,0x06,0x0a,0x79,0x7b,0x12,0x5d,0x7c,0x52,0x29, 240 0x67, 0x36, 0x57, 0x56, 0x42, 0x57, 0x4e, 0x31, 0x39, 0x6d, 0x41, 0x55, 0x78, 0x61, 0x5a, 0x44, 0x4a, 0x51, 0x65, 0x32, 0x6f, 0x67,
243 0x47,0x58,0x12,0x73,0x3f,0x27,0x56,0x05,0x0c,0x48,0x32,0x58,0x6b,0x57,0x5c,0x03, 241 0x63, 0x69, 0x73, 0x64, 0x66, 0x6b, 0x4e, 0x37, 0x59, 0x55, 0x49, 0x4c, 0x59, 0x58, 0x4d, 0x6b, 0x65, 0x54, 0x70, 0x72, 0x53, 0x6e,
244 0x64,0x56,0x11,0x52,0x7a,0x30,0x36,0x29,0x17,0x3b,0x68,0x7a,0x7c,0x05,0x6b,0x6b, 242 0x6c, 0x75, 0x43, 0x51, 0x38, 0x6e, 0x4c, 0x51, 0x78, 0x65, 0x4d, 0x6b, 0x73, 0x4e, 0x65, 0x55, 0x59, 0x35, 0x49, 0x51, 0x6f, 0x6d,
245 0x13,0x6a,0x24,0x5c,0x68,0x42,0x18,0x32,0x03,0x73,0x6e,0x04,0x21,0x2e,0x01,0x04, 243 0x58, 0x7a, 0x6f, 0x41, 0x4a, 0x6a, 0x38, 0x54, 0x4c, 0x6e, 0x35, 0x51, 0x4b, 0x32, 0x64, 0x47, 0x63, 0x6a, 0x38, 0x37, 0x41, 0x55,
246 0x63,0x7d,0x44,0x41,0x12,0x31,0x0b,0x15,0x1f,0x70,0x00,0x2e,0x66,0x14,0x3c,0x7f, 244 0x59, 0x62, 0x43, 0x7a, 0x56, 0x4a, 0x4f, 0x52, 0x6c, 0x77, 0x50, 0x51, 0x4a, 0x42, 0x44, 0x6a, 0x67, 0x46, 0x64, 0x6d, 0x56, 0x50,
247 0x2b,0x00,0x1f,0x0c,0x28,0x59,0x0a,0x16,0x49,0x5a,0x5c,0x64,0x65,0x4b,0x11,0x29, 245 0x4d, 0x57, 0x78, 0x65, 0x46, 0x77, 0x51, 0x56, 0x4e, 0x69, 0x5a, 0x6b, 0x4e, 0x42, 0x51, 0x58, 0x66, 0x41, 0x34, 0x4c, 0x57, 0x31,
248 0x15,0x36,0x5a,0x65,0x19,0x4f,0x60,0x23,0x3a,0x3a,0x13,0x25,0x02,0x78,0x4c,0x54 246 0x56, 0x54, 0x61, 0x77, 0x42, 0x43, 0x51, 0x55, 0x38, 0x43, 0x58, 0x42, 0x4d, 0x4b, 0x4c, 0x43, 0x77, 0x2b, 0x45, 0x42, 0x51, 0x7a,
249 }; 247 0x52, 0x58, 0x78, 0x36, 0x57, 0x6a, 0x46, 0x68, 0x4f, 0x51, 0x67, 0x69, 0x61, 0x68, 0x34, 0x50, 0x62, 0x78, 0x74, 0x73, 0x45, 0x31,
250 char b64_known[1369] = { 248 0x35, 0x35, 0x49, 0x48, 0x6c, 0x51, 0x59, 0x67, 0x59, 0x73, 0x64, 0x68, 0x63, 0x45, 0x4b, 0x79, 0x70, 0x31, 0x48, 0x77, 0x77, 0x33,
251 0x43,0x7a,0x42,0x45,0x59,0x6e,0x77,0x69,0x48,0x77,0x30,0x46,0x5a,0x79,0x77,0x71, 249 0x54, 0x67, 0x39, 0x37, 0x4c, 0x54, 0x52, 0x31, 0x59, 0x44, 0x46, 0x30, 0x4c, 0x67, 0x70, 0x4b, 0x45, 0x57, 0x78, 0x4a, 0x4a, 0x51,
252 0x4f,0x53,0x46,0x47,0x43,0x46,0x42,0x6d,0x4e,0x44,0x63,0x4c,0x52,0x55,0x73,0x34, 250 0x45, 0x36, 0x50, 0x53, 0x49, 0x65, 0x62, 0x52, 0x68, 0x52, 0x65, 0x43, 0x31, 0x69, 0x4d, 0x55, 0x78, 0x51, 0x51, 0x42, 0x64, 0x4c,
253 0x4d,0x67,0x5a,0x36,0x50,0x6e,0x38,0x4d,0x51,0x42,0x68,0x72,0x4c,0x57,0x42,0x4d, 251 0x62, 0x79, 0x49, 0x41, 0x66, 0x32, 0x45, 0x71, 0x4e, 0x44, 0x34, 0x41, 0x58, 0x79, 0x39, 0x66, 0x4c, 0x78, 0x51, 0x71, 0x56, 0x53,
254 0x59,0x41,0x77,0x6a,0x51,0x7a,0x73,0x2b,0x47,0x78,0x59,0x45,0x52,0x6c,0x67,0x2f, 252 0x63, 0x66, 0x52, 0x68, 0x38, 0x53, 0x52, 0x6c, 0x34, 0x65, 0x44, 0x48, 0x77, 0x34, 0x41, 0x57, 0x46, 0x6b, 0x64, 0x69, 0x4a, 0x75,
255 0x51,0x47,0x6f,0x52,0x42,0x57,0x4e,0x78,0x46,0x44,0x56,0x48,0x65,0x52,0x4e,0x76, 253 0x43, 0x43, 0x41, 0x34, 0x54, 0x33, 0x4e, 0x79, 0x56, 0x52, 0x4a, 0x43, 0x47, 0x56, 0x42, 0x68, 0x51, 0x33, 0x64, 0x39, 0x51, 0x53,
256 0x61,0x79,0x63,0x59,0x57,0x30,0x67,0x6e,0x50,0x6d,0x38,0x56,0x4d,0x30,0x38,0x2b, 254 0x34, 0x31, 0x54, 0x7a, 0x30, 0x78, 0x4b, 0x46, 0x68, 0x6e, 0x47, 0x77, 0x4e, 0x52, 0x49, 0x44, 0x49, 0x63, 0x43, 0x47, 0x34, 0x33,
257 0x58,0x6c,0x46,0x7a,0x61,0x43,0x55,0x50,0x42,0x6c,0x74,0x38,0x63,0x6e,0x55,0x2b, 255 0x64, 0x54, 0x64, 0x45, 0x54, 0x32, 0x67, 0x5a, 0x42, 0x32, 0x51, 0x55, 0x4b, 0x43, 0x55, 0x72, 0x61, 0x54, 0x55, 0x59, 0x4a, 0x79,
258 0x50,0x78,0x74,0x63,0x62,0x57,0x6f,0x35,0x66,0x47,0x4e,0x6a,0x59,0x47,0x78,0x36, 256 0x59, 0x55, 0x45, 0x33, 0x42, 0x43, 0x47, 0x52, 0x4a, 0x31, 0x50, 0x67, 0x4a, 0x64, 0x66, 0x42, 0x4d, 0x66, 0x46, 0x6c, 0x4d, 0x37,
259 0x4d,0x33,0x5a,0x53,0x45,0x79,0x55,0x7a,0x66,0x57,0x55,0x6a,0x4a,0x78,0x45,0x47, 257 0x64, 0x45, 0x67, 0x38, 0x58, 0x6a, 0x6c, 0x73, 0x48, 0x42, 0x78, 0x30, 0x4f, 0x52, 0x38, 0x41, 0x47, 0x77, 0x59, 0x4b, 0x61, 0x44,
260 0x42,0x6b,0x64,0x78,0x48,0x68,0x52,0x30,0x59,0x33,0x41,0x74,0x46,0x53,0x63,0x59, 258 0x74, 0x53, 0x54, 0x78, 0x35, 0x75, 0x50, 0x44, 0x55, 0x4d, 0x4f, 0x41, 0x34, 0x4c, 0x4f, 0x78, 0x70, 0x32, 0x49, 0x79, 0x6c, 0x54,
261 0x55,0x51,0x59,0x46,0x4d,0x78,0x45,0x73,0x61,0x77,0x41,0x74,0x64,0x79,0x42,0x49, 259 0x48, 0x6c, 0x39, 0x42, 0x44, 0x45, 0x73, 0x4b, 0x5a, 0x53, 0x68, 0x34, 0x5a, 0x30, 0x68, 0x5a, 0x4a, 0x6d, 0x30, 0x78, 0x64, 0x69,
262 0x44,0x58,0x4e,0x52,0x52,0x53,0x56,0x2f,0x66,0x7a,0x55,0x6d,0x4c,0x69,0x5a,0x54, 260 0x4e, 0x77, 0x59, 0x57, 0x51, 0x37, 0x4f, 0x48, 0x6c, 0x6d, 0x64, 0x46, 0x4d, 0x73, 0x5a, 0x47, 0x52, 0x55, 0x41, 0x31, 0x52, 0x6c,
263 0x4a,0x47,0x67,0x65,0x44,0x6c,0x67,0x36,0x57,0x56,0x42,0x57,0x4e,0x31,0x39,0x6d, 261 0x52, 0x45, 0x77, 0x59, 0x54, 0x30, 0x67, 0x67, 0x54, 0x33, 0x49, 0x51, 0x50, 0x77, 0x78, 0x53, 0x4c, 0x51, 0x4d, 0x55, 0x41, 0x31,
264 0x41,0x55,0x78,0x61,0x5a,0x44,0x4a,0x51,0x65,0x32,0x6f,0x67,0x63,0x69,0x73,0x64, 262 0x46, 0x43, 0x45, 0x48, 0x64, 0x71, 0x4e, 0x41, 0x59, 0x79, 0x41, 0x33, 0x49, 0x55, 0x66, 0x41, 0x68, 0x64, 0x55, 0x68, 0x70, 0x69,
265 0x66,0x6b,0x4e,0x37,0x59,0x55,0x49,0x4c,0x59,0x58,0x4d,0x6b,0x65,0x54,0x70,0x72, 263 0x66, 0x44, 0x34, 0x77, 0x66, 0x6c, 0x39, 0x2f, 0x56, 0x41, 0x39, 0x45, 0x53, 0x56, 0x31, 0x65, 0x45, 0x47, 0x6f, 0x47, 0x4b, 0x77,
266 0x53,0x6e,0x6c,0x75,0x43,0x51,0x38,0x6e,0x4c,0x51,0x78,0x65,0x4d,0x6b,0x73,0x4e, 264 0x5a, 0x54, 0x45, 0x44, 0x6b, 0x33, 0x4d, 0x6b, 0x70, 0x4f, 0x50, 0x53, 0x74, 0x6c, 0x4f, 0x44, 0x6b, 0x48, 0x63, 0x6c, 0x52, 0x6b,
267 0x65,0x55,0x59,0x35,0x49,0x51,0x6f,0x6d,0x58,0x7a,0x6f,0x41,0x4a,0x6a,0x38,0x54, 265 0x54, 0x56, 0x5a, 0x71, 0x41, 0x79, 0x4a, 0x77, 0x65, 0x31, 0x39, 0x67, 0x43, 0x79, 0x6f, 0x4c, 0x61, 0x78, 0x42, 0x6b, 0x46, 0x41,
268 0x4c,0x6e,0x35,0x51,0x4b,0x32,0x64,0x47,0x63,0x6a,0x38,0x37,0x41,0x55,0x59,0x62, 266 0x55, 0x69, 0x41, 0x48, 0x4e, 0x41, 0x49, 0x31, 0x74, 0x52, 0x48, 0x79, 0x73, 0x61, 0x58, 0x57, 0x6c, 0x36, 0x52, 0x67, 0x78, 0x66,
269 0x43,0x7a,0x56,0x4a,0x4f,0x52,0x6c,0x77,0x50,0x51,0x4a,0x42,0x44,0x6a,0x67,0x46, 267 0x4d, 0x6b, 0x74, 0x4b, 0x4b, 0x46, 0x4a, 0x35, 0x57, 0x78, 0x4a, 0x43, 0x47, 0x41, 0x42, 0x64, 0x4a, 0x7a, 0x46, 0x54, 0x50, 0x45,
270 0x64,0x6d,0x56,0x50,0x4d,0x57,0x78,0x65,0x46,0x77,0x51,0x56,0x4e,0x69,0x5a,0x6b, 268 0x77, 0x32, 0x54, 0x6a, 0x67, 0x2f, 0x63, 0x67, 0x4e, 0x78, 0x41, 0x6c, 0x73, 0x32, 0x57, 0x58, 0x39, 0x31, 0x62, 0x67, 0x68, 0x55,
271 0x4e,0x42,0x51,0x58,0x66,0x41,0x34,0x4c,0x57,0x31,0x56,0x54,0x61,0x77,0x42,0x43, 269 0x44, 0x54, 0x51, 0x63, 0x4e, 0x46, 0x64, 0x64, 0x61, 0x55, 0x67, 0x41, 0x4f, 0x77, 0x55, 0x48, 0x62, 0x69, 0x64, 0x6c, 0x62, 0x6b,
272 0x51,0x55,0x38,0x43,0x58,0x42,0x4d,0x4b,0x4c,0x43,0x77,0x2b,0x45,0x42,0x51,0x7a, 270 0x41, 0x39, 0x4f, 0x6b, 0x39, 0x79, 0x58, 0x54, 0x6b, 0x57, 0x44, 0x32, 0x4d, 0x53, 0x45, 0x68, 0x55, 0x36, 0x63, 0x41, 0x31, 0x58,
273 0x52,0x58,0x78,0x36,0x57,0x6a,0x46,0x68,0x4f,0x51,0x67,0x69,0x61,0x68,0x34,0x50, 271 0x47, 0x41, 0x31, 0x65, 0x50, 0x53, 0x4a, 0x6f, 0x61, 0x48, 0x78, 0x74, 0x54, 0x77, 0x78, 0x37, 0x43, 0x53, 0x31, 0x4b, 0x63, 0x79,
274 0x62,0x78,0x74,0x73,0x45,0x31,0x35,0x35,0x49,0x48,0x6c,0x51,0x59,0x67,0x59,0x73, 272 0x42, 0x48, 0x42, 0x31, 0x64, 0x31, 0x58, 0x56, 0x4e, 0x77, 0x4e, 0x43, 0x46, 0x41, 0x56, 0x31, 0x46, 0x65, 0x53, 0x55, 0x51, 0x41,
275 0x64,0x68,0x63,0x45,0x4b,0x79,0x70,0x31,0x48,0x77,0x77,0x33,0x54,0x67,0x39,0x37, 273 0x56, 0x43, 0x63, 0x45, 0x61, 0x48, 0x35, 0x5a, 0x56, 0x6c, 0x68, 0x30, 0x46, 0x44, 0x77, 0x57, 0x4d, 0x30, 0x45, 0x57, 0x53, 0x79,
276 0x4c,0x54,0x52,0x31,0x59,0x44,0x46,0x30,0x4c,0x67,0x70,0x4b,0x45,0x57,0x78,0x4a, 274 0x39, 0x4a, 0x4e, 0x77, 0x70, 0x55, 0x43, 0x41, 0x67, 0x66, 0x4f, 0x57, 0x64, 0x32, 0x4b, 0x43, 0x67, 0x48, 0x48, 0x57, 0x46, 0x48,
277 0x4a,0x51,0x45,0x36,0x50,0x53,0x49,0x65,0x62,0x52,0x68,0x52,0x65,0x43,0x31,0x69, 275 0x55, 0x55, 0x31, 0x31, 0x4a, 0x6c, 0x4a, 0x48, 0x52, 0x77, 0x78, 0x58, 0x57, 0x48, 0x51, 0x2b, 0x59, 0x6d, 0x78, 0x59, 0x4f, 0x6b,
278 0x4d,0x55,0x78,0x51,0x51,0x42,0x64,0x4c,0x62,0x79,0x49,0x41,0x66,0x32,0x45,0x71, 276 0x51, 0x65, 0x46, 0x69, 0x34, 0x68, 0x48, 0x48, 0x4e, 0x46, 0x5a, 0x33, 0x52, 0x50, 0x4d, 0x32, 0x59, 0x4f, 0x64, 0x47, 0x59, 0x6d,
279 0x4e,0x44,0x34,0x41,0x58,0x79,0x39,0x66,0x4c,0x78,0x51,0x71,0x56,0x53,0x63,0x66, 277 0x48, 0x79, 0x34, 0x34, 0x52, 0x45, 0x42, 0x2b, 0x4b, 0x6c, 0x42, 0x53, 0x58, 0x6b, 0x4d, 0x42, 0x65, 0x6a, 0x68, 0x4a, 0x50, 0x46,
280 0x52,0x68,0x38,0x53,0x52,0x6c,0x34,0x65,0x44,0x48,0x77,0x34,0x41,0x57,0x46,0x6b, 278 0x56, 0x4e, 0x57, 0x6b, 0x51, 0x49, 0x4a, 0x6c, 0x6c, 0x4e, 0x52, 0x51, 0x74, 0x49, 0x43, 0x6a, 0x4e, 0x65, 0x53, 0x6b, 0x31, 0x31,
281 0x64,0x69,0x4a,0x75,0x43,0x43,0x41,0x34,0x54,0x33,0x4e,0x79,0x56,0x52,0x4a,0x43, 279 0x46, 0x68, 0x64, 0x6a, 0x52, 0x67, 0x45, 0x71, 0x56, 0x58, 0x73, 0x50, 0x41, 0x6e, 0x4e, 0x71, 0x53, 0x33, 0x39, 0x31, 0x5a, 0x54,
282 0x47,0x56,0x42,0x68,0x51,0x33,0x64,0x39,0x51,0x53,0x34,0x31,0x54,0x7a,0x30,0x78, 280 0x78, 0x4d, 0x4d, 0x7a, 0x6c, 0x73, 0x64, 0x41, 0x56, 0x67, 0x44, 0x33, 0x38, 0x74, 0x51, 0x55, 0x31, 0x4e, 0x52, 0x6e, 0x45, 0x4a,
283 0x4b,0x46,0x68,0x6e,0x47,0x77,0x4e,0x52,0x49,0x44,0x49,0x63,0x43,0x47,0x34,0x33, 281 0x62, 0x30, 0x39, 0x67, 0x46, 0x51, 0x39, 0x47, 0x63, 0x32, 0x4e, 0x4d, 0x58, 0x6e, 0x51, 0x77, 0x44, 0x53, 0x68, 0x44, 0x43, 0x48,
284 0x64,0x54,0x64,0x45,0x54,0x32,0x67,0x5a,0x42,0x32,0x51,0x55,0x4b,0x43,0x55,0x72, 282 0x49, 0x79, 0x42, 0x43, 0x34, 0x78, 0x4b, 0x53, 0x64, 0x45, 0x62, 0x52, 0x4d, 0x58, 0x53, 0x41, 0x39, 0x4a, 0x55, 0x68, 0x41, 0x54,
285 0x61,0x54,0x55,0x59,0x4a,0x79,0x59,0x55,0x45,0x33,0x42,0x43,0x47,0x52,0x4a,0x31, 283 0x66, 0x78, 0x63, 0x57, 0x59, 0x6e, 0x6b, 0x31, 0x65, 0x44, 0x34, 0x42, 0x66, 0x43, 0x34, 0x50, 0x64, 0x6a, 0x35, 0x65, 0x55, 0x32,
286 0x50,0x67,0x4a,0x64,0x66,0x42,0x4d,0x66,0x46,0x6c,0x4d,0x37,0x64,0x45,0x67,0x38, 284 0x78, 0x62, 0x58, 0x33, 0x77, 0x5a, 0x51, 0x51, 0x49, 0x76, 0x46, 0x32, 0x52, 0x42, 0x64, 0x52, 0x41, 0x45, 0x52, 0x33, 0x77, 0x39,
287 0x58,0x6a,0x6c,0x73,0x48,0x42,0x78,0x30,0x4f,0x52,0x38,0x41,0x47,0x77,0x59,0x4b, 285 0x53, 0x31, 0x49, 0x41, 0x45, 0x46, 0x31, 0x52, 0x54, 0x6e, 0x6f, 0x6e, 0x4a, 0x56, 0x56, 0x41, 0x45, 0x6a, 0x56, 0x67, 0x42, 0x52,
288 0x61,0x44,0x74,0x53,0x54,0x78,0x35,0x75,0x50,0x44,0x55,0x4d,0x4f,0x41,0x34,0x4c, 286 0x73, 0x30, 0x4c, 0x51, 0x52, 0x36, 0x61, 0x6d, 0x6b, 0x43, 0x65, 0x51, 0x4d, 0x36, 0x4c, 0x77, 0x59, 0x4b, 0x65, 0x58, 0x73, 0x53,
289 0x4f,0x78,0x70,0x32,0x49,0x79,0x6c,0x54,0x48,0x6c,0x39,0x42,0x44,0x45,0x73,0x4b, 287 0x58, 0x58, 0x78, 0x53, 0x4b, 0x55, 0x64, 0x59, 0x45, 0x6e, 0x4d, 0x2f, 0x4a, 0x31, 0x59, 0x46, 0x44, 0x45, 0x67, 0x79, 0x57, 0x47,
290 0x5a,0x53,0x68,0x34,0x5a,0x30,0x68,0x5a,0x4a,0x6d,0x30,0x78,0x64,0x69,0x4e,0x77, 288 0x74, 0x58, 0x58, 0x41, 0x4e, 0x6b, 0x56, 0x68, 0x46, 0x53, 0x65, 0x6a, 0x41, 0x32, 0x4b, 0x52, 0x63, 0x37, 0x61, 0x48, 0x70, 0x38,
291 0x59,0x57,0x51,0x37,0x4f,0x48,0x6c,0x6d,0x64,0x46,0x4d,0x73,0x5a,0x47,0x52,0x55, 289 0x42, 0x57, 0x74, 0x72, 0x45, 0x32, 0x6f, 0x6b, 0x58, 0x47, 0x68, 0x43, 0x47, 0x44, 0x49, 0x44, 0x63, 0x32, 0x34, 0x45, 0x49, 0x53,
292 0x41,0x31,0x52,0x6c,0x52,0x45,0x77,0x59,0x54,0x30,0x67,0x67,0x54,0x33,0x49,0x51, 290 0x34, 0x42, 0x42, 0x47, 0x4e, 0x39, 0x52, 0x45, 0x45, 0x53, 0x4d, 0x51, 0x73, 0x56, 0x48, 0x33, 0x41, 0x41, 0x4c, 0x6d, 0x59, 0x55,
293 0x50,0x77,0x78,0x53,0x4c,0x51,0x4d,0x55,0x41,0x31,0x46,0x43,0x45,0x48,0x64,0x71, 291 0x50, 0x48, 0x38, 0x72, 0x41, 0x42, 0x38, 0x4d, 0x4b, 0x46, 0x6b, 0x4b, 0x46, 0x6b, 0x6c, 0x61, 0x58, 0x47, 0x52, 0x6c, 0x53, 0x78,
294 0x4e,0x41,0x59,0x79,0x41,0x33,0x49,0x55,0x66,0x41,0x68,0x64,0x55,0x68,0x70,0x69, 292 0x45, 0x70, 0x46, 0x54, 0x5a, 0x61, 0x5a, 0x52, 0x6c, 0x50, 0x59, 0x43, 0x4d, 0x36, 0x4f, 0x68, 0x4d, 0x6c, 0x41, 0x6e, 0x68, 0x4d,
295 0x66,0x44,0x34,0x77,0x66,0x6c,0x39,0x2f,0x56,0x41,0x39,0x45,0x53,0x56,0x31,0x65, 293 0x56, 0x41, 0x3d, 0x3d, 0x00};
296 0x45,0x47,0x6f,0x47,0x4b,0x77,0x5a,0x54,0x45,0x44,0x6b,0x33,0x4d,0x6b,0x70,0x4f,
297 0x50,0x53,0x74,0x6c,0x4f,0x44,0x6b,0x48,0x63,0x6c,0x52,0x6b,0x54,0x56,0x5a,0x71,
298 0x41,0x79,0x4a,0x77,0x65,0x31,0x39,0x67,0x43,0x79,0x6f,0x4c,0x61,0x78,0x42,0x6b,
299 0x46,0x41,0x55,0x69,0x41,0x48,0x4e,0x41,0x49,0x31,0x74,0x52,0x48,0x79,0x73,0x61,
300 0x58,0x57,0x6c,0x36,0x52,0x67,0x78,0x66,0x4d,0x6b,0x74,0x4b,0x4b,0x46,0x4a,0x35,
301 0x57,0x78,0x4a,0x43,0x47,0x41,0x42,0x64,0x4a,0x7a,0x46,0x54,0x50,0x45,0x77,0x32,
302 0x54,0x6a,0x67,0x2f,0x63,0x67,0x4e,0x78,0x41,0x6c,0x73,0x32,0x57,0x58,0x39,0x31,
303 0x62,0x67,0x68,0x55,0x44,0x54,0x51,0x63,0x4e,0x46,0x64,0x64,0x61,0x55,0x67,0x41,
304 0x4f,0x77,0x55,0x48,0x62,0x69,0x64,0x6c,0x62,0x6b,0x41,0x39,0x4f,0x6b,0x39,0x79,
305 0x58,0x54,0x6b,0x57,0x44,0x32,0x4d,0x53,0x45,0x68,0x55,0x36,0x63,0x41,0x31,0x58,
306 0x47,0x41,0x31,0x65,0x50,0x53,0x4a,0x6f,0x61,0x48,0x78,0x74,0x54,0x77,0x78,0x37,
307 0x43,0x53,0x31,0x4b,0x63,0x79,0x42,0x48,0x42,0x31,0x64,0x31,0x58,0x56,0x4e,0x77,
308 0x4e,0x43,0x46,0x41,0x56,0x31,0x46,0x65,0x53,0x55,0x51,0x41,0x56,0x43,0x63,0x45,
309 0x61,0x48,0x35,0x5a,0x56,0x6c,0x68,0x30,0x46,0x44,0x77,0x57,0x4d,0x30,0x45,0x57,
310 0x53,0x79,0x39,0x4a,0x4e,0x77,0x70,0x55,0x43,0x41,0x67,0x66,0x4f,0x57,0x64,0x32,
311 0x4b,0x43,0x67,0x48,0x48,0x57,0x46,0x48,0x55,0x55,0x31,0x31,0x4a,0x6c,0x4a,0x48,
312 0x52,0x77,0x78,0x58,0x57,0x48,0x51,0x2b,0x59,0x6d,0x78,0x59,0x4f,0x6b,0x51,0x65,
313 0x46,0x69,0x34,0x68,0x48,0x48,0x4e,0x46,0x5a,0x33,0x52,0x50,0x4d,0x32,0x59,0x4f,
314 0x64,0x47,0x59,0x6d,0x48,0x79,0x34,0x34,0x52,0x45,0x42,0x2b,0x4b,0x6c,0x42,0x53,
315 0x58,0x6b,0x4d,0x42,0x65,0x6a,0x68,0x4a,0x50,0x46,0x56,0x4e,0x57,0x6b,0x51,0x49,
316 0x4a,0x6c,0x6c,0x4e,0x52,0x51,0x74,0x49,0x43,0x6a,0x4e,0x65,0x53,0x6b,0x31,0x31,
317 0x46,0x68,0x64,0x6a,0x52,0x67,0x45,0x71,0x56,0x58,0x73,0x50,0x41,0x6e,0x4e,0x71,
318 0x53,0x33,0x39,0x31,0x5a,0x54,0x78,0x4d,0x4d,0x7a,0x6c,0x73,0x64,0x41,0x56,0x67,
319 0x44,0x33,0x38,0x74,0x51,0x55,0x31,0x4e,0x52,0x6e,0x45,0x4a,0x62,0x30,0x39,0x67,
320 0x46,0x51,0x39,0x47,0x63,0x32,0x4e,0x4d,0x58,0x6e,0x51,0x77,0x44,0x53,0x68,0x44,
321 0x43,0x48,0x49,0x79,0x42,0x43,0x34,0x78,0x4b,0x53,0x64,0x45,0x62,0x52,0x4d,0x58,
322 0x53,0x41,0x39,0x4a,0x55,0x68,0x41,0x54,0x66,0x78,0x63,0x57,0x59,0x6e,0x6b,0x31,
323 0x65,0x44,0x34,0x42,0x66,0x43,0x34,0x50,0x64,0x6a,0x35,0x65,0x55,0x32,0x78,0x62,
324 0x58,0x33,0x77,0x5a,0x51,0x51,0x49,0x76,0x46,0x32,0x52,0x42,0x64,0x52,0x41,0x45,
325 0x52,0x33,0x77,0x39,0x53,0x31,0x49,0x41,0x45,0x46,0x31,0x52,0x54,0x6e,0x6f,0x6e,
326 0x4a,0x56,0x56,0x41,0x45,0x6a,0x56,0x67,0x42,0x52,0x73,0x30,0x4c,0x51,0x52,0x36,
327 0x61,0x6d,0x6b,0x43,0x65,0x51,0x4d,0x36,0x4c,0x77,0x59,0x4b,0x65,0x58,0x73,0x53,
328 0x58,0x58,0x78,0x53,0x4b,0x55,0x64,0x59,0x45,0x6e,0x4d,0x2f,0x4a,0x31,0x59,0x46,
329 0x44,0x45,0x67,0x79,0x57,0x47,0x74,0x58,0x58,0x41,0x4e,0x6b,0x56,0x68,0x46,0x53,
330 0x65,0x6a,0x41,0x32,0x4b,0x52,0x63,0x37,0x61,0x48,0x70,0x38,0x42,0x57,0x74,0x72,
331 0x45,0x32,0x6f,0x6b,0x58,0x47,0x68,0x43,0x47,0x44,0x49,0x44,0x63,0x32,0x34,0x45,
332 0x49,0x53,0x34,0x42,0x42,0x47,0x4e,0x39,0x52,0x45,0x45,0x53,0x4d,0x51,0x73,0x56,
333 0x48,0x33,0x41,0x41,0x4c,0x6d,0x59,0x55,0x50,0x48,0x38,0x72,0x41,0x42,0x38,0x4d,
334 0x4b,0x46,0x6b,0x4b,0x46,0x6b,0x6c,0x61,0x58,0x47,0x52,0x6c,0x53,0x78,0x45,0x70,
335 0x46,0x54,0x5a,0x61,0x5a,0x52,0x6c,0x50,0x59,0x43,0x4d,0x36,0x4f,0x68,0x4d,0x6c,
336 0x41,0x6e,0x68,0x4d,0x56,0x41,0x3d,0x3d,0x00
337 };
338 char *b64_test; 294 char *b64_test;
339 295
340 plan_tests(1); 296 plan_tests(1);
341 297
342 base64_encode_alloc (random, 1024, &b64_test); 298 base64_encode_alloc(random, 1024, &b64_test);
343 299
344 ok(strcmp(b64_known, b64_test) == 0, 300 ok(strcmp(b64_known, b64_test) == 0, "Test matching a base64 encoded 1024 bytes random string");
345 "Test matching a base64 encoded 1024 bytes random string");
346 301
347 return exit_status(); 302 return exit_status();
348} 303}
349
diff --git a/lib/tests/test_cmd.c b/lib/tests/test_cmd.c
index 02ae11f5..c8867dfb 100644
--- a/lib/tests/test_cmd.c
+++ b/lib/tests/test_cmd.c
@@ -1,20 +1,20 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* This program is free software: you can redistribute it and/or modify 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 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 5 * the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version. 6 * (at your option) any later version.
7* 7 *
8* This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details. 11 * GNU General Public License for more details.
12* 12 *
13* You should have received a copy of the GNU General Public License 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/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15* 15 *
16* 16 *
17*****************************************************************************/ 17 *****************************************************************************/
18 18
19#include "common.h" 19#include "common.h"
20#include "utils_cmd.h" 20#include "utils_cmd.h"
@@ -22,27 +22,23 @@
22#include "tap.h" 22#include "tap.h"
23 23
24#define COMMAND_LINE 1024 24#define COMMAND_LINE 1024
25#define UNSET 65530 25#define UNSET 65530
26 26
27char * 27char *get_command(char *const *line) {
28get_command (char *const *line)
29{
30 char *cmd; 28 char *cmd;
31 int i = 0; 29 int i = 0;
32 30
33 asprintf (&cmd, " %s", line[i++]); 31 asprintf(&cmd, " %s", line[i++]);
34 while (line[i] != NULL) { 32 while (line[i] != NULL) {
35 asprintf (&cmd, "%s %s", cmd, line[i]); 33 asprintf(&cmd, "%s %s", cmd, line[i]);
36 i++; 34 i++;
37 } 35 }
38 36
39 return cmd; 37 return cmd;
40} 38}
41 39
42int 40int main(int argc, char **argv) {
43main (int argc, char **argv) 41 char **command_line = malloc(sizeof(char *) * COMMAND_LINE);
44{
45 char **command_line = malloc (sizeof (char *) * COMMAND_LINE);
46 char *command = NULL; 42 char *command = NULL;
47 char *perl; 43 char *perl;
48 output chld_out, chld_err; 44 output chld_out, chld_err;
@@ -51,183 +47,154 @@ main (int argc, char **argv)
51 47
52 plan_tests(51); 48 plan_tests(51);
53 49
54 diag ("Running plain echo command, set one"); 50 diag("Running plain echo command, set one");
55 51
56 /* ensure everything is empty before we begin */ 52 /* ensure everything is empty before we begin */
57 memset (&chld_out, 0, sizeof (output)); 53 memset(&chld_out, 0, sizeof(output));
58 memset (&chld_err, 0, sizeof (output)); 54 memset(&chld_err, 0, sizeof(output));
59 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 55 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
60 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 56 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
61 ok (result == UNSET, "(initialised) Checking exit code is reset"); 57 ok(result == UNSET, "(initialised) Checking exit code is reset");
62 58
63 command_line[0] = strdup ("/bin/echo"); 59 command_line[0] = strdup("/bin/echo");
64 command_line[1] = strdup ("this"); 60 command_line[1] = strdup("this");
65 command_line[2] = strdup ("is"); 61 command_line[2] = strdup("is");
66 command_line[3] = strdup ("test"); 62 command_line[3] = strdup("test");
67 command_line[4] = strdup ("one"); 63 command_line[4] = strdup("one");
68 64
69 command = get_command (command_line); 65 command = get_command(command_line);
70 66
71 result = cmd_run_array (command_line, &chld_out, &chld_err, 0); 67 result = cmd_run_array(command_line, &chld_out, &chld_err, 0);
72 ok (chld_out.lines == 1, 68 ok(chld_out.lines == 1, "(array) Check for expected number of stdout lines");
73 "(array) Check for expected number of stdout lines"); 69 ok(chld_err.lines == 0, "(array) Check for expected number of stderr lines");
74 ok (chld_err.lines == 0, 70 ok(strcmp(chld_out.line[0], "this is test one") == 0, "(array) Check for expected stdout output");
75 "(array) Check for expected number of stderr lines"); 71 ok(result == 0, "(array) Checking exit code");
76 ok (strcmp (chld_out.line[0], "this is test one") == 0,
77 "(array) Check for expected stdout output");
78 ok (result == 0, "(array) Checking exit code");
79 72
80 /* ensure everything is empty again */ 73 /* ensure everything is empty again */
81 memset (&chld_out, 0, sizeof (output)); 74 memset(&chld_out, 0, sizeof(output));
82 memset (&chld_err, 0, sizeof (output)); 75 memset(&chld_err, 0, sizeof(output));
83 result = UNSET; 76 result = UNSET;
84 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 77 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
85 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 78 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
86 ok (result == UNSET, "(initialised) Checking exit code is reset"); 79 ok(result == UNSET, "(initialised) Checking exit code is reset");
87 80
88 result = cmd_run (command, &chld_out, &chld_err, 0); 81 result = cmd_run(command, &chld_out, &chld_err, 0);
89 82
90 ok (chld_out.lines == 1, 83 ok(chld_out.lines == 1, "(string) Check for expected number of stdout lines");
91 "(string) Check for expected number of stdout lines"); 84 ok(chld_err.lines == 0, "(string) Check for expected number of stderr lines");
92 ok (chld_err.lines == 0, 85 ok(strcmp(chld_out.line[0], "this is test one") == 0, "(string) Check for expected stdout output");
93 "(string) Check for expected number of stderr lines"); 86 ok(result == 0, "(string) Checking exit code");
94 ok (strcmp (chld_out.line[0], "this is test one") == 0,
95 "(string) Check for expected stdout output");
96 ok (result == 0, "(string) Checking exit code");
97 87
98 diag ("Running plain echo command, set two"); 88 diag("Running plain echo command, set two");
99 89
100 /* ensure everything is empty again */ 90 /* ensure everything is empty again */
101 memset (&chld_out, 0, sizeof (output)); 91 memset(&chld_out, 0, sizeof(output));
102 memset (&chld_err, 0, sizeof (output)); 92 memset(&chld_err, 0, sizeof(output));
103 result = UNSET; 93 result = UNSET;
104 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 94 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
105 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 95 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
106 ok (result == UNSET, "(initialised) Checking exit code is reset"); 96 ok(result == UNSET, "(initialised) Checking exit code is reset");
107 97
108 command_line[0] = strdup ("/bin/echo"); 98 command_line[0] = strdup("/bin/echo");
109 command_line[1] = strdup ("this is test two"); 99 command_line[1] = strdup("this is test two");
110 command_line[2] = NULL; 100 command_line[2] = NULL;
111 command_line[3] = NULL; 101 command_line[3] = NULL;
112 command_line[4] = NULL; 102 command_line[4] = NULL;
113 103
114 result = cmd_run_array (command_line, &chld_out, &chld_err, 0); 104 result = cmd_run_array(command_line, &chld_out, &chld_err, 0);
115 ok (chld_out.lines == 1, 105 ok(chld_out.lines == 1, "(array) Check for expected number of stdout lines");
116 "(array) Check for expected number of stdout lines"); 106 ok(chld_err.lines == 0, "(array) Check for expected number of stderr lines");
117 ok (chld_err.lines == 0, 107 ok(strcmp(chld_out.line[0], "this is test two") == 0, "(array) Check for expected stdout output");
118 "(array) Check for expected number of stderr lines"); 108 ok(result == 0, "(array) Checking exit code");
119 ok (strcmp (chld_out.line[0], "this is test two") == 0,
120 "(array) Check for expected stdout output");
121 ok (result == 0, "(array) Checking exit code");
122 109
123 /* ensure everything is empty again */ 110 /* ensure everything is empty again */
124 memset (&chld_out, 0, sizeof (output)); 111 memset(&chld_out, 0, sizeof(output));
125 memset (&chld_err, 0, sizeof (output)); 112 memset(&chld_err, 0, sizeof(output));
126 result = UNSET; 113 result = UNSET;
127 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 114 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
128 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 115 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
129 ok (result == UNSET, "(initialised) Checking exit code is reset"); 116 ok(result == UNSET, "(initialised) Checking exit code is reset");
130
131 result = cmd_run (command, &chld_out, &chld_err, 0);
132 117
133 ok (chld_out.lines == 1, 118 result = cmd_run(command, &chld_out, &chld_err, 0);
134 "(string) Check for expected number of stdout lines");
135 ok (chld_err.lines == 0,
136 "(string) Check for expected number of stderr lines");
137 ok (strcmp (chld_out.line[0], "this is test one") == 0,
138 "(string) Check for expected stdout output");
139 ok (result == 0, "(string) Checking exit code");
140 119
120 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(strcmp(chld_out.line[0], "this is test one") == 0, "(string) Check for expected stdout output");
123 ok(result == 0, "(string) Checking exit code");
141 124
142 /* ensure everything is empty again */ 125 /* ensure everything is empty again */
143 memset (&chld_out, 0, sizeof (output)); 126 memset(&chld_out, 0, sizeof(output));
144 memset (&chld_err, 0, sizeof (output)); 127 memset(&chld_err, 0, sizeof(output));
145 result = UNSET; 128 result = UNSET;
146 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 129 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
147 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 130 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
148 ok (result == UNSET, "(initialised) Checking exit code is reset"); 131 ok(result == UNSET, "(initialised) Checking exit code is reset");
149 132
150 /* Pass linefeeds via parameters through - those should be evaluated by echo to give multi line output */ 133 /* Pass linefeeds via parameters through - those should be evaluated by echo to give multi line output */
151 command_line[0] = strdup("/bin/echo"); 134 command_line[0] = strdup("/bin/echo");
152 command_line[1] = strdup("this is a test via echo\nline two\nit's line 3"); 135 command_line[1] = strdup("this is a test via echo\nline two\nit's line 3");
153 command_line[2] = strdup("and (note space between '3' and 'and') $$ will not get evaluated"); 136 command_line[2] = strdup("and (note space between '3' and 'and') $$ will not get evaluated");
154 137
155 result = cmd_run_array (command_line, &chld_out, &chld_err, 0); 138 result = cmd_run_array(command_line, &chld_out, &chld_err, 0);
156 ok (chld_out.lines == 3, 139 ok(chld_out.lines == 3, "(array) Check for expected number of stdout lines");
157 "(array) Check for expected number of stdout lines"); 140 ok(chld_err.lines == 0, "(array) Check for expected number of stderr lines");
158 ok (chld_err.lines == 0, 141 ok(strcmp(chld_out.line[0], "this is a test via echo") == 0, "(array) Check line 1 for expected stdout output");
159 "(array) Check for expected number of stderr lines"); 142 ok(strcmp(chld_out.line[1], "line two") == 0, "(array) Check line 2 for expected stdout output");
160 ok (strcmp (chld_out.line[0], "this is a test via echo") == 0, 143 ok(strcmp(chld_out.line[2], "it's line 3 and (note space between '3' and 'and') $$ will not get evaluated") == 0,
161 "(array) Check line 1 for expected stdout output"); 144 "(array) Check line 3 for expected stdout output");
162 ok (strcmp (chld_out.line[1], "line two") == 0, 145 ok(result == 0, "(array) Checking exit code");
163 "(array) Check line 2 for expected stdout output");
164 ok (strcmp (chld_out.line[2], "it's line 3 and (note space between '3' and 'and') $$ will not get evaluated") == 0,
165 "(array) Check line 3 for expected stdout output");
166 ok (result == 0, "(array) Checking exit code");
167
168
169 146
170 /* ensure everything is empty again */ 147 /* ensure everything is empty again */
171 memset (&chld_out, 0, sizeof (output)); 148 memset(&chld_out, 0, sizeof(output));
172 memset (&chld_err, 0, sizeof (output)); 149 memset(&chld_err, 0, sizeof(output));
173 result = UNSET; 150 result = UNSET;
174 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 151 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
175 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 152 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
176 ok (result == UNSET, "(initialised) Checking exit code is reset"); 153 ok(result == UNSET, "(initialised) Checking exit code is reset");
177 154
178 command = (char *)malloc(COMMAND_LINE); 155 command = (char *)malloc(COMMAND_LINE);
179 strcpy(command, "/bin/echo3456 non-existent command"); 156 strcpy(command, "/bin/echo3456 non-existent command");
180 result = cmd_run (command, &chld_out, &chld_err, 0); 157 result = cmd_run(command, &chld_out, &chld_err, 0);
181
182 ok (chld_out.lines == 0,
183 "Non existent command, so no output");
184 ok (chld_err.lines == 0,
185 "No stderr either");
186 ok (result == 3, "Get return code 3 (?) for non-existent command");
187 158
159 ok(chld_out.lines == 0, "Non existent command, so no output");
160 ok(chld_err.lines == 0, "No stderr either");
161 ok(result == 3, "Get return code 3 (?) for non-existent command");
188 162
189 /* ensure everything is empty again */ 163 /* ensure everything is empty again */
190 memset (&chld_out, 0, sizeof (output)); 164 memset(&chld_out, 0, sizeof(output));
191 memset (&chld_err, 0, sizeof (output)); 165 memset(&chld_err, 0, sizeof(output));
192 result = UNSET; 166 result = UNSET;
193 167
194 command = (char *)malloc(COMMAND_LINE); 168 command = (char *)malloc(COMMAND_LINE);
195 strcpy(command, "/bin/sh non-existent-file"); 169 strcpy(command, "/bin/sh non-existent-file");
196 result = cmd_run (command, &chld_out, &chld_err, 0); 170 result = cmd_run(command, &chld_out, &chld_err, 0);
197
198 ok (chld_out.lines == 0,
199 "/bin/sh returns no stdout when file is missing...");
200 ok (chld_err.lines == 1,
201 "...but does give an error line");
202 ok (strstr(chld_err.line[0],"non-existent-file") != NULL, "And missing filename is in error message");
203 ok (result != 0, "Get non-zero return code from /bin/sh");
204 171
172 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");
174 ok(strstr(chld_err.line[0], "non-existent-file") != NULL, "And missing filename is in error message");
175 ok(result != 0, "Get non-zero return code from /bin/sh");
205 176
206 /* ensure everything is empty again */ 177 /* ensure everything is empty again */
207 result = UNSET; 178 result = UNSET;
208 179
209 command = (char *)malloc(COMMAND_LINE); 180 command = (char *)malloc(COMMAND_LINE);
210 strcpy(command, "/bin/sh -c 'exit 7'"); 181 strcpy(command, "/bin/sh -c 'exit 7'");
211 result = cmd_run (command, NULL, NULL, 0); 182 result = cmd_run(command, NULL, NULL, 0);
212
213 ok (result == 7, "Get return code 7 from /bin/sh");
214 183
184 ok(result == 7, "Get return code 7 from /bin/sh");
215 185
216 /* ensure everything is empty again */ 186 /* ensure everything is empty again */
217 memset (&chld_out, 0, sizeof (output)); 187 memset(&chld_out, 0, sizeof(output));
218 memset (&chld_err, 0, sizeof (output)); 188 memset(&chld_err, 0, sizeof(output));
219 result = UNSET; 189 result = UNSET;
220 190
221 command = (char *)malloc(COMMAND_LINE); 191 command = (char *)malloc(COMMAND_LINE);
222 strcpy(command, "/bin/non-existent-command"); 192 strcpy(command, "/bin/non-existent-command");
223 result = cmd_run (command, &chld_out, &chld_err, 0); 193 result = cmd_run(command, &chld_out, &chld_err, 0);
224
225 ok (chld_out.lines == 0,
226 "/bin/non-existent-command returns no stdout...");
227 ok (chld_err.lines == 0,
228 "...and no stderr output either");
229 ok (result == 3, "Get return code 3 = UNKNOWN when command does not exist");
230 194
195 ok(chld_out.lines == 0, "/bin/non-existent-command returns no stdout...");
196 ok(chld_err.lines == 0, "...and no stderr output either");
197 ok(result == 3, "Get return code 3 = UNKNOWN when command does not exist");
231 198
232 return exit_status (); 199 return exit_status();
233} 200}
diff --git a/lib/tests/test_disk.c b/lib/tests/test_disk.c
deleted file mode 100644
index e283fe2e..00000000
--- a/lib/tests/test_disk.c
+++ /dev/null
@@ -1,224 +0,0 @@
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 "common.h"
20#include "utils_disk.h"
21#include "tap.h"
22#include "regex.h"
23
24void np_test_mount_entry_regex (struct mount_entry *dummy_mount_list,
25 char *regstr, int cflags, int expect,
26 char *desc);
27
28
29int
30main (int argc, char **argv)
31{
32 struct name_list *exclude_filesystem=NULL;
33 struct name_list *exclude_fstype=NULL;
34 struct name_list *dummy_mountlist = NULL;
35 struct name_list *temp_name;
36 struct parameter_list *paths = NULL;
37 struct parameter_list *p, *prev = NULL, *last = NULL;
38
39 struct mount_entry *dummy_mount_list;
40 struct mount_entry *me;
41 struct mount_entry **mtail = &dummy_mount_list;
42 int cflags = REG_NOSUB | REG_EXTENDED;
43 int found = 0, count = 0;
44
45 plan_tests(33);
46
47 ok( np_find_name(exclude_filesystem, "/var/log") == false, "/var/log not in list");
48 np_add_name(&exclude_filesystem, "/var/log");
49 ok( np_find_name(exclude_filesystem, "/var/log") == true, "is in list now");
50 ok( np_find_name(exclude_filesystem, "/home") == false, "/home not in list");
51 np_add_name(&exclude_filesystem, "/home");
52 ok( np_find_name(exclude_filesystem, "/home") == true, "is in list now");
53 ok( np_find_name(exclude_filesystem, "/var/log") == true, "/var/log still in list");
54
55 ok( np_find_name(exclude_fstype, "iso9660") == false, "iso9660 not in list");
56 np_add_name(&exclude_fstype, "iso9660");
57 ok( np_find_name(exclude_fstype, "iso9660") == true, "is in list now");
58
59 ok( np_find_name(exclude_filesystem, "iso9660") == false, "Make sure no clashing in variables");
60
61 /*
62 for (temp_name = exclude_filesystem; temp_name; temp_name = temp_name->next) {
63 printf("Name: %s\n", temp_name->name);
64 }
65 */
66
67 me = (struct mount_entry *) malloc(sizeof *me);
68 me->me_devname = strdup("/dev/c0t0d0s0");
69 me->me_mountdir = strdup("/");
70 *mtail = me;
71 mtail = &me->me_next;
72
73 me = (struct mount_entry *) malloc(sizeof *me);
74 me->me_devname = strdup("/dev/c1t0d1s0");
75 me->me_mountdir = strdup("/var");
76 *mtail = me;
77 mtail = &me->me_next;
78
79 me = (struct mount_entry *) malloc(sizeof *me);
80 me->me_devname = strdup("/dev/c2t0d0s0");
81 me->me_mountdir = strdup("/home");
82 *mtail = me;
83 mtail = &me->me_next;
84
85 np_test_mount_entry_regex(dummy_mount_list, strdup("/"),
86 cflags, 3, strdup("a"));
87 np_test_mount_entry_regex(dummy_mount_list, strdup("/dev"),
88 cflags, 3,strdup("regex on dev names:"));
89 np_test_mount_entry_regex(dummy_mount_list, strdup("/foo"),
90 cflags, 0,
91 strdup("regex on non existent dev/path:"));
92 np_test_mount_entry_regex(dummy_mount_list, strdup("/Foo"),
93 cflags | REG_ICASE,0,
94 strdup("regi on non existent dev/path:"));
95 np_test_mount_entry_regex(dummy_mount_list, strdup("/c.t0"),
96 cflags, 3,
97 strdup("partial devname regex match:"));
98 np_test_mount_entry_regex(dummy_mount_list, strdup("c0t0"),
99 cflags, 1,
100 strdup("partial devname regex match:"));
101 np_test_mount_entry_regex(dummy_mount_list, strdup("C0t0"),
102 cflags | REG_ICASE, 1,
103 strdup("partial devname regi match:"));
104 np_test_mount_entry_regex(dummy_mount_list, strdup("home"),
105 cflags, 1,
106 strdup("partial pathname regex match:"));
107 np_test_mount_entry_regex(dummy_mount_list, strdup("hOme"),
108 cflags | REG_ICASE, 1,
109 strdup("partial pathname regi match:"));
110 np_test_mount_entry_regex(dummy_mount_list, strdup("(/home)|(/var)"),
111 cflags, 2,
112 strdup("grouped regex pathname match:"));
113 np_test_mount_entry_regex(dummy_mount_list, strdup("(/homE)|(/Var)"),
114 cflags | REG_ICASE, 2,
115 strdup("grouped regi pathname match:"));
116
117 np_add_parameter(&paths, "/home/groups");
118 np_add_parameter(&paths, "/var");
119 np_add_parameter(&paths, "/tmp");
120 np_add_parameter(&paths, "/home/tonvoon");
121 np_add_parameter(&paths, "/dev/c2t0d0s0");
122
123 np_set_best_match(paths, dummy_mount_list, false);
124 for (p = paths; p; p = p->name_next) {
125 struct mount_entry *temp_me;
126 temp_me = p->best_match;
127 if (! strcmp(p->name, "/home/groups")) {
128 ok( temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/groups got right best match: /home");
129 } else if (! strcmp(p->name, "/var")) {
130 ok( temp_me && !strcmp(temp_me->me_mountdir, "/var"), "/var got right best match: /var");
131 } else if (! strcmp(p->name, "/tmp")) {
132 ok( temp_me && !strcmp(temp_me->me_mountdir, "/"), "/tmp got right best match: /");
133 } else if (! strcmp(p->name, "/home/tonvoon")) {
134 ok( temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/tonvoon got right best match: /home");
135 } else if (! strcmp(p->name, "/dev/c2t0d0s0")) {
136 ok( temp_me && !strcmp(temp_me->me_devname, "/dev/c2t0d0s0"), "/dev/c2t0d0s0 got right best match: /dev/c2t0d0s0");
137 }
138 }
139
140 paths = NULL; /* Bad boy - should free, but this is a test suite */
141 np_add_parameter(&paths, "/home/groups");
142 np_add_parameter(&paths, "/var");
143 np_add_parameter(&paths, "/tmp");
144 np_add_parameter(&paths, "/home/tonvoon");
145 np_add_parameter(&paths, "/home");
146
147 np_set_best_match(paths, dummy_mount_list, true);
148 for (p = paths; p; p = p->name_next) {
149 if (! strcmp(p->name, "/home/groups")) {
150 ok( ! p->best_match , "/home/groups correctly not found");
151 } else if (! strcmp(p->name, "/var")) {
152 ok( p->best_match, "/var found");
153 } else if (! strcmp(p->name, "/tmp")) {
154 ok(! p->best_match, "/tmp correctly not found");
155 } else if (! strcmp(p->name, "/home/tonvoon")) {
156 ok(! p->best_match, "/home/tonvoon not found");
157 } else if (! strcmp(p->name, "/home")) {
158 ok( p->best_match, "/home found");
159 }
160 }
161
162 /* test deleting first element in paths */
163 paths = np_del_parameter(paths, NULL);
164 for (p = paths; p; p = p->name_next) {
165 if (! strcmp(p->name, "/home/groups"))
166 found = 1;
167 }
168 ok(found == 0, "first element successfully deleted");
169 found = 0;
170
171 p=paths;
172 while (p) {
173 if (! strcmp(p->name, "/tmp"))
174 p = np_del_parameter(p, prev);
175 else {
176 prev = p;
177 p = p->name_next;
178 }
179 }
180
181 for (p = paths; p; p = p->name_next) {
182 if (! strcmp(p->name, "/tmp"))
183 found = 1;
184 if (p->name_next)
185 prev = p;
186 else
187 last = p;
188 }
189 ok(found == 0, "/tmp element successfully deleted");
190
191 p = np_del_parameter(last, prev);
192 for (p = paths; p; p = p->name_next) {
193 if (! strcmp(p->name, "/home"))
194 found = 1;
195 last = p;
196 count++;
197 }
198 ok(found == 0, "last (/home) element successfully deleted");
199 ok(count == 2, "two elements remaining");
200
201
202 return exit_status();
203}
204
205
206void
207np_test_mount_entry_regex (struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc)
208{
209 int matches = 0;
210 regex_t re;
211 struct mount_entry *me;
212 if (regcomp(&re,regstr, cflags) == 0) {
213 for (me = dummy_mount_list; me; me= me->me_next) {
214 if(np_regex_match_mount_entry(me,&re))
215 matches++;
216 }
217 ok( matches == expect,
218 "%s '%s' matched %i/3 entries. ok: %i/3",
219 desc, regstr, expect, matches);
220
221 } else
222 ok ( false, "regex '%s' not compilable", regstr);
223}
224
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 b/lib/tests/test_generic_output
new file mode 100755
index 00000000..51e299a0
--- /dev/null
+++ b/lib/tests/test_generic_output
Binary files differ
diff --git a/lib/tests/test_generic_output.c b/lib/tests/test_generic_output.c
new file mode 100644
index 00000000..e67aefc9
--- /dev/null
+++ b/lib/tests/test_generic_output.c
@@ -0,0 +1,315 @@
1#include "../lib/output.h"
2#include "../../tap/tap.h"
3#include "./states.h"
4
5#include <string.h>
6
7void test_one_subcheck(void);
8void test_two_subchecks(void);
9
10void test_perfdata_formatting(void);
11void test_perfdata_formatting2(void);
12
13void test_deep_check_hierarchy(void);
14void test_deep_check_hierarchy2(void);
15
16void test_default_states1(void);
17void test_default_states2(void);
18
19int main(void) {
20 plan_tests(19);
21
22 diag("Simple test with one subcheck");
23 test_one_subcheck();
24
25 diag("Test with two subchecks");
26 test_two_subchecks();
27
28 diag("Test for performance data formatting");
29 test_perfdata_formatting();
30
31 diag("Another test for performance data formatting");
32 test_perfdata_formatting2();
33
34 diag("Test for deeper hierarchies");
35 test_deep_check_hierarchy();
36
37 diag("Another test for deeper hierarchies");
38 test_deep_check_hierarchy2();
39
40 diag("Testing the default state logic");
41 test_default_states1();
42
43 diag("Testing the default state logic #2");
44 test_default_states2();
45
46 return exit_status();
47}
48
49void test_one_subcheck(void) {
50 mp_subcheck sc1 = mp_subcheck_init();
51
52 sc1.output = "foobar";
53 sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
54
55 mp_check check = mp_check_init();
56 mp_add_subcheck_to_check(&check, sc1);
57
58 ok(mp_compute_check_state(check) == STATE_WARNING, "Main state should be warning");
59
60 char *output = mp_fmt_output(check);
61
62 // diag("Formatted output");
63 // diag(output);
64
65 char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n"
66 "\t\\_[WARNING] - foobar\n";
67
68 // diag("Expected output");
69 // diag(expected);
70
71 ok(strcmp(output, expected) == 0, "Simple output test");
72}
73
74void test_perfdata_formatting2(void) {
75 mp_perfdata pd1 = perfdata_init();
76 mp_perfdata pd2 = perfdata_init();
77
78 pd1.label = "foo";
79 pd2.label = "bar";
80
81 pd1 = mp_set_pd_value(pd1, 23);
82 pd2 = mp_set_pd_value(pd2, 1LL);
83
84 pd_list *tmp = pd_list_init();
85
86 pd_list_append(tmp, pd1);
87 pd_list_append(tmp, pd2);
88
89 char *result = pd_list_to_string(*tmp);
90
91 ok(strcmp(result, "foo=23;;; bar=1;;;") == 0, "Perfdata string formatting");
92}
93
94void test_perfdata_formatting(void) {
95 mp_perfdata pd1 = perfdata_init();
96
97 pd1.uom = "s";
98 pd1.label = "foo";
99
100 pd1 = mp_set_pd_value(pd1, 23);
101
102 char *pd_string = pd_to_string(pd1);
103
104 ok(strcmp(pd_string, "foo=23s;;;") == 0, "Perfdata string formatting");
105}
106
107void test_two_subchecks(void) {
108 mp_subcheck sc1 = mp_subcheck_init();
109
110 sc1.output = "foobar";
111 sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
112
113 ok(mp_compute_subcheck_state(sc1) == STATE_WARNING, "Test subcheck state directly after setting it");
114
115 mp_perfdata pd1 = perfdata_init();
116
117 pd1 = mp_set_pd_value(pd1, 23);
118
119 pd1.uom = "s";
120 pd1.label = "foo";
121
122 mp_add_perfdata_to_subcheck(&sc1, pd1);
123
124 mp_subcheck sc2 = mp_subcheck_init();
125 sc2.output = "baz";
126 sc2 = mp_set_subcheck_state(sc2, STATE_OK);
127
128 ok(mp_compute_subcheck_state(sc2) == STATE_OK, "Test subcheck 2 state after setting it");
129
130 mp_add_subcheck_to_subcheck(&sc1, sc2);
131
132 ok(mp_compute_subcheck_state(sc1) == STATE_WARNING, "Test subcheck state after adding a subcheck");
133
134 mp_check check = mp_check_init();
135 mp_add_subcheck_to_check(&check, sc1);
136
137 ok(mp_compute_check_state(check) == STATE_WARNING, "Test main check result");
138
139 char *output = mp_fmt_output(check);
140
141 // diag("Formatted output. Length: %u", strlen(output));
142 // diag(output);
143
144 ok(output != NULL, "Output should not be NULL");
145
146 char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n"
147 "\t\\_[WARNING] - foobar\n"
148 "\t\t\\_[OK] - baz\n"
149 "|foo=23s;;; \n";
150
151 // diag("Expected output. Length: %u", strlen(expected));
152 // diag(expected);
153
154 ok(strcmp(output, expected) == 0, "Output is as expected");
155}
156
157void test_deep_check_hierarchy(void) {
158 // level 4
159 mp_subcheck sc4 = mp_subcheck_init();
160 sc4.output = "level4";
161 sc4 = mp_set_subcheck_state(sc4, STATE_OK);
162
163 // level 3
164 mp_subcheck sc3 = mp_subcheck_init();
165 sc3.output = "level3";
166 sc3 = mp_set_subcheck_state(sc3, STATE_OK);
167
168 // level 2
169 mp_subcheck sc2 = mp_subcheck_init();
170 sc2.output = "baz";
171 sc2 = mp_set_subcheck_state(sc2, STATE_OK);
172
173 // level 1
174 mp_subcheck sc1 = mp_subcheck_init();
175
176 sc1.output = "foobar";
177 sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
178
179 mp_perfdata pd1 = perfdata_init();
180
181 pd1.uom = "s";
182 pd1.label = "foo";
183 pd1 = mp_set_pd_value(pd1, 23);
184
185 mp_add_perfdata_to_subcheck(&sc1, pd1);
186
187 // main check
188 mp_check check = mp_check_init();
189
190 mp_add_subcheck_to_subcheck(&sc3, sc4);
191 mp_add_subcheck_to_subcheck(&sc2, sc3);
192 mp_add_subcheck_to_subcheck(&sc1, sc2);
193 mp_add_subcheck_to_check(&check, sc1);
194
195 char *output = mp_fmt_output(check);
196
197 size_t output_length = strlen(output);
198
199 // diag("Formatted output of length %i", output_length);
200 // diag(output);
201
202 ok(output != NULL, "Output should not be NULL");
203
204 char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n"
205 "\t\\_[WARNING] - foobar\n"
206 "\t\t\\_[OK] - baz\n"
207 "\t\t\t\\_[OK] - level3\n"
208 "\t\t\t\t\\_[OK] - level4\n"
209 "|foo=23s;;; \n";
210
211 size_t expected_length = strlen(expected);
212
213 // diag("Expected output of length: %i", expected_length);
214 // diag(expected);
215
216 ok(output_length == expected_length, "Outputs are of equal length");
217 ok(strcmp(output, expected) == 0, "Output is as expected");
218}
219
220void test_deep_check_hierarchy2(void) {
221 // level 1
222 mp_subcheck sc1 = mp_subcheck_init();
223
224 sc1.output = "foobar";
225 sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
226
227 mp_perfdata pd1 = perfdata_init();
228 pd1.uom = "s";
229 pd1.label = "foo";
230 pd1 = mp_set_pd_value(pd1, 23);
231
232 mp_add_perfdata_to_subcheck(&sc1, pd1);
233
234 // level 2
235 mp_subcheck sc2 = mp_subcheck_init();
236 sc2.output = "baz";
237 sc2 = mp_set_subcheck_state(sc2, STATE_OK);
238
239 mp_perfdata pd2 = perfdata_init();
240 pd2.uom = "B";
241 pd2.label = "baz";
242 pd2 = mp_set_pd_value(pd2, 1024);
243 mp_add_perfdata_to_subcheck(&sc2, pd2);
244
245 // level 3
246 mp_subcheck sc3 = mp_subcheck_init();
247 sc3.output = "level3";
248 sc3 = mp_set_subcheck_state(sc3, STATE_OK);
249
250 mp_perfdata pd3 = perfdata_init();
251 pd3.label = "floatMe";
252 pd3 = mp_set_pd_value(pd3, 1024.1024);
253 mp_add_perfdata_to_subcheck(&sc3, pd3);
254
255 // level 4
256 mp_subcheck sc4 = mp_subcheck_init();
257 sc4.output = "level4";
258 sc4 = mp_set_subcheck_state(sc4, STATE_OK);
259
260 mp_check check = mp_check_init();
261
262 mp_add_subcheck_to_subcheck(&sc3, sc4);
263 mp_add_subcheck_to_subcheck(&sc2, sc3);
264 mp_add_subcheck_to_subcheck(&sc1, sc2);
265 mp_add_subcheck_to_check(&check, sc1);
266
267 char *output = mp_fmt_output(check);
268
269 // diag("Formatted output of length: %i", strlen(output));
270 // diag(output);
271
272 ok(output != NULL, "Output should not be NULL");
273
274 char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n"
275 "\t\\_[WARNING] - foobar\n"
276 "\t\t\\_[OK] - baz\n"
277 "\t\t\t\\_[OK] - level3\n"
278 "\t\t\t\t\\_[OK] - level4\n"
279 "|foo=23s;;; baz=1024B;;; floatMe=1024.102400;;; \n";
280
281 // diag("Expected output of length: %i", strlen(expected));
282 // diag(expected);
283
284 ok(strcmp(output, expected) == 0, "Output is as expected");
285}
286
287void test_default_states1(void) {
288 mp_subcheck sc = mp_subcheck_init();
289
290 mp_state_enum state1 = mp_compute_subcheck_state(sc);
291 ok(state1 == STATE_UNKNOWN, "Default default state is Unknown");
292
293 sc = mp_set_subcheck_default_state(sc, STATE_CRITICAL);
294
295 mp_state_enum state2 = mp_compute_subcheck_state(sc);
296 ok(state2 == STATE_CRITICAL, "Default state is Critical");
297
298 sc = mp_set_subcheck_state(sc, STATE_OK);
299
300 mp_state_enum state3 = mp_compute_subcheck_state(sc);
301 ok(state3 == STATE_OK, "Default state is Critical");
302}
303
304void test_default_states2(void) {
305 mp_check check = mp_check_init();
306
307 mp_subcheck sc = mp_subcheck_init();
308 sc.output = "placeholder";
309 sc = mp_set_subcheck_default_state(sc, STATE_CRITICAL);
310
311 mp_add_subcheck_to_check(&check, sc);
312
313 mp_state_enum result_state = mp_compute_check_state(check);
314 ok(result_state == STATE_CRITICAL, "Derived state is the proper default state");
315}
diff --git a/lib/tests/test_generic_output.t b/lib/tests/test_generic_output.t
new file mode 100644
index 00000000..48c2ddf4
--- /dev/null
+++ b/lib/tests/test_generic_output.t
@@ -0,0 +1,6 @@
1#!/usr/bin/perl
2use Test::More;
3if (! -e "./test_generic_output") {
4 plan skip_all => "./test_generic_output not compiled - please enable libtap library to test";
5}
6exec "./test_generic_output";
diff --git a/lib/tests/test_ini1.c b/lib/tests/test_ini1.c
index 6843bac2..246c1250 100644
--- a/lib/tests/test_ini1.c
+++ b/lib/tests/test_ini1.c
@@ -1,20 +1,20 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* This program is free software: you can redistribute it and/or modify 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 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 5 * the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version. 6 * (at your option) any later version.
7* 7 *
8* This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details. 11 * GNU General Public License for more details.
12* 12 *
13* You should have received a copy of the GNU General Public License 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/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15* 15 *
16* 16 *
17*****************************************************************************/ 17 *****************************************************************************/
18 18
19#include "common.h" 19#include "common.h"
20#include "utils_base.h" 20#include "utils_base.h"
@@ -29,81 +29,93 @@ void my_free(char *string) {
29 } 29 }
30} 30}
31 31
32char* 32char *list2str(np_arg_list *optlst) {
33list2str(np_arg_list *optlst) 33 char *optstr = NULL;
34{
35 char *optstr=NULL;
36 np_arg_list *optltmp; 34 np_arg_list *optltmp;
37 35
38 /* Put everything as a space-separated string */ 36 /* Put everything as a space-separated string */
39 asprintf(&optstr, ""); 37 asprintf(&optstr, "");
40 while (optlst) { 38 while (optlst) {
41 asprintf(&optstr, "%s%s ", optstr, optlst->arg); 39 asprintf(&optstr, "%s%s ", optstr, optlst->arg);
42 optltmp=optlst; 40 optltmp = optlst;
43 optlst=optlst->next; 41 optlst = optlst->next;
44 free(optltmp); 42 free(optltmp);
45 } 43 }
46 /* Strip last whitespace */ 44 /* Strip last whitespace */
47 if (strlen(optstr)>1) optstr[strlen(optstr)-1]='\0'; 45 if (strlen(optstr) > 1)
46 optstr[strlen(optstr) - 1] = '\0';
48 47
49 return optstr; 48 return optstr;
50} 49}
51 50
52int 51int main(int argc, char **argv) {
53main (int argc, char **argv) 52 char *optstr = NULL;
54{
55 char *optstr=NULL;
56 53
57 plan_tests(12); 54 plan_tests(12);
58 55
59 optstr=list2str(np_get_defaults("section@./config-tiny.ini", "check_disk")); 56 optstr = list2str(np_get_defaults("section@./config-tiny.ini", "check_disk"));
60 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"), "config-tiny.ini's section as expected");
61 my_free(optstr); 58 my_free(optstr);
62 59
63 optstr=list2str(np_get_defaults("@./config-tiny.ini", "section")); 60 optstr = list2str(np_get_defaults("@./config-tiny.ini", "section"));
64 ok( !strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank"), "Used default section name, without specific"); 61 ok(!strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank"), "Used default section name, without specific");
65 my_free(optstr); 62 my_free(optstr);
66 63
67 optstr=list2str(np_get_defaults("Section Two@./config-tiny.ini", "check_disk")); 64 optstr = list2str(np_get_defaults("Section Two@./config-tiny.ini", "check_disk"));
68 ok( !strcmp(optstr, "--something else=blah --remove=whitespace"), "config-tiny.ini's Section Two as expected"); 65 ok(!strcmp(optstr, "--something else=blah --remove=whitespace"), "config-tiny.ini's Section Two as expected");
69 my_free(optstr); 66 my_free(optstr);
70 67
71 optstr=list2str(np_get_defaults("/path/to/file.txt@./config-tiny.ini", "check_disk")); 68 optstr = list2str(np_get_defaults("/path/to/file.txt@./config-tiny.ini", "check_disk"));
72 ok( !strcmp(optstr, "--this=that"), "config-tiny.ini's filename as section name"); 69 ok(!strcmp(optstr, "--this=that"), "config-tiny.ini's filename as section name");
73 my_free(optstr); 70 my_free(optstr);
74 71
75 optstr=list2str(np_get_defaults("section2@./config-tiny.ini", "check_disk")); 72 optstr = list2str(np_get_defaults("section2@./config-tiny.ini", "check_disk"));
76 ok( !strcmp(optstr, "--this=that"), "config-tiny.ini's section2 with whitespace before section name"); 73 ok(!strcmp(optstr, "--this=that"), "config-tiny.ini's section2 with whitespace before section name");
77 my_free(optstr); 74 my_free(optstr);
78 75
79 optstr=list2str(np_get_defaults("section3@./config-tiny.ini", "check_disk")); 76 optstr = list2str(np_get_defaults("section3@./config-tiny.ini", "check_disk"));
80 ok( !strcmp(optstr, "--this=that"), "config-tiny.ini's section3 with whitespace after section name"); 77 ok(!strcmp(optstr, "--this=that"), "config-tiny.ini's section3 with whitespace after section name");
81 my_free(optstr); 78 my_free(optstr);
82 79
83 optstr=list2str(np_get_defaults("check_mysql@./plugin.ini", "check_disk")); 80 optstr = list2str(np_get_defaults("check_mysql@./plugin.ini", "check_disk"));
84 ok( !strcmp(optstr, "--username=operator --password=secret"), "plugin.ini's check_mysql as expected"); 81 ok(!strcmp(optstr, "--username=operator --password=secret"), "plugin.ini's check_mysql as expected");
85 my_free(optstr); 82 my_free(optstr);
86 83
87 optstr=list2str(np_get_defaults("check_mysql2@./plugin.ini", "check_disk")); 84 optstr = list2str(np_get_defaults("check_mysql2@./plugin.ini", "check_disk"));
88 ok( !strcmp(optstr, "-u=admin -p=secret"), "plugin.ini's check_mysql2 as expected"); 85 ok(!strcmp(optstr, "-u=admin -p=secret"), "plugin.ini's check_mysql2 as expected");
89 my_free(optstr); 86 my_free(optstr);
90 87
91 optstr=list2str(np_get_defaults("check space_and_flags@./plugin.ini", "check_disk")); 88 optstr = list2str(np_get_defaults("check space_and_flags@./plugin.ini", "check_disk"));
92 ok( !strcmp(optstr, "--foo=bar -a -b --bar"), "plugin.ini space in stanza and flag arguments"); 89 ok(!strcmp(optstr, "--foo=bar -a -b --bar"), "plugin.ini space in stanza and flag arguments");
93 my_free(optstr); 90 my_free(optstr);
94 91
95 optstr=list2str(np_get_defaults("Section Two@./config-dos.ini", "check_disk")); 92 optstr = list2str(np_get_defaults("Section Two@./config-dos.ini", "check_disk"));
96 ok( !strcmp(optstr, "--something else=blah --remove=whitespace"), "config-dos.ini's Section Two as expected"); 93 ok(!strcmp(optstr, "--something else=blah --remove=whitespace"), "config-dos.ini's Section Two as expected");
97 my_free(optstr); 94 my_free(optstr);
98 95
99 optstr=list2str(np_get_defaults("section_twice@./plugin.ini", "check_disk")); 96 optstr = list2str(np_get_defaults("section_twice@./plugin.ini", "check_disk"));
100 ok( !strcmp(optstr, "--foo=bar --bar=foo"), "plugin.ini's section_twice defined twice in the file"); 97 ok(!strcmp(optstr, "--foo=bar --bar=foo"), "plugin.ini's section_twice defined twice in the file");
101 my_free(optstr); 98 my_free(optstr);
102 99
103 optstr=list2str(np_get_defaults("tcp_long_lines@plugins.ini", "check_tcp")); 100 optstr = list2str(np_get_defaults("tcp_long_lines@plugins.ini", "check_tcp"));
104 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 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 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 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 yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda --expect=Foo bar 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 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 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 yadda Foo bar 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 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 yadda yadda Foo bar BAZ yadda yadda yadda --jail"), "Long options"); 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 "
102 "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 "
104 "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 "
106 "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 "
108 "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 "
110 "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 "
112 "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 "
114 "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 "
116 "bar BAZ yadda yadda yadda --jail"),
117 "Long options");
105 my_free(optstr); 118 my_free(optstr);
106 119
107 return exit_status(); 120 return exit_status();
108} 121}
109
diff --git a/lib/tests/test_ini3.c b/lib/tests/test_ini3.c
index 8a2a0414..2186e4bb 100644
--- a/lib/tests/test_ini3.c
+++ b/lib/tests/test_ini3.c
@@ -1,26 +1,24 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* This program is free software: you can redistribute it and/or modify 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 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 5 * the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version. 6 * (at your option) any later version.
7* 7 *
8* This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details. 11 * GNU General Public License for more details.
12* 12 *
13* You should have received a copy of the GNU General Public License 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/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15* 15 *
16* 16 *
17*****************************************************************************/ 17 *****************************************************************************/
18 18
19#include "parse_ini.h" 19#include "parse_ini.h"
20 20
21int 21int main(int argc, char **argv) {
22main (int argc, char **argv)
23{
24 22
25 /* 23 /*
26 * This is for testing arguments expected to die. 24 * This is for testing arguments expected to die.
@@ -30,4 +28,3 @@ main (int argc, char **argv)
30 28
31 return 0; 29 return 0;
32} 30}
33
diff --git a/lib/tests/test_opts1.c b/lib/tests/test_opts1.c
index 077c5b63..984183d3 100644
--- a/lib/tests/test_opts1.c
+++ b/lib/tests/test_opts1.c
@@ -1,19 +1,19 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* This program is free software: you can redistribute it and/or modify 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 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 5 * the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version. 6 * (at your option) any later version.
7* 7 *
8* This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details. 11 * GNU General Public License for more details.
12* 12 *
13* You should have received a copy of the GNU General Public License 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/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15* 15 *
16*****************************************************************************/ 16 *****************************************************************************/
17 17
18#include "common.h" 18#include "common.h"
19#include "utils_base.h" 19#include "utils_base.h"
@@ -40,23 +40,24 @@ 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 int i, freeflag = 1;
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 for (i = 1; i < *argc; i++) {
47 printf ("'%s' ", newargv[i]); 47 printf("'%s' ", newargv[i]);
48 /* Stop freeing when we get to the start of the original array */ 48 /* Stop freeing when we get to the start of the original array */
49 if (freeflag) { 49 if (freeflag) {
50 if (newargv[i] == argv[1]) 50 if (newargv[i] == argv[1])
51 freeflag=0; 51 freeflag = 0;
52 else 52 else
53 free(newargv[i]); 53 free(newargv[i]);
54 } 54 }
55 } 55 }
56 printf ("\n"); 56 printf("\n");
57 /* Free only if it's a different array */ 57 /* Free only if it's a different array */
58 if (newargv != argv) free(newargv); 58 if (newargv != argv)
59 *argc=0; 59 free(newargv);
60 *argc = 0;
60} 61}
61#endif 62#endif
62 63
@@ -67,9 +68,10 @@ int array_diff(int i1, char **a1, int i2, char **a2) {
67 printf(" Argument count doesn't match!\n"); 68 printf(" Argument count doesn't match!\n");
68 return 0; 69 return 0;
69 } 70 }
70 for (i=0; i<=i1; i++) { 71 for (i = 0; i <= i1; i++) {
71 if (a1[i]==NULL && a2[i]==NULL) continue; 72 if (a1[i] == NULL && a2[i] == NULL)
72 if (a1[i]==NULL || a2[i]==NULL) { 73 continue;
74 if (a1[i] == NULL || a2[i] == NULL) {
73 printf(" Argument # %i null in one array!\n", i); 75 printf(" Argument # %i null in one array!\n", i);
74 return 0; 76 return 0;
75 } 77 }
@@ -81,59 +83,58 @@ int array_diff(int i1, char **a1, int i2, char **a2) {
81 return 1; 83 return 1;
82} 84}
83 85
84int 86int main(int argc, char **argv) {
85main (int argc, char **argv) 87 char **argv_new = NULL;
86{
87 char **argv_new=NULL;
88 int i, argc_test; 88 int i, argc_test;
89 89
90 plan_tests(5); 90 plan_tests(5);
91 91
92 { 92 {
93 char *argv_test[] = {"prog_name", (char *) NULL}; 93 char *argv_test[] = {"prog_name", (char *)NULL};
94 argc_test=1; 94 argc_test = 1;
95 char *argv_known[] = {"prog_name", (char *) NULL}; 95 char *argv_known[] = {"prog_name", (char *)NULL};
96 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 96 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
97 ok(array_diff(argc_test, argv_new, 1, argv_known), "No opts, returns correct argv/argc"); 97 ok(array_diff(argc_test, argv_new, 1, argv_known), "No opts, returns correct argv/argc");
98 my_free(&argc_test, argv_new, argv_test); 98 my_free(&argc_test, argv_new, argv_test);
99 } 99 }
100 100
101 { 101 {
102 char *argv_test[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *) NULL}; 102 char *argv_test[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *)NULL};
103 argc_test=5; 103 argc_test = 5;
104 char *argv_known[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *) NULL}; 104 char *argv_known[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *)NULL};
105 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 105 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
106 ok(array_diff(argc_test, argv_new, 5, argv_known), "No extra opts, verbatim copy of argv"); 106 ok(array_diff(argc_test, argv_new, 5, argv_known), "No extra opts, verbatim copy of argv");
107 my_free(&argc_test, argv_new, argv_test); 107 my_free(&argc_test, argv_new, argv_test);
108 } 108 }
109 109
110 { 110 {
111 char *argv_test[] = {"prog_name", "--extra-opts=@./config-opts.ini", (char *) NULL}; 111 char *argv_test[] = {"prog_name", "--extra-opts=@./config-opts.ini", (char *)NULL};
112 argc_test=2; 112 argc_test = 2;
113 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank", (char *) NULL}; 113 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank", (char *)NULL};
114 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 114 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"); 115 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); 116 my_free(&argc_test, argv_new, argv_test);
117 } 117 }
118 118
119 { 119 {
120 char *argv_test[] = {"prog_name", "--extra-opts=sect1@./config-opts.ini", "--extra-opts", "sect2@./config-opts.ini", (char *) NULL}; 120 char *argv_test[] = {"prog_name", "--extra-opts=sect1@./config-opts.ini", "--extra-opts", "sect2@./config-opts.ini", (char *)NULL};
121 argc_test=4; 121 argc_test = 4;
122 char *argv_known[] = {"prog_name", "--one=two", "--something else=oops", "--this=that", (char *) NULL}; 122 char *argv_known[] = {"prog_name", "--one=two", "--something else=oops", "--this=that", (char *)NULL};
123 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 123 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"); 124 ok(array_diff(argc_test, argv_new, 4, argv_known), "Only extra opts specified twice");
125 my_free(&argc_test, argv_new, argv_test); 125 my_free(&argc_test, argv_new, argv_test);
126 } 126 }
127 127
128 { 128 {
129 char *argv_test[] = {"prog_name", "--arg1=val1", "--extra-opts=@./config-opts.ini", "--extra-opts", "sect1@./config-opts.ini", "--arg2", (char *) NULL}; 129 char *argv_test[] = {"prog_name", "--arg1=val1", "--extra-opts=@./config-opts.ini", "--extra-opts", "sect1@./config-opts.ini",
130 argc_test=6; 130 "--arg2", (char *)NULL};
131 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank", "--one=two", "--arg1=val1", "--arg2", (char *) NULL}; 131 argc_test = 6;
132 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 132 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank", "--one=two",
133 "--arg1=val1", "--arg2", (char *)NULL};
134 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
133 ok(array_diff(argc_test, argv_new, 7, argv_known), "twice extra opts using two sections"); 135 ok(array_diff(argc_test, argv_new, 7, argv_known), "twice extra opts using two sections");
134 my_free(&argc_test, argv_new, argv_test); 136 my_free(&argc_test, argv_new, argv_test);
135 } 137 }
136 138
137 return exit_status(); 139 return exit_status();
138} 140}
139
diff --git a/lib/tests/test_opts2.c b/lib/tests/test_opts2.c
index 780220ee..23496617 100644
--- a/lib/tests/test_opts2.c
+++ b/lib/tests/test_opts2.c
@@ -1,19 +1,19 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* This program is free software: you can redistribute it and/or modify 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 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 5 * the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version. 6 * (at your option) any later version.
7* 7 *
8* This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details. 11 * GNU General Public License for more details.
12* 12 *
13* You should have received a copy of the GNU General Public License 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/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15* 15 *
16*****************************************************************************/ 16 *****************************************************************************/
17 17
18#include "common.h" 18#include "common.h"
19#include "utils_base.h" 19#include "utils_base.h"
@@ -23,23 +23,24 @@
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 int i, freeflag = 1;
27 printf (" Arg(%i): ", *argc+1); 27 printf(" Arg(%i): ", *argc + 1);
28 printf ("'%s' ", newargv[0]); 28 printf("'%s' ", newargv[0]);
29 for (i=1; i<*argc; i++) { 29 for (i = 1; i < *argc; i++) {
30 printf ("'%s' ", newargv[i]); 30 printf("'%s' ", newargv[i]);
31 /* Stop freeing when we get to the start of the original array */ 31 /* Stop freeing when we get to the start of the original array */
32 if (freeflag) { 32 if (freeflag) {
33 if (newargv[i] == argv[1]) 33 if (newargv[i] == argv[1])
34 freeflag=0; 34 freeflag = 0;
35 else 35 else
36 free(newargv[i]); 36 free(newargv[i]);
37 } 37 }
38 } 38 }
39 printf ("\n"); 39 printf("\n");
40 /* Free only if it's a different array */ 40 /* Free only if it's a different array */
41 if (newargv != argv) free(newargv); 41 if (newargv != argv)
42 *argc=0; 42 free(newargv);
43 *argc = 0;
43} 44}
44 45
45int array_diff(int i1, char **a1, int i2, char **a2) { 46int array_diff(int i1, char **a1, int i2, char **a2) {
@@ -49,9 +50,10 @@ int array_diff(int i1, char **a1, int i2, char **a2) {
49 printf(" Argument count doesn't match!\n"); 50 printf(" Argument count doesn't match!\n");
50 return 0; 51 return 0;
51 } 52 }
52 for (i=0; i<=i1; i++) { 53 for (i = 0; i <= i1; i++) {
53 if (a1[i]==NULL && a2[i]==NULL) continue; 54 if (a1[i] == NULL && a2[i] == NULL)
54 if (a1[i]==NULL || a2[i]==NULL) { 55 continue;
56 if (a1[i] == NULL || a2[i] == NULL) {
55 printf(" Argument # %i null in one array!\n", i); 57 printf(" Argument # %i null in one array!\n", i);
56 return 0; 58 return 0;
57 } 59 }
@@ -63,59 +65,77 @@ int array_diff(int i1, char **a1, int i2, char **a2) {
63 return 1; 65 return 1;
64} 66}
65 67
66int 68int main(int argc, char **argv) {
67main (int argc, char **argv) 69 char **argv_new = NULL;
68{
69 char **argv_new=NULL;
70 int i, argc_test; 70 int i, argc_test;
71 71
72 plan_tests(5); 72 plan_tests(5);
73 73
74 { 74 {
75 char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "--arg3", "val2", (char *) NULL}; 75 char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "--arg3", "val2", (char *)NULL};
76 argc_test=5; 76 argc_test = 5;
77 char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "--arg3", "val2", (char *) NULL}; 77 char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "--arg3", "val2", (char *)NULL};
78 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 78 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
79 ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 1"); 79 ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 1");
80 my_free(&argc_test, argv_new, argv_test); 80 my_free(&argc_test, argv_new, argv_test);
81 } 81 }
82 82
83 { 83 {
84 char *argv_test[] = {"prog_name", "--extra-opts", (char *) NULL}; 84 char *argv_test[] = {"prog_name", "--extra-opts", (char *)NULL};
85 argc_test=2; 85 argc_test = 2;
86 char *argv_known[] = {"prog_name", "--foo=bar", (char *) NULL}; 86 char *argv_known[] = {"prog_name", "--foo=bar", (char *)NULL};
87 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 87 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
88 ok(array_diff(argc_test, argv_new, 2, argv_known), "Default section 2"); 88 ok(array_diff(argc_test, argv_new, 2, argv_known), "Default section 2");
89 my_free(&argc_test, argv_new, argv_test); 89 my_free(&argc_test, argv_new, argv_test);
90 } 90 }
91 91
92 { 92 {
93 char *argv_test[] = {"prog_name", "arg1", "--extra-opts=section1", "--arg3", "val2", (char *) NULL}; 93 char *argv_test[] = {"prog_name", "arg1", "--extra-opts=section1", "--arg3", "val2", (char *)NULL};
94 argc_test=5; 94 argc_test = 5;
95 char *argv_known[] = {"prog_name", "--foobar=baz", "arg1", "--arg3", "val2", (char *) NULL}; 95 char *argv_known[] = {"prog_name", "--foobar=baz", "arg1", "--arg3", "val2", (char *)NULL};
96 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 96 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
97 ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 3"); 97 ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 3");
98 my_free(&argc_test, argv_new, argv_test); 98 my_free(&argc_test, argv_new, argv_test);
99 } 99 }
100 100
101 { 101 {
102 char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "-arg3", "val2", (char *) NULL}; 102 char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "-arg3", "val2", (char *)NULL};
103 argc_test=5; 103 argc_test = 5;
104 char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "-arg3", "val2", (char *) NULL}; 104 char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "-arg3", "val2", (char *)NULL};
105 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 105 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
106 ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 4"); 106 ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 4");
107 my_free(&argc_test, argv_new, argv_test); 107 my_free(&argc_test, argv_new, argv_test);
108 } 108 }
109 109
110 { 110 {
111 char *argv_test[] = {"check_tcp", "--extra-opts", "--extra-opts=tcp_long_lines", (char *) NULL}; 111 char *argv_test[] = {"check_tcp", "--extra-opts", "--extra-opts=tcp_long_lines", (char *)NULL};
112 argc_test=3; 112 argc_test = 3;
113 char *argv_known[] = {"check_tcp", "--timeout=10", "--escape", "--send=Foo bar 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 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 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 yadda Foo bar 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 yadda yadda yadda", "--expect=Foo bar 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 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 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 yadda Foo bar 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 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 yadda yadda Foo bar BAZ yadda yadda yadda", "--jail", (char *) NULL}; 113 char *argv_known[] = {
114 argv_new=np_extra_opts(&argc_test, argv_test, "check_tcp"); 114 "check_tcp",
115 "--timeout=10",
116 "--escape",
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 "
118 "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 "
120 "yadda Foo bar BAZ "
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 "
122 "yadda yadda Foo bar "
123 "BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda 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 "
125 "yadda Foo bar BAZ yadda "
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 "
127 "yadda Foo bar BAZ "
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 "
129 "yadda yadda Foo bar "
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 "
131 "yadda yadda yadda Foo "
132 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda",
133 "--jail",
134 (char *)NULL};
135 argv_new = np_extra_opts(&argc_test, argv_test, "check_tcp");
115 ok(array_diff(argc_test, argv_new, 6, argv_known), "Long lines test"); 136 ok(array_diff(argc_test, argv_new, 6, argv_known), "Long lines test");
116 my_free(&argc_test, argv_new, argv_test); 137 my_free(&argc_test, argv_new, argv_test);
117 } 138 }
118 139
119 return exit_status(); 140 return exit_status();
120} 141}
121
diff --git a/lib/tests/test_opts3.c b/lib/tests/test_opts3.c
index b64270da..cecea437 100644
--- a/lib/tests/test_opts3.c
+++ b/lib/tests/test_opts3.c
@@ -1,31 +1,28 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* This program is free software: you can redistribute it and/or modify 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 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 5 * the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version. 6 * (at your option) any later version.
7* 7 *
8* This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details. 11 * GNU General Public License for more details.
12* 12 *
13* You should have received a copy of the GNU General Public License 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/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15* 15 *
16*****************************************************************************/ 16 *****************************************************************************/
17 17
18#include "extra_opts.h" 18#include "extra_opts.h"
19 19
20int 20int main(int argc, char **argv) {
21main (int argc, char **argv)
22{
23 21
24 /* 22 /*
25 * This is for testing arguments expected to die. 23 * This is for testing arguments expected to die.
26 */ 24 */
27 argv=np_extra_opts(&argc, argv, argv[0]); 25 argv = np_extra_opts(&argc, argv, argv[0]);
28 26
29 return 0; 27 return 0;
30} 28}
31
diff --git a/lib/tests/test_tcp.c b/lib/tests/test_tcp.c
index 1954b0fb..1b3003e9 100644
--- a/lib/tests/test_tcp.c
+++ b/lib/tests/test_tcp.c
@@ -1,34 +1,32 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* This program is free software: you can redistribute it and/or modify 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 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 5 * the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version. 6 * (at your option) any later version.
7* 7 *
8* This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details. 11 * GNU General Public License for more details.
12* 12 *
13* You should have received a copy of the GNU General Public License 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/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15* 15 *
16* 16 *
17*****************************************************************************/ 17 *****************************************************************************/
18 18
19#include "common.h" 19#include "common.h"
20#include "utils_tcp.h" 20#include "utils_tcp.h"
21#include "tap.h" 21#include "tap.h"
22 22
23int 23int main(void) {
24main(void)
25{
26 char **server_expect; 24 char **server_expect;
27 int server_expect_count = 3; 25 int server_expect_count = 3;
28 26
29 plan_tests(9); 27 plan_tests(9);
30 28
31 server_expect = malloc(sizeof(char*) * server_expect_count); 29 server_expect = malloc(sizeof(char *) * server_expect_count);
32 30
33 server_expect[0] = strdup("AA"); 31 server_expect[0] = strdup("AA");
34 server_expect[1] = strdup("bb"); 32 server_expect[1] = strdup("bb");
@@ -42,17 +40,13 @@ main(void)
42 "Test matching any string at the beginning (substring match)"); 40 "Test matching any string at the beginning (substring match)");
43 ok(np_expect_match("XX bb AA CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_FAILURE, 41 ok(np_expect_match("XX bb AA CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_FAILURE,
44 "Test with strings not matching at the beginning"); 42 "Test with strings not matching at the beginning");
45 ok(np_expect_match("XX CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_FAILURE, 43 ok(np_expect_match("XX CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_FAILURE, "Test matching any string");
46 "Test matching any string"); 44 ok(np_expect_match("XX", server_expect, server_expect_count, 0) == NP_MATCH_RETRY, "Test not matching any string");
47 ok(np_expect_match("XX", server_expect, server_expect_count, 0) == NP_MATCH_RETRY,
48 "Test not matching any string");
49 ok(np_expect_match("XX AA bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_SUCCESS, 45 ok(np_expect_match("XX AA bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_SUCCESS,
50 "Test matching all strings"); 46 "Test matching all strings");
51 ok(np_expect_match("XX bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_RETRY, 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");
52 "Test not matching all strings");
53 ok(np_expect_match("XX XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_RETRY, 48 ok(np_expect_match("XX XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_RETRY,
54 "Test not matching any string (testing all)"); 49 "Test not matching any string (testing all)");
55 50
56
57 return exit_status(); 51 return exit_status();
58} 52}
diff --git a/lib/tests/test_utils.c b/lib/tests/test_utils.c
index 01afacdc..c3150f00 100644
--- a/lib/tests/test_utils.c
+++ b/lib/tests/test_utils.c
@@ -1,20 +1,20 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* This program is free software: you can redistribute it and/or modify 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 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 5 * the Free Software Foundation, either version 3 of the License, or
6* (at your option) any later version. 6 * (at your option) any later version.
7* 7 *
8* This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details. 11 * GNU General Public License for more details.
12* 12 *
13* You should have received a copy of the GNU General Public License 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/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15* 15 *
16* 16 *
17*****************************************************************************/ 17 *****************************************************************************/
18 18
19#include "common.h" 19#include "common.h"
20#include "utils_base.h" 20#include "utils_base.h"
@@ -27,331 +27,323 @@
27 27
28#include "utils_base.c" 28#include "utils_base.c"
29 29
30int 30int main(int argc, char **argv) {
31main (int argc, char **argv)
32{
33 char state_path[1024]; 31 char state_path[1024];
34 range *range; 32 range *range;
35 double temp; 33 double temp;
36 thresholds *thresholds = NULL; 34 thresholds *thresholds = NULL;
37 int i, rc; 35 int i, rc;
38 char *temp_string; 36 char *temp_string;
39 state_key *temp_state_key = NULL; 37 state_key *temp_state_key = NULL;
40 state_data *temp_state_data; 38 state_data *temp_state_data;
41 time_t current_time; 39 time_t current_time;
42 40
43 plan_tests(185); 41 plan_tests(185);
44 42
45 ok( this_monitoring_plugin==NULL, "monitoring_plugin not initialised"); 43 ok(this_monitoring_plugin == NULL, "monitoring_plugin not initialised");
46 44
47 np_init( "check_test", argc, argv ); 45 np_init("check_test", argc, argv);
48 46
49 ok( this_monitoring_plugin!=NULL, "monitoring_plugin now initialised"); 47 ok(this_monitoring_plugin != NULL, "monitoring_plugin now initialised");
50 ok( !strcmp(this_monitoring_plugin->plugin_name, "check_test"), "plugin name initialised" ); 48 ok(!strcmp(this_monitoring_plugin->plugin_name, "check_test"), "plugin name initialised");
51 49
52 ok( this_monitoring_plugin->argc==argc, "Argc set" ); 50 ok(this_monitoring_plugin->argc == argc, "Argc set");
53 ok( this_monitoring_plugin->argv==argv, "Argv set" ); 51 ok(this_monitoring_plugin->argv == argv, "Argv set");
54 52
55 np_set_args(0,0); 53 np_set_args(0, 0);
56 54
57 ok( this_monitoring_plugin->argc==0, "argc changed" ); 55 ok(this_monitoring_plugin->argc == 0, "argc changed");
58 ok( this_monitoring_plugin->argv==0, "argv changed" ); 56 ok(this_monitoring_plugin->argv == 0, "argv changed");
59 57
60 np_set_args(argc, argv); 58 np_set_args(argc, argv);
61 59
62 range = parse_range_string("6"); 60 range = parse_range_string("6");
63 ok( range != NULL, "'6' is valid range"); 61 ok(range != NULL, "'6' is valid range");
64 ok( range->start == 0, "Start correct"); 62 ok(range->start == 0, "Start correct");
65 ok( range->start_infinity == false, "Not using negative infinity"); 63 ok(range->start_infinity == false, "Not using negative infinity");
66 ok( range->end == 6, "End correct"); 64 ok(range->end == 6, "End correct");
67 ok( range->end_infinity == false, "Not using infinity"); 65 ok(range->end_infinity == false, "Not using infinity");
68 free(range); 66 free(range);
69 67
70 range = parse_range_string("1:12%%"); 68 range = parse_range_string("1:12%%");
71 ok( range != NULL, "'1:12%%' is valid - percentages are ignored"); 69 ok(range != NULL, "'1:12%%' is valid - percentages are ignored");
72 ok( range->start == 1, "Start correct"); 70 ok(range->start == 1, "Start correct");
73 ok( range->start_infinity == false, "Not using negative infinity"); 71 ok(range->start_infinity == false, "Not using negative infinity");
74 ok( range->end == 12, "End correct"); 72 ok(range->end == 12, "End correct");
75 ok( range->end_infinity == false, "Not using infinity"); 73 ok(range->end_infinity == false, "Not using infinity");
76 free(range); 74 free(range);
77 75
78 range = parse_range_string("-7:23"); 76 range = parse_range_string("-7:23");
79 ok( range != NULL, "'-7:23' is valid range"); 77 ok(range != NULL, "'-7:23' is valid range");
80 ok( range->start == -7, "Start correct"); 78 ok(range->start == -7, "Start correct");
81 ok( range->start_infinity == false, "Not using negative infinity"); 79 ok(range->start_infinity == false, "Not using negative infinity");
82 ok( range->end == 23, "End correct"); 80 ok(range->end == 23, "End correct");
83 ok( range->end_infinity == false, "Not using infinity"); 81 ok(range->end_infinity == false, "Not using infinity");
84 free(range); 82 free(range);
85 83
86 range = parse_range_string(":5.75"); 84 range = parse_range_string(":5.75");
87 ok( range != NULL, "':5.75' is valid range"); 85 ok(range != NULL, "':5.75' is valid range");
88 ok( range->start == 0, "Start correct"); 86 ok(range->start == 0, "Start correct");
89 ok( range->start_infinity == false, "Not using negative infinity"); 87 ok(range->start_infinity == false, "Not using negative infinity");
90 ok( range->end == 5.75, "End correct"); 88 ok(range->end == 5.75, "End correct");
91 ok( range->end_infinity == false, "Not using infinity"); 89 ok(range->end_infinity == false, "Not using infinity");
92 free(range); 90 free(range);
93 91
94 range = parse_range_string("~:-95.99"); 92 range = parse_range_string("~:-95.99");
95 ok( range != NULL, "~:-95.99' is valid range"); 93 ok(range != NULL, "~:-95.99' is valid range");
96 ok( range->start_infinity == true, "Using negative infinity"); 94 ok(range->start_infinity == true, "Using negative infinity");
97 ok( range->end == -95.99, "End correct (with rounding errors)"); 95 ok(range->end == -95.99, "End correct (with rounding errors)");
98 ok( range->end_infinity == false, "Not using infinity"); 96 ok(range->end_infinity == false, "Not using infinity");
99 free(range); 97 free(range);
100 98
101 range = parse_range_string("12345678901234567890:"); 99 range = parse_range_string("12345678901234567890:");
102 temp = atof("12345678901234567890"); /* Can't just use this because number too large */ 100 temp = atof("12345678901234567890"); /* Can't just use this because number too large */
103 ok( range != NULL, "'12345678901234567890:' is valid range"); 101 ok(range != NULL, "'12345678901234567890:' is valid range");
104 ok( range->start == temp, "Start correct"); 102 ok(range->start == temp, "Start correct");
105 ok( range->start_infinity == false, "Not using negative infinity"); 103 ok(range->start_infinity == false, "Not using negative infinity");
106 ok( range->end_infinity == true, "Using infinity"); 104 ok(range->end_infinity == true, "Using infinity");
107 /* Cannot do a "-1" on temp, as it appears to be same value */ 105 /* Cannot do a "-1" on temp, as it appears to be same value */
108 ok( check_range(temp/1.1, range) == true, "12345678901234567890/1.1 - alert"); 106 ok(check_range(temp / 1.1, range) == true, "12345678901234567890/1.1 - alert");
109 ok( check_range(temp, range) == false, "12345678901234567890 - no alert"); 107 ok(check_range(temp, range) == false, "12345678901234567890 - no alert");
110 ok( check_range(temp*2, range) == false, "12345678901234567890*2 - no alert"); 108 ok(check_range(temp * 2, range) == false, "12345678901234567890*2 - no alert");
111 free(range); 109 free(range);
112 110
113 range = parse_range_string("~:0"); 111 range = parse_range_string("~:0");
114 ok( range != NULL, "'~:0' is valid range"); 112 ok(range != NULL, "'~:0' is valid range");
115 ok( range->start_infinity == true, "Using negative infinity"); 113 ok(range->start_infinity == true, "Using negative infinity");
116 ok( range->end == 0, "End correct"); 114 ok(range->end == 0, "End correct");
117 ok( range->end_infinity == false, "Not using infinity"); 115 ok(range->end_infinity == false, "Not using infinity");
118 ok( range->alert_on == OUTSIDE, "Will alert on outside of this range"); 116 ok(range->alert_on == OUTSIDE, "Will alert on outside of this range");
119 ok( check_range(0.5, range) == true, "0.5 - alert"); 117 ok(check_range(0.5, range) == true, "0.5 - alert");
120 ok( check_range(-10, range) == false, "-10 - no alert"); 118 ok(check_range(-10, range) == false, "-10 - no alert");
121 ok( check_range(0, range) == false, "0 - no alert"); 119 ok(check_range(0, range) == false, "0 - no alert");
122 free(range); 120 free(range);
123 121
124 range = parse_range_string("@0:657.8210567"); 122 range = parse_range_string("@0:657.8210567");
125 ok( range != 0, "@0:657.8210567' is a valid range"); 123 ok(range != 0, "@0:657.8210567' is a valid range");
126 ok( range->start == 0, "Start correct"); 124 ok(range->start == 0, "Start correct");
127 ok( range->start_infinity == false, "Not using negative infinity"); 125 ok(range->start_infinity == false, "Not using negative infinity");
128 ok( range->end == 657.8210567, "End correct"); 126 ok(range->end == 657.8210567, "End correct");
129 ok( range->end_infinity == false, "Not using infinity"); 127 ok(range->end_infinity == false, "Not using infinity");
130 ok( range->alert_on == INSIDE, "Will alert on inside of this range" ); 128 ok(range->alert_on == INSIDE, "Will alert on inside of this range");
131 ok( check_range(32.88, range) == true, "32.88 - alert"); 129 ok(check_range(32.88, range) == true, "32.88 - alert");
132 ok( check_range(-2, range) == false, "-2 - no alert"); 130 ok(check_range(-2, range) == false, "-2 - no alert");
133 ok( check_range(657.8210567, range) == true, "657.8210567 - alert"); 131 ok(check_range(657.8210567, range) == true, "657.8210567 - alert");
134 ok( check_range(0, range) == true, "0 - alert"); 132 ok(check_range(0, range) == true, "0 - alert");
135 free(range); 133 free(range);
136 134
137 range = parse_range_string("@1:1"); 135 range = parse_range_string("@1:1");
138 ok( range != NULL, "'@1:1' is a valid range"); 136 ok(range != NULL, "'@1:1' is a valid range");
139 ok( range->start == 1, "Start correct"); 137 ok(range->start == 1, "Start correct");
140 ok( range->start_infinity == false, "Not using negative infinity"); 138 ok(range->start_infinity == false, "Not using negative infinity");
141 ok( range->end == 1, "End correct"); 139 ok(range->end == 1, "End correct");
142 ok( range->end_infinity == false, "Not using infinity"); 140 ok(range->end_infinity == false, "Not using infinity");
143 ok( range->alert_on == INSIDE, "Will alert on inside of this range" ); 141 ok(range->alert_on == INSIDE, "Will alert on inside of this range");
144 ok( check_range(0.5, range) == false, "0.5 - no alert"); 142 ok(check_range(0.5, range) == false, "0.5 - no alert");
145 ok( check_range(1, range) == true, "1 - alert"); 143 ok(check_range(1, range) == true, "1 - alert");
146 ok( check_range(5.2, range) == false, "5.2 - no alert"); 144 ok(check_range(5.2, range) == false, "5.2 - no alert");
147 free(range); 145 free(range);
148 146
149 range = parse_range_string("1:1"); 147 range = parse_range_string("1:1");
150 ok( range != NULL, "'1:1' is a valid range"); 148 ok(range != NULL, "'1:1' is a valid range");
151 ok( range->start == 1, "Start correct"); 149 ok(range->start == 1, "Start correct");
152 ok( range->start_infinity == false, "Not using negative infinity"); 150 ok(range->start_infinity == false, "Not using negative infinity");
153 ok( range->end == 1, "End correct"); 151 ok(range->end == 1, "End correct");
154 ok( range->end_infinity == false, "Not using infinity"); 152 ok(range->end_infinity == false, "Not using infinity");
155 ok( check_range(0.5, range) == true, "0.5 - alert"); 153 ok(check_range(0.5, range) == true, "0.5 - alert");
156 ok( check_range(1, range) == false, "1 - no alert"); 154 ok(check_range(1, range) == false, "1 - no alert");
157 ok( check_range(5.2, range) == true, "5.2 - alert"); 155 ok(check_range(5.2, range) == true, "5.2 - alert");
158 free(range); 156 free(range);
159 157
160 range = parse_range_string("2:1"); 158 range = parse_range_string("2:1");
161 ok( range == NULL, "'2:1' rejected"); 159 ok(range == NULL, "'2:1' rejected");
162 160
163 rc = _set_thresholds(&thresholds, NULL, NULL); 161 rc = _set_thresholds(&thresholds, NULL, NULL);
164 ok( rc == 0, "Thresholds (NULL, NULL) set"); 162 ok(rc == 0, "Thresholds (NULL, NULL) set");
165 ok( thresholds->warning == NULL, "Warning not set"); 163 ok(thresholds->warning == NULL, "Warning not set");
166 ok( thresholds->critical == NULL, "Critical not set"); 164 ok(thresholds->critical == NULL, "Critical not set");
167 165
168 rc = _set_thresholds(&thresholds, NULL, "80"); 166 rc = _set_thresholds(&thresholds, NULL, "80");
169 ok( rc == 0, "Thresholds (NULL, '80') set"); 167 ok(rc == 0, "Thresholds (NULL, '80') set");
170 ok( thresholds->warning == NULL, "Warning not set"); 168 ok(thresholds->warning == NULL, "Warning not set");
171 ok( thresholds->critical->end == 80, "Critical set correctly"); 169 ok(thresholds->critical->end == 80, "Critical set correctly");
172 170
173 rc = _set_thresholds(&thresholds, "5:33", NULL); 171 rc = _set_thresholds(&thresholds, "5:33", NULL);
174 ok( rc == 0, "Thresholds ('5:33', NULL) set"); 172 ok(rc == 0, "Thresholds ('5:33', NULL) set");
175 ok( thresholds->warning->start == 5, "Warning start set"); 173 ok(thresholds->warning->start == 5, "Warning start set");
176 ok( thresholds->warning->end == 33, "Warning end set"); 174 ok(thresholds->warning->end == 33, "Warning end set");
177 ok( thresholds->critical == NULL, "Critical not set"); 175 ok(thresholds->critical == NULL, "Critical not set");
178 176
179 rc = _set_thresholds(&thresholds, "30", "60"); 177 rc = _set_thresholds(&thresholds, "30", "60");
180 ok( rc == 0, "Thresholds ('30', '60') set"); 178 ok(rc == 0, "Thresholds ('30', '60') set");
181 ok( thresholds->warning->end == 30, "Warning set correctly"); 179 ok(thresholds->warning->end == 30, "Warning set correctly");
182 ok( thresholds->critical->end == 60, "Critical set correctly"); 180 ok(thresholds->critical->end == 60, "Critical set correctly");
183 ok( get_status(15.3, thresholds) == STATE_OK, "15.3 - ok"); 181 ok(get_status(15.3, thresholds) == STATE_OK, "15.3 - ok");
184 ok( get_status(30.0001, thresholds) == STATE_WARNING, "30.0001 - warning"); 182 ok(get_status(30.0001, thresholds) == STATE_WARNING, "30.0001 - warning");
185 ok( get_status(69, thresholds) == STATE_CRITICAL, "69 - critical"); 183 ok(get_status(69, thresholds) == STATE_CRITICAL, "69 - critical");
186 184
187 rc = _set_thresholds(&thresholds, "-10:-2", "-30:20"); 185 rc = _set_thresholds(&thresholds, "-10:-2", "-30:20");
188 ok( rc == 0, "Thresholds ('-30:20', '-10:-2') set"); 186 ok(rc == 0, "Thresholds ('-30:20', '-10:-2') set");
189 ok( thresholds->warning->start == -10, "Warning start set correctly"); 187 ok(thresholds->warning->start == -10, "Warning start set correctly");
190 ok( thresholds->warning->end == -2, "Warning end set correctly"); 188 ok(thresholds->warning->end == -2, "Warning end set correctly");
191 ok( thresholds->critical->start == -30, "Critical start set correctly"); 189 ok(thresholds->critical->start == -30, "Critical start set correctly");
192 ok( thresholds->critical->end == 20, "Critical end set correctly"); 190 ok(thresholds->critical->end == 20, "Critical end set correctly");
193 ok( get_status(-31, thresholds) == STATE_CRITICAL, "-31 - critical"); 191 ok(get_status(-31, thresholds) == STATE_CRITICAL, "-31 - critical");
194 ok( get_status(-29, thresholds) == STATE_WARNING, "-29 - warning"); 192 ok(get_status(-29, thresholds) == STATE_WARNING, "-29 - warning");
195 ok( get_status(-11, thresholds) == STATE_WARNING, "-11 - warning"); 193 ok(get_status(-11, thresholds) == STATE_WARNING, "-11 - warning");
196 ok( get_status(-10, thresholds) == STATE_OK, "-10 - ok"); 194 ok(get_status(-10, thresholds) == STATE_OK, "-10 - ok");
197 ok( get_status(-2, thresholds) == STATE_OK, "-2 - ok"); 195 ok(get_status(-2, thresholds) == STATE_OK, "-2 - ok");
198 ok( get_status(-1, thresholds) == STATE_WARNING, "-1 - warning"); 196 ok(get_status(-1, thresholds) == STATE_WARNING, "-1 - warning");
199 ok( get_status(19, thresholds) == STATE_WARNING, "19 - warning"); 197 ok(get_status(19, thresholds) == STATE_WARNING, "19 - warning");
200 ok( get_status(21, thresholds) == STATE_CRITICAL, "21 - critical"); 198 ok(get_status(21, thresholds) == STATE_CRITICAL, "21 - critical");
201 199
202 char *test; 200 char *test;
203 test = np_escaped_string("bob\\n"); 201 test = np_escaped_string("bob\\n");
204 ok( strcmp(test, "bob\n") == 0, "bob\\n ok"); 202 ok(strcmp(test, "bob\n") == 0, "bob\\n ok");
205 free(test); 203 free(test);
206 204
207 test = np_escaped_string("rhuba\\rb"); 205 test = np_escaped_string("rhuba\\rb");
208 ok( strcmp(test, "rhuba\rb") == 0, "rhuba\\rb okay"); 206 ok(strcmp(test, "rhuba\rb") == 0, "rhuba\\rb okay");
209 free(test); 207 free(test);
210 208
211 test = np_escaped_string("ba\\nge\\r"); 209 test = np_escaped_string("ba\\nge\\r");
212 ok( strcmp(test, "ba\nge\r") == 0, "ba\\nge\\r okay"); 210 ok(strcmp(test, "ba\nge\r") == 0, "ba\\nge\\r okay");
213 free(test); 211 free(test);
214 212
215 test = np_escaped_string("\\rabbi\\t"); 213 test = np_escaped_string("\\rabbi\\t");
216 ok( strcmp(test, "\rabbi\t") == 0, "\\rabbi\\t okay"); 214 ok(strcmp(test, "\rabbi\t") == 0, "\\rabbi\\t okay");
217 free(test); 215 free(test);
218 216
219 test = np_escaped_string("and\\\\or"); 217 test = np_escaped_string("and\\\\or");
220 ok( strcmp(test, "and\\or") == 0, "and\\\\or okay"); 218 ok(strcmp(test, "and\\or") == 0, "and\\\\or okay");
221 free(test); 219 free(test);
222 220
223 test = np_escaped_string("bo\\gus"); 221 test = np_escaped_string("bo\\gus");
224 ok( strcmp(test, "bogus") == 0, "bo\\gus okay"); 222 ok(strcmp(test, "bogus") == 0, "bo\\gus okay");
225 free(test); 223 free(test);
226 224
227 test = np_escaped_string("everything"); 225 test = np_escaped_string("everything");
228 ok( strcmp(test, "everything") == 0, "everything okay"); 226 ok(strcmp(test, "everything") == 0, "everything okay");
229 227
230 /* np_extract_ntpvar tests (23) */ 228 /* np_extract_ntpvar tests (23) */
231 test=np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foo"); 229 test = np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foo");
232 ok(test && !strcmp(test, "bar"), "1st test as expected"); 230 ok(test && !strcmp(test, "bar"), "1st test as expected");
233 free(test); 231 free(test);
234 232
235 test=np_extract_ntpvar("foo=bar,bar=foo,foobar=barfoo\n", "bar"); 233 test = np_extract_ntpvar("foo=bar,bar=foo,foobar=barfoo\n", "bar");
236 ok(test && !strcmp(test, "foo"), "2nd test as expected"); 234 ok(test && !strcmp(test, "foo"), "2nd test as expected");
237 free(test); 235 free(test);
238 236
239 test=np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foobar"); 237 test = np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foobar");
240 ok(test && !strcmp(test, "barfoo"), "3rd test as expected"); 238 ok(test && !strcmp(test, "barfoo"), "3rd test as expected");
241 free(test); 239 free(test);
242 240
243 test=np_extract_ntpvar("foo=bar\n", "foo"); 241 test = np_extract_ntpvar("foo=bar\n", "foo");
244 ok(test && !strcmp(test, "bar"), "Single test as expected"); 242 ok(test && !strcmp(test, "bar"), "Single test as expected");
245 free(test); 243 free(test);
246 244
247 test=np_extract_ntpvar("foo=bar, bar=foo, foobar=barfooi\n", "abcd"); 245 test = np_extract_ntpvar("foo=bar, bar=foo, foobar=barfooi\n", "abcd");
248 ok(!test, "Key not found 1"); 246 ok(!test, "Key not found 1");
249 247
250 test=np_extract_ntpvar("foo=bar\n", "abcd"); 248 test = np_extract_ntpvar("foo=bar\n", "abcd");
251 ok(!test, "Key not found 2"); 249 ok(!test, "Key not found 2");
252 250
253 test=np_extract_ntpvar("foo=bar=foobar", "foo"); 251 test = np_extract_ntpvar("foo=bar=foobar", "foo");
254 ok(test && !strcmp(test, "bar=foobar"), "Strange string 1"); 252 ok(test && !strcmp(test, "bar=foobar"), "Strange string 1");
255 free(test); 253 free(test);
256 254
257 test=np_extract_ntpvar("foo", "foo"); 255 test = np_extract_ntpvar("foo", "foo");
258 ok(!test, "Malformed string 1"); 256 ok(!test, "Malformed string 1");
259 257
260 test=np_extract_ntpvar("foo,", "foo"); 258 test = np_extract_ntpvar("foo,", "foo");
261 ok(!test, "Malformed string 2"); 259 ok(!test, "Malformed string 2");
262 260
263 test=np_extract_ntpvar("foo=", "foo"); 261 test = np_extract_ntpvar("foo=", "foo");
264 ok(!test, "Malformed string 3"); 262 ok(!test, "Malformed string 3");
265 263
266 test=np_extract_ntpvar("foo=,bar=foo", "foo"); 264 test = np_extract_ntpvar("foo=,bar=foo", "foo");
267 ok(!test, "Malformed string 4"); 265 ok(!test, "Malformed string 4");
268 266
269 test=np_extract_ntpvar(",foo", "foo"); 267 test = np_extract_ntpvar(",foo", "foo");
270 ok(!test, "Malformed string 5"); 268 ok(!test, "Malformed string 5");
271 269
272 test=np_extract_ntpvar("=foo", "foo"); 270 test = np_extract_ntpvar("=foo", "foo");
273 ok(!test, "Malformed string 6"); 271 ok(!test, "Malformed string 6");
274 272
275 test=np_extract_ntpvar("=foo,", "foo"); 273 test = np_extract_ntpvar("=foo,", "foo");
276 ok(!test, "Malformed string 7"); 274 ok(!test, "Malformed string 7");
277 275
278 test=np_extract_ntpvar(",,,", "foo"); 276 test = np_extract_ntpvar(",,,", "foo");
279 ok(!test, "Malformed string 8"); 277 ok(!test, "Malformed string 8");
280 278
281 test=np_extract_ntpvar("===", "foo"); 279 test = np_extract_ntpvar("===", "foo");
282 ok(!test, "Malformed string 9"); 280 ok(!test, "Malformed string 9");
283 281
284 test=np_extract_ntpvar(",=,=,", "foo"); 282 test = np_extract_ntpvar(",=,=,", "foo");
285 ok(!test, "Malformed string 10"); 283 ok(!test, "Malformed string 10");
286 284
287 test=np_extract_ntpvar("=,=,=", "foo"); 285 test = np_extract_ntpvar("=,=,=", "foo");
288 ok(!test, "Malformed string 11"); 286 ok(!test, "Malformed string 11");
289 287
290 test=np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "foo"); 288 test = np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "foo");
291 ok(test && !strcmp(test, "bar"), "Random spaces and newlines 1"); 289 ok(test && !strcmp(test, "bar"), "Random spaces and newlines 1");
292 free(test); 290 free(test);
293 291
294 test=np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "bar"); 292 test = np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "bar");
295 ok(test && !strcmp(test, "foo"), "Random spaces and newlines 2"); 293 ok(test && !strcmp(test, "foo"), "Random spaces and newlines 2");
296 free(test); 294 free(test);
297 295
298 test=np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "foobar"); 296 test = np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "foobar");
299 ok(test && !strcmp(test, "barfoo"), "Random spaces and newlines 3"); 297 ok(test && !strcmp(test, "barfoo"), "Random spaces and newlines 3");
300 free(test); 298 free(test);
301 299
302 test=np_extract_ntpvar(" foo=bar ,\n bar\n \n= \n foo\n , foobar=barfoo \n ", "bar"); 300 test = np_extract_ntpvar(" foo=bar ,\n bar\n \n= \n foo\n , foobar=barfoo \n ", "bar");
303 ok(test && !strcmp(test, "foo"), "Random spaces and newlines 4"); 301 ok(test && !strcmp(test, "foo"), "Random spaces and newlines 4");
304 free(test); 302 free(test);
305 303
306 test=np_extract_ntpvar("", "foo"); 304 test = np_extract_ntpvar("", "foo");
307 ok(!test, "Empty string return NULL"); 305 ok(!test, "Empty string return NULL");
308 306
309
310 /* This is the result of running ./test_utils */ 307 /* This is the result of running ./test_utils */
311 temp_string = (char *) _np_state_generate_key(); 308 temp_string = (char *)_np_state_generate_key();
312 ok(!strcmp(temp_string, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got hash with exe and no parameters" ) || 309 ok(!strcmp(temp_string, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got hash with exe and no parameters") ||
313 diag( "You are probably running in wrong directory. Must run as ./test_utils" ); 310 diag("You are probably running in wrong directory. Must run as ./test_utils");
314
315 311
316 this_monitoring_plugin->argc=4; 312 this_monitoring_plugin->argc = 4;
317 this_monitoring_plugin->argv[0] = "./test_utils"; 313 this_monitoring_plugin->argv[0] = "./test_utils";
318 this_monitoring_plugin->argv[1] = "here"; 314 this_monitoring_plugin->argv[1] = "here";
319 this_monitoring_plugin->argv[2] = "--and"; 315 this_monitoring_plugin->argv[2] = "--and";
320 this_monitoring_plugin->argv[3] = "now"; 316 this_monitoring_plugin->argv[3] = "now";
321 temp_string = (char *) _np_state_generate_key(); 317 temp_string = (char *)_np_state_generate_key();
322 ok(!strcmp(temp_string, "bd72da9f78ff1419fad921ea5e43ce56508aef6c"), "Got based on expected argv" ); 318 ok(!strcmp(temp_string, "bd72da9f78ff1419fad921ea5e43ce56508aef6c"), "Got based on expected argv");
323 319
324 unsetenv("MP_STATE_PATH"); 320 unsetenv("MP_STATE_PATH");
325 temp_string = (char *) _np_state_calculate_location_prefix(); 321 temp_string = (char *)_np_state_calculate_location_prefix();
326 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory" ); 322 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory");
327 323
328 setenv("MP_STATE_PATH", "", 1); 324 setenv("MP_STATE_PATH", "", 1);
329 temp_string = (char *) _np_state_calculate_location_prefix(); 325 temp_string = (char *)_np_state_calculate_location_prefix();
330 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory even with empty string" ); 326 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory even with empty string");
331 327
332 setenv("MP_STATE_PATH", "/usr/local/nagios/var", 1); 328 setenv("MP_STATE_PATH", "/usr/local/nagios/var", 1);
333 temp_string = (char *) _np_state_calculate_location_prefix(); 329 temp_string = (char *)_np_state_calculate_location_prefix();
334 ok(!strcmp(temp_string, "/usr/local/nagios/var"), "Got default directory" ); 330 ok(!strcmp(temp_string, "/usr/local/nagios/var"), "Got default directory");
335
336 331
332 ok(temp_state_key == NULL, "temp_state_key initially empty");
337 333
338 ok(temp_state_key==NULL, "temp_state_key initially empty"); 334 this_monitoring_plugin->argc = 1;
339
340 this_monitoring_plugin->argc=1;
341 this_monitoring_plugin->argv[0] = "./test_utils"; 335 this_monitoring_plugin->argv[0] = "./test_utils";
342 np_enable_state(NULL, 51); 336 np_enable_state(NULL, 51);
343 temp_state_key = this_monitoring_plugin->state; 337 temp_state_key = this_monitoring_plugin->state;
344 ok( !strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name" ); 338 ok(!strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name");
345 ok( !strcmp(temp_state_key->name, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got generated filename" ); 339 ok(!strcmp(temp_state_key->name, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got generated filename");
346
347 340
348 np_enable_state("allowedchars_in_keyname", 77); 341 np_enable_state("allowedchars_in_keyname", 77);
349 temp_state_key = this_monitoring_plugin->state; 342 temp_state_key = this_monitoring_plugin->state;
350 sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/allowedchars_in_keyname", (unsigned long)geteuid()); 343 sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/allowedchars_in_keyname", (unsigned long)geteuid());
351 ok( !strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name" ); 344 ok(!strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name");
352 ok( !strcmp(temp_state_key->name, "allowedchars_in_keyname"), "Got key name with valid chars" ); 345 ok(!strcmp(temp_state_key->name, "allowedchars_in_keyname"), "Got key name with valid chars");
353 ok( !strcmp(temp_state_key->_filename, state_path), "Got internal filename" ); 346 ok(!strcmp(temp_state_key->_filename, state_path), "Got internal filename");
354
355 347
356 /* Don't do this test just yet. Will die */ 348 /* Don't do this test just yet. Will die */
357 /* 349 /*
@@ -363,73 +355,65 @@ main (int argc, char **argv)
363 np_enable_state("funnykeyname", 54); 355 np_enable_state("funnykeyname", 54);
364 temp_state_key = this_monitoring_plugin->state; 356 temp_state_key = this_monitoring_plugin->state;
365 sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/funnykeyname", (unsigned long)geteuid()); 357 sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/funnykeyname", (unsigned long)geteuid());
366 ok( !strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name" ); 358 ok(!strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name");
367 ok( !strcmp(temp_state_key->name, "funnykeyname"), "Got key name" ); 359 ok(!strcmp(temp_state_key->name, "funnykeyname"), "Got key name");
368 360
369 361 ok(!strcmp(temp_state_key->_filename, state_path), "Got internal filename");
370 362 ok(temp_state_key->data_version == 54, "Version set");
371 ok( !strcmp(temp_state_key->_filename, state_path), "Got internal filename" );
372 ok( temp_state_key->data_version==54, "Version set" );
373 363
374 temp_state_data = np_state_read(); 364 temp_state_data = np_state_read();
375 ok( temp_state_data==NULL, "Got no state data as file does not exist" ); 365 ok(temp_state_data == NULL, "Got no state data as file does not exist");
376
377 366
378/* 367 /*
379 temp_fp = fopen("var/statefile", "r"); 368 temp_fp = fopen("var/statefile", "r");
380 if (temp_fp==NULL) 369 if (temp_fp==NULL)
381 printf("Error opening. errno=%d\n", errno); 370 printf("Error opening. errno=%d\n", errno);
382 printf("temp_fp=%s\n", temp_fp); 371 printf("temp_fp=%s\n", temp_fp);
383 ok( _np_state_read_file(temp_fp) == true, "Can read state file" ); 372 ok( _np_state_read_file(temp_fp) == true, "Can read state file" );
384 fclose(temp_fp); 373 fclose(temp_fp);
385*/ 374 */
386 375
387 temp_state_key->_filename="var/statefile"; 376 temp_state_key->_filename = "var/statefile";
388 temp_state_data = np_state_read(); 377 temp_state_data = np_state_read();
389 ok( this_monitoring_plugin->state->state_data!=NULL, "Got state data now" ) || diag("Are you running in right directory? Will get coredump next if not"); 378 ok(this_monitoring_plugin->state->state_data != NULL, "Got state data now") ||
390 ok( this_monitoring_plugin->state->state_data->time==1234567890, "Got time" ); 379 diag("Are you running in right directory? Will get coredump next if not");
391 ok( !strcmp((char *)this_monitoring_plugin->state->state_data->data, "String to read"), "Data as expected" ); 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");
392 382
393 temp_state_key->data_version=53; 383 temp_state_key->data_version = 53;
394 temp_state_data = np_state_read(); 384 temp_state_data = np_state_read();
395 ok( temp_state_data==NULL, "Older data version gives NULL" ); 385 ok(temp_state_data == NULL, "Older data version gives NULL");
396 temp_state_key->data_version=54; 386 temp_state_key->data_version = 54;
397 387
398 temp_state_key->_filename="var/nonexistent"; 388 temp_state_key->_filename = "var/nonexistent";
399 temp_state_data = np_state_read(); 389 temp_state_data = np_state_read();
400 ok( temp_state_data==NULL, "Missing file gives NULL" ); 390 ok(temp_state_data == NULL, "Missing file gives NULL");
401 ok( this_monitoring_plugin->state->state_data==NULL, "No state information" ); 391 ok(this_monitoring_plugin->state->state_data == NULL, "No state information");
402 392
403 temp_state_key->_filename="var/oldformat"; 393 temp_state_key->_filename = "var/oldformat";
404 temp_state_data = np_state_read(); 394 temp_state_data = np_state_read();
405 ok( temp_state_data==NULL, "Old file format gives NULL" ); 395 ok(temp_state_data == NULL, "Old file format gives NULL");
406 396
407 temp_state_key->_filename="var/baddate"; 397 temp_state_key->_filename = "var/baddate";
408 temp_state_data = np_state_read(); 398 temp_state_data = np_state_read();
409 ok( temp_state_data==NULL, "Bad date gives NULL" ); 399 ok(temp_state_data == NULL, "Bad date gives NULL");
410 400
411 temp_state_key->_filename="var/missingdataline"; 401 temp_state_key->_filename = "var/missingdataline";
412 temp_state_data = np_state_read(); 402 temp_state_data = np_state_read();
413 ok( temp_state_data==NULL, "Missing data line gives NULL" ); 403 ok(temp_state_data == NULL, "Missing data line gives NULL");
414
415
416
417 404
418 unlink("var/generated"); 405 unlink("var/generated");
419 temp_state_key->_filename="var/generated"; 406 temp_state_key->_filename = "var/generated";
420 current_time=1234567890; 407 current_time = 1234567890;
421 np_state_write_string(current_time, "String to read"); 408 np_state_write_string(current_time, "String to read");
422 ok(system("cmp var/generated var/statefile")==0, "Generated file same as expected"); 409 ok(system("cmp var/generated var/statefile") == 0, "Generated file same as expected");
423
424
425
426 410
427 unlink("var/generated_directory/statefile"); 411 unlink("var/generated_directory/statefile");
428 unlink("var/generated_directory"); 412 unlink("var/generated_directory");
429 temp_state_key->_filename="var/generated_directory/statefile"; 413 temp_state_key->_filename = "var/generated_directory/statefile";
430 current_time=1234567890; 414 current_time = 1234567890;
431 np_state_write_string(current_time, "String to read"); 415 np_state_write_string(current_time, "String to read");
432 ok(system("cmp var/generated_directory/statefile var/statefile")==0, "Have created directory"); 416 ok(system("cmp var/generated_directory/statefile var/statefile") == 0, "Have created directory");
433 417
434 /* This test to check cannot write to dir - can't automate yet */ 418 /* This test to check cannot write to dir - can't automate yet */
435 /* 419 /*
@@ -438,15 +422,13 @@ main (int argc, char **argv)
438 np_state_write_string(current_time, "String to read"); 422 np_state_write_string(current_time, "String to read");
439 */ 423 */
440 424
441 425 temp_state_key->_filename = "var/generated";
442 temp_state_key->_filename="var/generated";
443 time(&current_time); 426 time(&current_time);
444 np_state_write_string(0, "String to read"); 427 np_state_write_string(0, "String to read");
445 temp_state_data = np_state_read(); 428 temp_state_data = np_state_read();
446 /* Check time is set to current_time */ 429 /* Check time is set to current_time */
447 ok(system("cmp var/generated var/statefile > /dev/null")!=0, "Generated file should be different this time"); 430 ok(system("cmp var/generated var/statefile > /dev/null") != 0, "Generated file should be different this time");
448 ok(this_monitoring_plugin->state->state_data->time-current_time<=1, "Has time generated from current time"); 431 ok(this_monitoring_plugin->state->state_data->time - current_time <= 1, "Has time generated from current time");
449
450 432
451 /* Don't know how to automatically test this. Need to be able to redefine die and catch the error */ 433 /* Don't know how to automatically test this. Need to be able to redefine die and catch the error */
452 /* 434 /*
@@ -454,23 +436,16 @@ main (int argc, char **argv)
454 np_state_write_string(0, "Bad file"); 436 np_state_write_string(0, "Bad file");
455 */ 437 */
456 438
457
458 np_cleanup(); 439 np_cleanup();
459 440
460 ok(this_monitoring_plugin==NULL, "Free'd this_monitoring_plugin"); 441 ok(this_monitoring_plugin == NULL, "Free'd this_monitoring_plugin");
461 442
462 ok(mp_suid() == false, "Test aren't suid"); 443 ok(mp_suid() == false, "Test aren't suid");
463 444
464 /* base states with random case */ 445 /* base states with random case */
465 char *states[] = { 446 char *states[] = {"Ok", "wArnINg", "cRiTIcaL", "UnKNoWN", NULL};
466 "Ok", 447
467 "wArnINg", 448 for (i = 0; states[i] != NULL; i++) {
468 "cRiTIcaL",
469 "UnKNoWN",
470 NULL
471 };
472
473 for (i=0; states[i]!=NULL; i++) {
474 /* out of the random case states, create the lower and upper versions + numeric string one */ 449 /* out of the random case states, create the lower and upper versions + numeric string one */
475 char *statelower = strdup(states[i]); 450 char *statelower = strdup(states[i]);
476 char *stateupper = strdup(states[i]); 451 char *stateupper = strdup(states[i]);
@@ -488,23 +463,23 @@ main (int argc, char **argv)
488 char testname[64] = "Translate state string: "; 463 char testname[64] = "Translate state string: ";
489 int tlen = strlen(testname); 464 int tlen = strlen(testname);
490 465
491 strcpy(testname+tlen, states[i]); 466 strcpy(testname + tlen, states[i]);
492 ok(i==mp_translate_state(states[i]), testname); 467 ok(i == mp_translate_state(states[i]), testname);
493 468
494 strcpy(testname+tlen, statelower); 469 strcpy(testname + tlen, statelower);
495 ok(i==mp_translate_state(statelower), testname); 470 ok(i == mp_translate_state(statelower), testname);
496 471
497 strcpy(testname+tlen, stateupper); 472 strcpy(testname + tlen, stateupper);
498 ok(i==mp_translate_state(stateupper), testname); 473 ok(i == mp_translate_state(stateupper), testname);
499 474
500 strcpy(testname+tlen, statenum); 475 strcpy(testname + tlen, statenum);
501 ok(i==mp_translate_state(statenum), testname); 476 ok(i == mp_translate_state(statenum), testname);
502 } 477 }
503 ok(ERROR==mp_translate_state("warningfewgw"), "Translate state string with garbage"); 478 ok(ERROR == mp_translate_state("warningfewgw"), "Translate state string with garbage");
504 ok(ERROR==mp_translate_state("00"), "Translate state string: bad numeric string 1"); 479 ok(ERROR == mp_translate_state("00"), "Translate state string: bad numeric string 1");
505 ok(ERROR==mp_translate_state("01"), "Translate state string: bad numeric string 2"); 480 ok(ERROR == mp_translate_state("01"), "Translate state string: bad numeric string 2");
506 ok(ERROR==mp_translate_state("10"), "Translate state string: bad numeric string 3"); 481 ok(ERROR == mp_translate_state("10"), "Translate state string: bad numeric string 3");
507 ok(ERROR==mp_translate_state(""), "Translate state string: empty string"); 482 ok(ERROR == mp_translate_state(""), "Translate state string: empty string");
508 483
509 return exit_status(); 484 return exit_status();
510} 485}
diff --git a/lib/thresholds.c b/lib/thresholds.c
new file mode 100644
index 00000000..de2b9315
--- /dev/null
+++ b/lib/thresholds.c
@@ -0,0 +1,71 @@
1#include "./thresholds.h"
2#include "./utils_base.h"
3#include "perfdata.h"
4
5#include <stddef.h>
6
7mp_thresholds mp_thresholds_init() {
8 mp_thresholds tmp = {
9 .critical = {},
10 .critical_is_set = false,
11 .warning = {},
12 .warning_is_set = false,
13 };
14 return tmp;
15}
16
17char *fmt_threshold_warning(const thresholds th) {
18 if (th.warning == NULL) {
19 return "";
20 }
21
22 return fmt_range(*th.warning);
23}
24
25char *fmt_threshold_critical(const thresholds th) {
26 if (th.critical == NULL) {
27 return "";
28 }
29 return fmt_range(*th.critical);
30}
31
32mp_perfdata mp_pd_set_thresholds(mp_perfdata perfdata, mp_thresholds threshold) {
33 if (threshold.critical_is_set) {
34 perfdata.crit = threshold.critical;
35 perfdata.crit_present = true;
36 }
37
38 if (threshold.warning_is_set) {
39 perfdata.warn = threshold.warning;
40 perfdata.warn_present = true;
41 }
42
43 return perfdata;
44}
45
46mp_state_enum mp_get_pd_status(mp_perfdata perfdata) {
47 if (perfdata.crit_present) {
48 if (mp_check_range(perfdata.value, perfdata.crit)) {
49 return STATE_CRITICAL;
50 }
51 }
52 if (perfdata.warn_present) {
53 if (mp_check_range(perfdata.value, perfdata.warn)) {
54 return STATE_WARNING;
55 }
56 }
57
58 return STATE_OK;
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
new file mode 100644
index 00000000..5f9f9247
--- /dev/null
+++ b/lib/thresholds.h
@@ -0,0 +1,31 @@
1#pragma once
2
3#include "./perfdata.h"
4#include "states.h"
5
6/*
7 * Old threshold type using the old range type
8 */
9typedef struct thresholds_struct {
10 range *warning;
11 range *critical;
12} thresholds;
13
14typedef struct mp_thresholds_struct {
15 bool warning_is_set;
16 mp_range warning;
17 bool critical_is_set;
18 mp_range critical;
19} mp_thresholds;
20
21mp_thresholds mp_thresholds_init(void);
22
23mp_perfdata mp_pd_set_thresholds(mp_perfdata /* pd */, mp_thresholds /* th */);
24
25mp_state_enum mp_get_pd_status(mp_perfdata /* pd */);
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
30char *fmt_threshold_warning(thresholds th);
31char *fmt_threshold_critical(thresholds th);
diff --git a/lib/utils_base.c b/lib/utils_base.c
index f8592f41..c49a473f 100644
--- a/lib/utils_base.c
+++ b/lib/utils_base.c
@@ -1,28 +1,28 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* utils_base.c 3 * utils_base.c
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2006 Monitoring Plugins Development Team 6 * Copyright (c) 2006 - 2024 Monitoring Plugins Development Team
7* 7 *
8* Library of useful functions for plugins 8 * Library of useful functions for plugins
9* 9 *
10* 10 *
11* This program is free software: you can redistribute it and/or modify 11 * This program is free software: you can redistribute it and/or modify
12* it under the terms of the GNU General Public License as published by 12 * it under the terms of the GNU General Public License as published by
13* the Free Software Foundation, either version 3 of the License, or 13 * the Free Software Foundation, either version 3 of the License, or
14* (at your option) any later version. 14 * (at your option) any later version.
15* 15 *
16* This program is distributed in the hope that it will be useful, 16 * This program is distributed in the hope that it will be useful,
17* but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19* GNU General Public License for more details. 19 * GNU General Public License for more details.
20* 20 *
21* You should have received a copy of the GNU General Public License 21 * You should have received a copy of the GNU General Public License
22* along with this program. If not, see <http://www.gnu.org/licenses/>. 22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23* 23 *
24* 24 *
25*****************************************************************************/ 25 *****************************************************************************/
26 26
27#include "../plugins/common.h" 27#include "../plugins/common.h"
28#include <stdarg.h> 28#include <stdarg.h>
@@ -33,43 +33,49 @@
33#include <unistd.h> 33#include <unistd.h>
34#include <sys/types.h> 34#include <sys/types.h>
35 35
36#define np_free(ptr) { if(ptr) { free(ptr); ptr = NULL; } } 36#define np_free(ptr) \
37 { \
38 if (ptr) { \
39 free(ptr); \
40 ptr = NULL; \
41 } \
42 }
37 43
38monitoring_plugin *this_monitoring_plugin=NULL; 44monitoring_plugin *this_monitoring_plugin = NULL;
39 45
40int timeout_state = STATE_CRITICAL; 46int timeout_state = STATE_CRITICAL;
41unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT; 47unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT;
42 48
43bool _np_state_read_file(FILE *); 49bool _np_state_read_file(FILE *);
44 50
45void np_init( char *plugin_name, int argc, char **argv ) { 51void np_init(char *plugin_name, int argc, char **argv) {
46 if (this_monitoring_plugin==NULL) { 52 if (this_monitoring_plugin == NULL) {
47 this_monitoring_plugin = calloc(1, sizeof(monitoring_plugin)); 53 this_monitoring_plugin = calloc(1, sizeof(monitoring_plugin));
48 if (this_monitoring_plugin==NULL) { 54 if (this_monitoring_plugin == NULL) {
49 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 55 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
50 strerror(errno));
51 } 56 }
52 this_monitoring_plugin->plugin_name = strdup(plugin_name); 57 this_monitoring_plugin->plugin_name = strdup(plugin_name);
53 if (this_monitoring_plugin->plugin_name==NULL) 58 if (this_monitoring_plugin->plugin_name == NULL) {
54 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); 59 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
60 }
55 this_monitoring_plugin->argc = argc; 61 this_monitoring_plugin->argc = argc;
56 this_monitoring_plugin->argv = argv; 62 this_monitoring_plugin->argv = argv;
57 } 63 }
58} 64}
59 65
60void np_set_args( int argc, char **argv ) { 66void np_set_args(int argc, char **argv) {
61 if (this_monitoring_plugin==NULL) 67 if (this_monitoring_plugin == NULL) {
62 die(STATE_UNKNOWN, _("This requires np_init to be called")); 68 die(STATE_UNKNOWN, _("This requires np_init to be called"));
69 }
63 70
64 this_monitoring_plugin->argc = argc; 71 this_monitoring_plugin->argc = argc;
65 this_monitoring_plugin->argv = argv; 72 this_monitoring_plugin->argv = argv;
66} 73}
67 74
68 75void np_cleanup(void) {
69void np_cleanup() { 76 if (this_monitoring_plugin != NULL) {
70 if (this_monitoring_plugin!=NULL) { 77 if (this_monitoring_plugin->state != NULL) {
71 if(this_monitoring_plugin->state!=NULL) { 78 if (this_monitoring_plugin->state->state_data) {
72 if(this_monitoring_plugin->state->state_data) {
73 np_free(this_monitoring_plugin->state->state_data->data); 79 np_free(this_monitoring_plugin->state->state_data->data);
74 np_free(this_monitoring_plugin->state->state_data); 80 np_free(this_monitoring_plugin->state->state_data);
75 } 81 }
@@ -79,48 +85,43 @@ void np_cleanup() {
79 np_free(this_monitoring_plugin->plugin_name); 85 np_free(this_monitoring_plugin->plugin_name);
80 np_free(this_monitoring_plugin); 86 np_free(this_monitoring_plugin);
81 } 87 }
82 this_monitoring_plugin=NULL; 88 this_monitoring_plugin = NULL;
83} 89}
84 90
85/* Hidden function to get a pointer to this_monitoring_plugin for testing */ 91/* Hidden function to get a pointer to this_monitoring_plugin for testing */
86void _get_monitoring_plugin( monitoring_plugin **pointer ){ 92void _get_monitoring_plugin(monitoring_plugin **pointer) { *pointer = this_monitoring_plugin; }
87 *pointer = this_monitoring_plugin;
88}
89 93
90void 94void die(int result, const char *fmt, ...) {
91die (int result, const char *fmt, ...) 95 if (fmt != NULL) {
92{
93 if(fmt!=NULL) {
94 va_list ap; 96 va_list ap;
95 va_start (ap, fmt); 97 va_start(ap, fmt);
96 vprintf (fmt, ap); 98 vprintf(fmt, ap);
97 va_end (ap); 99 va_end(ap);
98 } 100 }
99 101
100 if(this_monitoring_plugin!=NULL) { 102 if (this_monitoring_plugin != NULL) {
101 np_cleanup(); 103 np_cleanup();
102 } 104 }
103 exit (result); 105 exit(result);
104} 106}
105 107
106void set_range_start (range *this, double value) { 108void set_range_start(range *this, double value) {
107 this->start = value; 109 this->start = value;
108 this->start_infinity = false; 110 this->start_infinity = false;
109} 111}
110 112
111void set_range_end (range *this, double value) { 113void set_range_end(range *this, double value) {
112 this->end = value; 114 this->end = value;
113 this->end_infinity = false; 115 this->end_infinity = false;
114} 116}
115 117
116range 118range *parse_range_string(char *str) {
117*parse_range_string (char *str) {
118 range *temp_range; 119 range *temp_range;
119 double start; 120 double start;
120 double end; 121 double end;
121 char *end_str; 122 char *end_str;
122 123
123 temp_range = (range *) calloc(1, sizeof(range)); 124 temp_range = (range *)calloc(1, sizeof(range));
124 125
125 /* Set defaults */ 126 /* Set defaults */
126 temp_range->start = 0; 127 temp_range->start = 0;
@@ -140,10 +141,10 @@ range
140 if (str[0] == '~') { 141 if (str[0] == '~') {
141 temp_range->start_infinity = true; 142 temp_range->start_infinity = true;
142 } else { 143 } else {
143 start = strtod(str, NULL); /* Will stop at the ':' */ 144 start = strtod(str, NULL); /* Will stop at the ':' */
144 set_range_start(temp_range, start); 145 set_range_start(temp_range, start);
145 } 146 }
146 end_str++; /* Move past the ':' */ 147 end_str++; /* Move past the ':' */
147 } else { 148 } else {
148 end_str = str; 149 end_str = str;
149 } 150 }
@@ -152,9 +153,7 @@ range
152 set_range_end(temp_range, end); 153 set_range_end(temp_range, end);
153 } 154 }
154 155
155 if (temp_range->start_infinity == true || 156 if (temp_range->start_infinity == true || temp_range->end_infinity == true || temp_range->start <= temp_range->end) {
156 temp_range->end_infinity == true ||
157 temp_range->start <= temp_range->end) {
158 return temp_range; 157 return temp_range;
159 } 158 }
160 free(temp_range); 159 free(temp_range);
@@ -162,14 +161,12 @@ range
162} 161}
163 162
164/* returns 0 if okay, otherwise 1 */ 163/* returns 0 if okay, otherwise 1 */
165int 164int _set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string) {
166_set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string)
167{
168 thresholds *temp_thresholds = NULL; 165 thresholds *temp_thresholds = NULL;
169 166
170 if ((temp_thresholds = calloc(1, sizeof(thresholds))) == NULL) 167 if ((temp_thresholds = calloc(1, sizeof(thresholds))) == NULL) {
171 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 168 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
172 strerror(errno)); 169 }
173 170
174 temp_thresholds->warning = NULL; 171 temp_thresholds->warning = NULL;
175 temp_thresholds->critical = NULL; 172 temp_thresholds->critical = NULL;
@@ -190,9 +187,7 @@ _set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_st
190 return 0; 187 return 0;
191} 188}
192 189
193void 190void set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string) {
194set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string)
195{
196 switch (_set_thresholds(my_thresholds, warn_string, critical_string)) { 191 switch (_set_thresholds(my_thresholds, warn_string, critical_string)) {
197 case 0: 192 case 0:
198 return; 193 return;
@@ -206,7 +201,7 @@ set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_str
206 201
207void print_thresholds(const char *threshold_name, thresholds *my_threshold) { 202void print_thresholds(const char *threshold_name, thresholds *my_threshold) {
208 printf("%s - ", threshold_name); 203 printf("%s - ", threshold_name);
209 if (! my_threshold) { 204 if (!my_threshold) {
210 printf("Threshold not set"); 205 printf("Threshold not set");
211 } else { 206 } else {
212 if (my_threshold->warning) { 207 if (my_threshold->warning) {
@@ -223,9 +218,36 @@ void print_thresholds(const char *threshold_name, thresholds *my_threshold) {
223 printf("\n"); 218 printf("\n");
224} 219}
225 220
221/* Returns true if alert should be raised based on the range, false otherwise */
222bool mp_check_range(const mp_perfdata_value value, const mp_range my_range) {
223 bool is_inside = false;
224
225 if (my_range.end_infinity == false && my_range.start_infinity == false) {
226 // range: .........|---inside---|...........
227 // value
228 is_inside = ((cmp_perfdata_value(my_range.start, value) < 1) && (cmp_perfdata_value(value, my_range.end) <= 0));
229 } else if (my_range.start_infinity == false && my_range.end_infinity == true) {
230 // range: .........|---inside---------
231 // value
232 is_inside = (cmp_perfdata_value(my_range.start, value) < 0);
233 } else if (my_range.start_infinity == true && my_range.end_infinity == false) {
234 // range: -inside--------|....................
235 // value
236 is_inside = (cmp_perfdata_value(value, my_range.end) == -1);
237 } else {
238 // range from -inf to inf, so always inside
239 is_inside = true;
240 }
241
242 if ((is_inside && my_range.alert_on_inside_range == INSIDE) || (!is_inside && my_range.alert_on_inside_range == OUTSIDE)) {
243 return true;
244 }
245
246 return false;
247}
248
226/* Returns true if alert should be raised based on the range */ 249/* Returns true if alert should be raised based on the range */
227bool check_range(double value, range *my_range) 250bool check_range(double value, range *my_range) {
228{
229 bool no = false; 251 bool no = false;
230 bool yes = true; 252 bool yes = true;
231 253
@@ -237,30 +259,28 @@ bool check_range(double value, range *my_range)
237 if (my_range->end_infinity == false && my_range->start_infinity == false) { 259 if (my_range->end_infinity == false && my_range->start_infinity == false) {
238 if ((my_range->start <= value) && (value <= my_range->end)) { 260 if ((my_range->start <= value) && (value <= my_range->end)) {
239 return no; 261 return no;
240 } else {
241 return yes;
242 } 262 }
243 } else if (my_range->start_infinity == false && my_range->end_infinity == true) { 263 return yes;
264 }
265
266 if (my_range->start_infinity == false && my_range->end_infinity == true) {
244 if (my_range->start <= value) { 267 if (my_range->start <= value) {
245 return no; 268 return no;
246 } else {
247 return yes;
248 } 269 }
249 } else if (my_range->start_infinity == true && my_range->end_infinity == false) { 270 return yes;
271 }
272
273 if (my_range->start_infinity == true && my_range->end_infinity == false) {
250 if (value <= my_range->end) { 274 if (value <= my_range->end) {
251 return no; 275 return no;
252 } else {
253 return yes;
254 } 276 }
255 } else { 277 return yes;
256 return no;
257 } 278 }
279 return no;
258} 280}
259 281
260/* Returns status */ 282/* Returns status */
261int 283int get_status(double value, thresholds *my_thresholds) {
262get_status(double value, thresholds *my_thresholds)
263{
264 if (my_thresholds->critical != NULL) { 284 if (my_thresholds->critical != NULL) {
265 if (check_range(value, my_thresholds->critical) == true) { 285 if (check_range(value, my_thresholds->critical) == true) {
266 return STATE_CRITICAL; 286 return STATE_CRITICAL;
@@ -274,27 +294,28 @@ get_status(double value, thresholds *my_thresholds)
274 return STATE_OK; 294 return STATE_OK;
275} 295}
276 296
277char *np_escaped_string (const char *string) { 297char *np_escaped_string(const char *string) {
278 char *data; 298 char *data;
279 int i, j=0; 299 int i;
300 int j = 0;
280 data = strdup(string); 301 data = strdup(string);
281 for (i=0; data[i]; i++) { 302 for (i = 0; data[i]; i++) {
282 if (data[i] == '\\') { 303 if (data[i] == '\\') {
283 switch(data[++i]) { 304 switch (data[++i]) {
284 case 'n': 305 case 'n':
285 data[j++] = '\n'; 306 data[j++] = '\n';
286 break; 307 break;
287 case 'r': 308 case 'r':
288 data[j++] = '\r'; 309 data[j++] = '\r';
289 break; 310 break;
290 case 't': 311 case 't':
291 data[j++] = '\t'; 312 data[j++] = '\t';
292 break; 313 break;
293 case '\\': 314 case '\\':
294 data[j++] = '\\'; 315 data[j++] = '\\';
295 break; 316 break;
296 default: 317 default:
297 data[j++] = data[i]; 318 data[j++] = data[i];
298 } 319 }
299 } else { 320 } else {
300 data[j++] = data[i]; 321 data[j++] = data[i];
@@ -313,33 +334,41 @@ int np_check_if_root(void) { return (geteuid() == 0); }
313 * data strings. 334 * data strings.
314 */ 335 */
315char *np_extract_value(const char *varlist, const char *name, char sep) { 336char *np_extract_value(const char *varlist, const char *name, char sep) {
316 char *tmp=NULL, *value=NULL; 337 char *tmp = NULL;
338 char *value = NULL;
317 int i; 339 int i;
318 340
319 while (1) { 341 while (1) {
320 /* Strip any leading space */ 342 /* Strip any leading space */
321 for (; isspace(varlist[0]); varlist++); 343 for (; isspace(varlist[0]); varlist++)
344 ;
322 345
323 if (strncmp(name, varlist, strlen(name)) == 0) { 346 if (strncmp(name, varlist, strlen(name)) == 0) {
324 varlist += strlen(name); 347 varlist += strlen(name);
325 /* strip trailing spaces */ 348 /* strip trailing spaces */
326 for (; isspace(varlist[0]); varlist++); 349 for (; isspace(varlist[0]); varlist++)
350 ;
327 351
328 if (varlist[0] == '=') { 352 if (varlist[0] == '=') {
329 /* We matched the key, go past the = sign */ 353 /* We matched the key, go past the = sign */
330 varlist++; 354 varlist++;
331 /* strip leading spaces */ 355 /* strip leading spaces */
332 for (; isspace(varlist[0]); varlist++); 356 for (; isspace(varlist[0]); varlist++)
357 ;
333 358
334 if ((tmp = index(varlist, sep))) { 359 if ((tmp = index(varlist, sep))) {
335 /* Value is delimited by a comma */ 360 /* Value is delimited by a comma */
336 if (tmp-varlist == 0) continue; 361 if (tmp - varlist == 0) {
337 value = (char *)calloc(1, tmp-varlist+1); 362 continue;
338 strncpy(value, varlist, tmp-varlist); 363 }
339 value[tmp-varlist] = '\0'; 364 value = (char *)calloc(1, tmp - varlist + 1);
365 strncpy(value, varlist, tmp - varlist);
366 value[tmp - varlist] = '\0';
340 } else { 367 } else {
341 /* Value is delimited by a \0 */ 368 /* Value is delimited by a \0 */
342 if (strlen(varlist) == 0) continue; 369 if (strlen(varlist) == 0) {
370 continue;
371 }
343 value = (char *)calloc(1, strlen(varlist) + 1); 372 value = (char *)calloc(1, strlen(varlist) + 1);
344 strncpy(value, varlist, strlen(varlist)); 373 strncpy(value, varlist, strlen(varlist));
345 value[strlen(varlist)] = '\0'; 374 value[strlen(varlist)] = '\0';
@@ -357,14 +386,16 @@ char *np_extract_value(const char *varlist, const char *name, char sep) {
357 } 386 }
358 387
359 /* Clean-up trailing spaces/newlines */ 388 /* Clean-up trailing spaces/newlines */
360 if (value) for (i=strlen(value)-1; isspace(value[i]); i--) value[i] = '\0'; 389 if (value) {
390 for (i = strlen(value) - 1; isspace(value[i]); i--) {
391 value[i] = '\0';
392 }
393 }
361 394
362 return value; 395 return value;
363} 396}
364 397
365const char * 398const char *state_text(int result) {
366state_text (int result)
367{
368 switch (result) { 399 switch (result) {
369 case STATE_OK: 400 case STATE_OK:
370 return "OK"; 401 return "OK";
@@ -383,15 +414,19 @@ state_text (int result)
383 * Read a string representing a state (ok, warning... or numeric: 0, 1) and 414 * Read a string representing a state (ok, warning... or numeric: 0, 1) and
384 * return the corresponding STATE_ value or ERROR) 415 * return the corresponding STATE_ value or ERROR)
385 */ 416 */
386int mp_translate_state (char *state_text) { 417int mp_translate_state(char *state_text) {
387 if (!strcasecmp(state_text,"OK") || !strcmp(state_text,"0")) 418 if (!strcasecmp(state_text, "OK") || !strcmp(state_text, "0")) {
388 return STATE_OK; 419 return STATE_OK;
389 if (!strcasecmp(state_text,"WARNING") || !strcmp(state_text,"1")) 420 }
421 if (!strcasecmp(state_text, "WARNING") || !strcmp(state_text, "1")) {
390 return STATE_WARNING; 422 return STATE_WARNING;
391 if (!strcasecmp(state_text,"CRITICAL") || !strcmp(state_text,"2")) 423 }
424 if (!strcasecmp(state_text, "CRITICAL") || !strcmp(state_text, "2")) {
392 return STATE_CRITICAL; 425 return STATE_CRITICAL;
393 if (!strcasecmp(state_text,"UNKNOWN") || !strcmp(state_text,"3")) 426 }
427 if (!strcasecmp(state_text, "UNKNOWN") || !strcmp(state_text, "3")) {
394 return STATE_UNKNOWN; 428 return STATE_UNKNOWN;
429 }
395 return ERROR; 430 return ERROR;
396} 431}
397 432
@@ -400,11 +435,11 @@ int mp_translate_state (char *state_text) {
400 * hopefully a unique key per service/plugin invocation. Use the extra-opts 435 * hopefully a unique key per service/plugin invocation. Use the extra-opts
401 * parse of argv, so that uniqueness in parameters are reflected there. 436 * parse of argv, so that uniqueness in parameters are reflected there.
402 */ 437 */
403char *_np_state_generate_key() { 438char *_np_state_generate_key(void) {
404 int i; 439 int i;
405 char **argv = this_monitoring_plugin->argv; 440 char **argv = this_monitoring_plugin->argv;
406 char keyname[41]; 441 char keyname[41];
407 char *p=NULL; 442 char *p = NULL;
408 443
409 unsigned char result[256]; 444 unsigned char result[256];
410 445
@@ -418,7 +453,7 @@ char *_np_state_generate_key() {
418 453
419 EVP_DigestInit(ctx, EVP_sha256()); 454 EVP_DigestInit(ctx, EVP_sha256());
420 455
421 for(i=0; i<this_monitoring_plugin->argc; i++) { 456 for (i = 0; i < this_monitoring_plugin->argc; i++) {
422 EVP_DigestUpdate(ctx, argv[i], strlen(argv[i])); 457 EVP_DigestUpdate(ctx, argv[i], strlen(argv[i]));
423 } 458 }
424 459
@@ -427,28 +462,28 @@ char *_np_state_generate_key() {
427 462
428 struct sha256_ctx ctx; 463 struct sha256_ctx ctx;
429 464
430 for(i=0; i<this_monitoring_plugin->argc; i++) { 465 for (i = 0; i < this_monitoring_plugin->argc; i++) {
431 sha256_process_bytes(argv[i], strlen(argv[i]), &ctx); 466 sha256_process_bytes(argv[i], strlen(argv[i]), &ctx);
432 } 467 }
433 468
434 sha256_finish_ctx(&ctx, result); 469 sha256_finish_ctx(&ctx, result);
435#endif // FOUNDOPENSSL 470#endif // FOUNDOPENSSL
436 471
437 for (i=0; i<20; ++i) { 472 for (i = 0; i < 20; ++i) {
438 sprintf(&keyname[2*i], "%02x", result[i]); 473 sprintf(&keyname[2 * i], "%02x", result[i]);
439 } 474 }
440 475
441 keyname[40]='\0'; 476 keyname[40] = '\0';
442 477
443 p = strdup(keyname); 478 p = strdup(keyname);
444 if(p==NULL) { 479 if (p == NULL) {
445 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); 480 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
446 } 481 }
447 return p; 482 return p;
448} 483}
449 484
450void _cleanup_state_data() { 485void _cleanup_state_data(void) {
451 if (this_monitoring_plugin->state->state_data!=NULL) { 486 if (this_monitoring_plugin->state->state_data != NULL) {
452 np_free(this_monitoring_plugin->state->state_data->data); 487 np_free(this_monitoring_plugin->state->state_data->data);
453 np_free(this_monitoring_plugin->state->state_data); 488 np_free(this_monitoring_plugin->state->state_data);
454 } 489 }
@@ -459,19 +494,21 @@ void _cleanup_state_data() {
459 * envvar NAGIOS_PLUGIN_STATE_DIRECTORY 494 * envvar NAGIOS_PLUGIN_STATE_DIRECTORY
460 * statically compiled shared state directory 495 * statically compiled shared state directory
461 */ 496 */
462char* _np_state_calculate_location_prefix(){ 497char *_np_state_calculate_location_prefix(void) {
463 char *env_dir; 498 char *env_dir;
464 499
465 /* Do not allow passing MP_STATE_PATH in setuid plugins 500 /* Do not allow passing MP_STATE_PATH in setuid plugins
466 * for security reasons */ 501 * for security reasons */
467 if (!mp_suid()) { 502 if (!mp_suid()) {
468 env_dir = getenv("MP_STATE_PATH"); 503 env_dir = getenv("MP_STATE_PATH");
469 if(env_dir && env_dir[0] != '\0') 504 if (env_dir && env_dir[0] != '\0') {
470 return env_dir; 505 return env_dir;
506 }
471 /* This is the former ENV, for backward-compatibility */ 507 /* This is the former ENV, for backward-compatibility */
472 env_dir = getenv("NAGIOS_PLUGIN_STATE_DIRECTORY"); 508 env_dir = getenv("NAGIOS_PLUGIN_STATE_DIRECTORY");
473 if(env_dir && env_dir[0] != '\0') 509 if (env_dir && env_dir[0] != '\0') {
474 return env_dir; 510 return env_dir;
511 }
475 } 512 }
476 513
477 return NP_STATE_DIR_PREFIX; 514 return NP_STATE_DIR_PREFIX;
@@ -486,46 +523,47 @@ void np_enable_state(char *keyname, int expected_data_version) {
486 state_key *this_state = NULL; 523 state_key *this_state = NULL;
487 char *temp_filename = NULL; 524 char *temp_filename = NULL;
488 char *temp_keyname = NULL; 525 char *temp_keyname = NULL;
489 char *p=NULL; 526 char *p = NULL;
490 int ret; 527 int ret;
491 528
492 if(this_monitoring_plugin==NULL) 529 if (this_monitoring_plugin == NULL) {
493 die(STATE_UNKNOWN, _("This requires np_init to be called")); 530 die(STATE_UNKNOWN, _("This requires np_init to be called"));
531 }
494 532
495 this_state = (state_key *) calloc(1, sizeof(state_key)); 533 this_state = (state_key *)calloc(1, sizeof(state_key));
496 if(this_state==NULL) 534 if (this_state == NULL) {
497 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 535 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
498 strerror(errno)); 536 }
499 537
500 if(keyname==NULL) { 538 if (keyname == NULL) {
501 temp_keyname = _np_state_generate_key(); 539 temp_keyname = _np_state_generate_key();
502 } else { 540 } else {
503 temp_keyname = strdup(keyname); 541 temp_keyname = strdup(keyname);
504 if(temp_keyname==NULL) 542 if (temp_keyname == NULL) {
505 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); 543 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
544 }
506 } 545 }
507 /* Die if invalid characters used for keyname */ 546 /* Die if invalid characters used for keyname */
508 p = temp_keyname; 547 p = temp_keyname;
509 while(*p!='\0') { 548 while (*p != '\0') {
510 if(! (isalnum(*p) || *p == '_')) { 549 if (!(isalnum(*p) || *p == '_')) {
511 die(STATE_UNKNOWN, _("Invalid character for keyname - only alphanumerics or '_'")); 550 die(STATE_UNKNOWN, _("Invalid character for keyname - only alphanumerics or '_'"));
512 } 551 }
513 p++; 552 p++;
514 } 553 }
515 this_state->name=temp_keyname; 554 this_state->name = temp_keyname;
516 this_state->plugin_name=this_monitoring_plugin->plugin_name; 555 this_state->plugin_name = this_monitoring_plugin->plugin_name;
517 this_state->data_version=expected_data_version; 556 this_state->data_version = expected_data_version;
518 this_state->state_data=NULL; 557 this_state->state_data = NULL;
519 558
520 /* Calculate filename */ 559 /* Calculate filename */
521 ret = asprintf(&temp_filename, "%s/%lu/%s/%s", 560 ret = asprintf(&temp_filename, "%s/%lu/%s/%s", _np_state_calculate_location_prefix(), (unsigned long)geteuid(),
522 _np_state_calculate_location_prefix(), (unsigned long)geteuid(), 561 this_monitoring_plugin->plugin_name, this_state->name);
523 this_monitoring_plugin->plugin_name, this_state->name); 562 if (ret < 0) {
524 if (ret < 0) 563 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
525 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 564 }
526 strerror(errno));
527 565
528 this_state->_filename=temp_filename; 566 this_state->_filename = temp_filename;
529 567
530 this_monitoring_plugin->state = this_state; 568 this_monitoring_plugin->state = this_state;
531} 569}
@@ -537,24 +575,25 @@ void np_enable_state(char *keyname, int expected_data_version) {
537 * If numerically lower, then return as no previous state. die with UNKNOWN 575 * If numerically lower, then return as no previous state. die with UNKNOWN
538 * if exceptional error. 576 * if exceptional error.
539 */ 577 */
540state_data *np_state_read() { 578state_data *np_state_read(void) {
541 state_data *this_state_data=NULL; 579 state_data *this_state_data = NULL;
542 FILE *statefile; 580 FILE *statefile;
543 bool rc = false; 581 bool rc = false;
544 582
545 if(this_monitoring_plugin==NULL) 583 if (this_monitoring_plugin == NULL) {
546 die(STATE_UNKNOWN, _("This requires np_init to be called")); 584 die(STATE_UNKNOWN, _("This requires np_init to be called"));
585 }
547 586
548 /* Open file. If this fails, no previous state found */ 587 /* Open file. If this fails, no previous state found */
549 statefile = fopen( this_monitoring_plugin->state->_filename, "r" ); 588 statefile = fopen(this_monitoring_plugin->state->_filename, "r");
550 if(statefile!=NULL) { 589 if (statefile != NULL) {
551 590
552 this_state_data = (state_data *) calloc(1, sizeof(state_data)); 591 this_state_data = (state_data *)calloc(1, sizeof(state_data));
553 if(this_state_data==NULL) 592 if (this_state_data == NULL) {
554 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 593 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
555 strerror(errno)); 594 }
556 595
557 this_state_data->data=NULL; 596 this_state_data->data = NULL;
558 this_monitoring_plugin->state->state_data = this_state_data; 597 this_monitoring_plugin->state->state_data = this_state_data;
559 598
560 rc = _np_state_read_file(statefile); 599 rc = _np_state_read_file(statefile);
@@ -562,7 +601,7 @@ state_data *np_state_read() {
562 fclose(statefile); 601 fclose(statefile);
563 } 602 }
564 603
565 if(!rc) { 604 if (!rc) {
566 _cleanup_state_data(); 605 _cleanup_state_data();
567 } 606 }
568 607
@@ -577,60 +616,70 @@ bool _np_state_read_file(FILE *f) {
577 size_t pos; 616 size_t pos;
578 char *line; 617 char *line;
579 int i; 618 int i;
580 int failure=0; 619 int failure = 0;
581 time_t current_time, data_time; 620 time_t current_time, data_time;
582 enum { STATE_FILE_VERSION, STATE_DATA_VERSION, STATE_DATA_TIME, STATE_DATA_TEXT, STATE_DATA_END } expected=STATE_FILE_VERSION; 621 enum {
622 STATE_FILE_VERSION,
623 STATE_DATA_VERSION,
624 STATE_DATA_TIME,
625 STATE_DATA_TEXT,
626 STATE_DATA_END
627 } expected = STATE_FILE_VERSION;
583 628
584 time(&current_time); 629 time(&current_time);
585 630
586 /* Note: This introduces a limit of 1024 bytes in the string data */ 631 /* Note: This introduces a limit of 1024 bytes in the string data */
587 line = (char *) calloc(1, 1024); 632 line = (char *)calloc(1, 1024);
588 if(line==NULL) 633 if (line == NULL) {
589 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 634 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
590 strerror(errno)); 635 }
591 636
592 while(!failure && (fgets(line,1024,f))!=NULL){ 637 while (!failure && (fgets(line, 1024, f)) != NULL) {
593 pos=strlen(line); 638 pos = strlen(line);
594 if(line[pos-1]=='\n') { 639 if (line[pos - 1] == '\n') {
595 line[pos-1]='\0'; 640 line[pos - 1] = '\0';
596 } 641 }
597 642
598 if(line[0] == '#') continue; 643 if (line[0] == '#') {
644 continue;
645 }
599 646
600 switch(expected) { 647 switch (expected) {
601 case STATE_FILE_VERSION: 648 case STATE_FILE_VERSION:
602 i=atoi(line); 649 i = atoi(line);
603 if(i!=NP_STATE_FORMAT_VERSION) 650 if (i != NP_STATE_FORMAT_VERSION) {
604 failure++; 651 failure++;
605 else 652 } else {
606 expected=STATE_DATA_VERSION; 653 expected = STATE_DATA_VERSION;
607 break; 654 }
608 case STATE_DATA_VERSION: 655 break;
609 i=atoi(line); 656 case STATE_DATA_VERSION:
610 if(i != this_monitoring_plugin->state->data_version) 657 i = atoi(line);
611 failure++; 658 if (i != this_monitoring_plugin->state->data_version) {
612 else 659 failure++;
613 expected=STATE_DATA_TIME; 660 } else {
614 break; 661 expected = STATE_DATA_TIME;
615 case STATE_DATA_TIME: 662 }
616 /* If time > now, error */ 663 break;
617 data_time=strtoul(line,NULL,10); 664 case STATE_DATA_TIME:
618 if(data_time > current_time) 665 /* If time > now, error */
619 failure++; 666 data_time = strtoul(line, NULL, 10);
620 else { 667 if (data_time > current_time) {
621 this_monitoring_plugin->state->state_data->time = data_time; 668 failure++;
622 expected=STATE_DATA_TEXT; 669 } else {
623 } 670 this_monitoring_plugin->state->state_data->time = data_time;
624 break; 671 expected = STATE_DATA_TEXT;
625 case STATE_DATA_TEXT: 672 }
626 this_monitoring_plugin->state->state_data->data = strdup(line); 673 break;
627 if(this_monitoring_plugin->state->state_data->data==NULL) 674 case STATE_DATA_TEXT:
628 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); 675 this_monitoring_plugin->state->state_data->data = strdup(line);
629 expected=STATE_DATA_END; 676 if (this_monitoring_plugin->state->state_data->data == NULL) {
630 status=true; 677 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
631 break; 678 }
632 case STATE_DATA_END: 679 expected = STATE_DATA_END;
633 ; 680 status = true;
681 break;
682 case STATE_DATA_END:;
634 } 683 }
635 } 684 }
636 685
@@ -647,77 +696,78 @@ bool _np_state_read_file(FILE *f) {
647 */ 696 */
648void np_state_write_string(time_t data_time, char *data_string) { 697void np_state_write_string(time_t data_time, char *data_string) {
649 FILE *fp; 698 FILE *fp;
650 char *temp_file=NULL; 699 char *temp_file = NULL;
651 int fd=0, result=0; 700 int fd = 0, result = 0;
652 time_t current_time; 701 time_t current_time;
653 char *directories=NULL; 702 char *directories = NULL;
654 char *p=NULL; 703 char *p = NULL;
655 704
656 if(data_time==0) 705 if (data_time == 0) {
657 time(&current_time); 706 time(&current_time);
658 else 707 } else {
659 current_time=data_time; 708 current_time = data_time;
709 }
660 710
661 /* If file doesn't currently exist, create directories */ 711 /* If file doesn't currently exist, create directories */
662 if(access(this_monitoring_plugin->state->_filename,F_OK)!=0) { 712 if (access(this_monitoring_plugin->state->_filename, F_OK) != 0) {
663 result = asprintf(&directories, "%s", this_monitoring_plugin->state->_filename); 713 result = asprintf(&directories, "%s", this_monitoring_plugin->state->_filename);
664 if(result < 0) 714 if (result < 0) {
665 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 715 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
666 strerror(errno)); 716 }
667 717
668 for(p=directories+1; *p; p++) { 718 for (p = directories + 1; *p; p++) {
669 if(*p=='/') { 719 if (*p == '/') {
670 *p='\0'; 720 *p = '\0';
671 if((access(directories,F_OK)!=0) && (mkdir(directories, S_IRWXU)!=0)) { 721 if ((access(directories, F_OK) != 0) && (mkdir(directories, S_IRWXU) != 0)) {
672 /* Can't free this! Otherwise error message is wrong! */ 722 /* Can't free this! Otherwise error message is wrong! */
673 /* np_free(directories); */ 723 /* np_free(directories); */
674 die(STATE_UNKNOWN, _("Cannot create directory: %s"), directories); 724 die(STATE_UNKNOWN, _("Cannot create directory: %s"), directories);
675 } 725 }
676 *p='/'; 726 *p = '/';
677 } 727 }
678 } 728 }
679 np_free(directories); 729 np_free(directories);
680 } 730 }
681 731
682 result = asprintf(&temp_file,"%s.XXXXXX",this_monitoring_plugin->state->_filename); 732 result = asprintf(&temp_file, "%s.XXXXXX", this_monitoring_plugin->state->_filename);
683 if(result < 0) 733 if (result < 0) {
684 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 734 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
685 strerror(errno)); 735 }
686 736
687 if((fd=mkstemp(temp_file))==-1) { 737 if ((fd = mkstemp(temp_file)) == -1) {
688 np_free(temp_file); 738 np_free(temp_file);
689 die(STATE_UNKNOWN, _("Cannot create temporary filename")); 739 die(STATE_UNKNOWN, _("Cannot create temporary filename"));
690 } 740 }
691 741
692 fp=(FILE *)fdopen(fd,"w"); 742 fp = (FILE *)fdopen(fd, "w");
693 if(fp==NULL) { 743 if (fp == NULL) {
694 close(fd); 744 close(fd);
695 unlink(temp_file); 745 unlink(temp_file);
696 np_free(temp_file); 746 np_free(temp_file);
697 die(STATE_UNKNOWN, _("Unable to open temporary state file")); 747 die(STATE_UNKNOWN, _("Unable to open temporary state file"));
698 } 748 }
699 749
700 fprintf(fp,"# NP State file\n"); 750 fprintf(fp, "# NP State file\n");
701 fprintf(fp,"%d\n",NP_STATE_FORMAT_VERSION); 751 fprintf(fp, "%d\n", NP_STATE_FORMAT_VERSION);
702 fprintf(fp,"%d\n",this_monitoring_plugin->state->data_version); 752 fprintf(fp, "%d\n", this_monitoring_plugin->state->data_version);
703 fprintf(fp,"%lu\n",current_time); 753 fprintf(fp, "%lu\n", current_time);
704 fprintf(fp,"%s\n",data_string); 754 fprintf(fp, "%s\n", data_string);
705 755
706 fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP); 756 fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP);
707 757
708 fflush(fp); 758 fflush(fp);
709 759
710 result=fclose(fp); 760 result = fclose(fp);
711 761
712 fsync(fd); 762 fsync(fd);
713 763
714 if(result!=0) { 764 if (result != 0) {
715 unlink(temp_file); 765 unlink(temp_file);
716 np_free(temp_file); 766 np_free(temp_file);
717 die(STATE_UNKNOWN, _("Error writing temp file")); 767 die(STATE_UNKNOWN, _("Error writing temp file"));
718 } 768 }
719 769
720 if(rename(temp_file, this_monitoring_plugin->state->_filename)!=0) { 770 if (rename(temp_file, this_monitoring_plugin->state->_filename) != 0) {
721 unlink(temp_file); 771 unlink(temp_file);
722 np_free(temp_file); 772 np_free(temp_file);
723 die(STATE_UNKNOWN, _("Cannot rename state temp file")); 773 die(STATE_UNKNOWN, _("Cannot rename state temp file"));
diff --git a/lib/utils_base.h b/lib/utils_base.h
index 9d4dffed..123066f8 100644
--- a/lib/utils_base.h
+++ b/lib/utils_base.h
@@ -2,8 +2,15 @@
2#define _UTILS_BASE_ 2#define _UTILS_BASE_
3/* Header file for Monitoring Plugins utils_base.c */ 3/* Header file for Monitoring Plugins utils_base.c */
4 4
5#include "../config.h"
6#include <time.h>
7
8#include "./perfdata.h"
9#include "./thresholds.h"
10
11
5#ifndef USE_OPENSSL 12#ifndef USE_OPENSSL
6# include "sha256.h" 13# include "sha256.h"
7#endif 14#endif
8 15
9/* This file holds header information for thresholds - use this in preference to 16/* This file holds header information for thresholds - use this in preference to
@@ -19,49 +26,35 @@
19#define OUTSIDE 0 26#define OUTSIDE 0
20#define INSIDE 1 27#define INSIDE 1
21 28
22typedef struct range_struct {
23 double start;
24 bool start_infinity;
25 double end;
26 int end_infinity;
27 int alert_on; /* OUTSIDE (default) or INSIDE */
28 char* text; /* original unparsed text input */
29 } range;
30
31typedef struct thresholds_struct {
32 range *warning;
33 range *critical;
34 } thresholds;
35
36#define NP_STATE_FORMAT_VERSION 1 29#define NP_STATE_FORMAT_VERSION 1
37 30
38typedef struct state_data_struct { 31typedef struct state_data_struct {
39 time_t time; 32 time_t time;
40 void *data; 33 void *data;
41 int length; /* Of binary data */ 34 int length; /* Of binary data */
42 } state_data; 35} state_data;
43
44 36
45typedef struct state_key_struct { 37typedef struct state_key_struct {
46 char *name; 38 char *name;
47 char *plugin_name; 39 char *plugin_name;
48 int data_version; 40 int data_version;
49 char *_filename; 41 char *_filename;
50 state_data *state_data; 42 state_data *state_data;
51 } state_key; 43} state_key;
52 44
53typedef struct np_struct { 45typedef struct np_struct {
54 char *plugin_name; 46 char *plugin_name;
55 state_key *state; 47 state_key *state;
56 int argc; 48 int argc;
57 char **argv; 49 char **argv;
58 } monitoring_plugin; 50} monitoring_plugin;
59 51
60range *parse_range_string (char *); 52range *parse_range_string(char *);
61int _set_thresholds(thresholds **, char *, char *); 53int _set_thresholds(thresholds **, char *, char *);
62void set_thresholds(thresholds **, char *, char *); 54void set_thresholds(thresholds **, char *, char *);
63void print_thresholds(const char *, thresholds *); 55void print_thresholds(const char *, thresholds *);
64bool check_range(double, range *); 56bool check_range(double, range *);
57bool mp_check_range(mp_perfdata_value, mp_range);
65int get_status(double, thresholds *); 58int get_status(double, thresholds *);
66 59
67/* Handle timeouts */ 60/* Handle timeouts */
@@ -71,13 +64,13 @@ extern unsigned int timeout_interval;
71/* All possible characters in a threshold range */ 64/* All possible characters in a threshold range */
72#define NP_THRESHOLDS_CHARS "-0123456789.:@~" 65#define NP_THRESHOLDS_CHARS "-0123456789.:@~"
73 66
74char *np_escaped_string (const char *); 67char *np_escaped_string(const char *);
75 68
76void die (int, const char *, ...) __attribute__((noreturn,format(printf, 2, 3))); 69void die(int, const char *, ...) __attribute__((noreturn, format(printf, 2, 3)));
77 70
78/* Return codes for _set_thresholds */ 71/* Return codes for _set_thresholds */
79#define NP_RANGE_UNPARSEABLE 1 72#define NP_RANGE_UNPARSEABLE 1
80#define NP_WARN_WITHIN_CRIT 2 73#define NP_WARN_WITHIN_CRIT 2
81 74
82/* a simple check to see if we're running as root. 75/* a simple check to see if we're running as root.
83 * returns zero on failure, nonzero on success */ 76 * returns zero on failure, nonzero on success */
@@ -93,7 +86,7 @@ int np_check_if_root(void);
93 * This function can be used to parse NTP control packet data and performance 86 * This function can be used to parse NTP control packet data and performance
94 * data strings. 87 * data strings.
95 */ 88 */
96char *np_extract_value(const char*, const char*, char); 89char *np_extract_value(const char *, const char *, char);
97 90
98/* 91/*
99 * Same as np_extract_value with separator suitable for NTP control packet 92 * Same as np_extract_value with separator suitable for NTP control packet
@@ -105,15 +98,15 @@ char *np_extract_value(const char*, const char*, char);
105 * Read a string representing a state (ok, warning... or numeric: 0, 1) and 98 * Read a string representing a state (ok, warning... or numeric: 0, 1) and
106 * return the corresponding NP_STATE or ERROR) 99 * return the corresponding NP_STATE or ERROR)
107 */ 100 */
108int mp_translate_state (char *); 101int mp_translate_state(char *);
109 102
110void np_enable_state(char *, int); 103void np_enable_state(char *, int);
111state_data *np_state_read(); 104state_data *np_state_read(void);
112void np_state_write_string(time_t, char *); 105void np_state_write_string(time_t, char *);
113 106
114void np_init(char *, int argc, char **argv); 107void np_init(char *, int argc, char **argv);
115void np_set_args(int argc, char **argv); 108void np_set_args(int argc, char **argv);
116void np_cleanup(); 109void np_cleanup(void);
117const char *state_text (int); 110const char *state_text(int);
118 111
119#endif /* _UTILS_BASE_ */ 112#endif /* _UTILS_BASE_ */
diff --git a/lib/utils_cmd.c b/lib/utils_cmd.c
index 7957ec14..9b222409 100644
--- a/lib/utils_cmd.c
+++ b/lib/utils_cmd.c
@@ -1,40 +1,40 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring run command utilities 3 * Monitoring run command utilities
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2005-2006 Monitoring Plugins Development Team 6 * Copyright (c) 2005-2024 Monitoring Plugins Development Team
7* 7 *
8* Description : 8 * Description :
9* 9 *
10* A simple interface to executing programs from other programs, using an 10 * A simple interface to executing programs from other programs, using an
11* optimized and safe popen()-like implementation. It is considered safe 11 * optimized and safe popen()-like implementation. It is considered safe
12* in that no shell needs to be spawned and the environment passed to the 12 * in that no shell needs to be spawned and the environment passed to the
13* execve()'d program is essentially empty. 13 * execve()'d program is essentially empty.
14* 14 *
15* The code in this file is a derivative of popen.c which in turn was taken 15 * The code in this file is a derivative of popen.c which in turn was taken
16* from "Advanced Programming for the Unix Environment" by W. Richard Stevens. 16 * from "Advanced Programming for the Unix Environment" by W. Richard Stevens.
17* 17 *
18* Care has been taken to make sure the functions are async-safe. The one 18 * Care has been taken to make sure the functions are async-safe. The one
19* function which isn't is cmd_init() which it doesn't make sense to 19 * function which isn't is cmd_init() which it doesn't make sense to
20* call twice anyway, so the api as a whole should be considered async-safe. 20 * call twice anyway, so the api as a whole should be considered async-safe.
21* 21 *
22* 22 *
23* This program is free software: you can redistribute it and/or modify 23 * This program is free software: you can redistribute it and/or modify
24* it under the terms of the GNU General Public License as published by 24 * it under the terms of the GNU General Public License as published by
25* the Free Software Foundation, either version 3 of the License, or 25 * the Free Software Foundation, either version 3 of the License, or
26* (at your option) any later version. 26 * (at your option) any later version.
27* 27 *
28* This program is distributed in the hope that it will be useful, 28 * This program is distributed in the hope that it will be useful,
29* but WITHOUT ANY WARRANTY; without even the implied warranty of 29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31* GNU General Public License for more details. 31 * GNU General Public License for more details.
32* 32 *
33* You should have received a copy of the GNU General Public License 33 * You should have received a copy of the GNU General Public License
34* along with this program. If not, see <http://www.gnu.org/licenses/>. 34 * along with this program. If not, see <http://www.gnu.org/licenses/>.
35* 35 *
36* 36 *
37*****************************************************************************/ 37 *****************************************************************************/
38 38
39#define NAGIOSPLUG_API_C 1 39#define NAGIOSPLUG_API_C 1
40 40
@@ -59,7 +59,7 @@ static pid_t *_cmd_pids = NULL;
59#include <fcntl.h> 59#include <fcntl.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 */ 65/* used in _cmd_open to pass the environment to commands */
@@ -67,57 +67,48 @@ extern char **environ;
67 67
68/** macros **/ 68/** macros **/
69#ifndef WEXITSTATUS 69#ifndef WEXITSTATUS
70# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) 70# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
71#endif 71#endif
72 72
73#ifndef WIFEXITED 73#ifndef WIFEXITED
74# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) 74# define WIFEXITED(stat_val) (((stat_val)&255) == 0)
75#endif 75#endif
76 76
77/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */ 77/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */
78#if defined(SIG_IGN) && !defined(SIG_ERR) 78#if defined(SIG_IGN) && !defined(SIG_ERR)
79# define SIG_ERR ((Sigfunc *)-1) 79# define SIG_ERR ((Sigfunc *)-1)
80#endif 80#endif
81 81
82/** prototypes **/ 82/** prototypes **/
83static int _cmd_open (char *const *, int *, int *) 83static int _cmd_open(char *const *, int *, int *) __attribute__((__nonnull__(1, 2, 3)));
84 __attribute__ ((__nonnull__ (1, 2, 3)));
85 84
86static int _cmd_fetch_output (int, output *, int) 85static int _cmd_fetch_output(int, output *, int) __attribute__((__nonnull__(2)));
87 __attribute__ ((__nonnull__ (2)));
88 86
89static int _cmd_close (int); 87static int _cmd_close(int);
90 88
91/* prototype imported from utils.h */ 89/* prototype imported from utils.h */
92extern void die (int, const char *, ...) 90extern void die(int, const char *, ...) __attribute__((__noreturn__, __format__(__printf__, 2, 3)));
93 __attribute__ ((__noreturn__, __format__ (__printf__, 2, 3)));
94
95 91
96/* this function is NOT async-safe. It is exported so multithreaded 92/* this function is NOT async-safe. It is exported so multithreaded
97 * plugins (or other apps) can call it prior to running any commands 93 * plugins (or other apps) can call it prior to running any commands
98 * through this api and thus achieve async-safeness throughout the api */ 94 * through this api and thus achieve async-safeness throughout the api */
99void 95void cmd_init(void) {
100cmd_init (void)
101{
102 long maxfd = mp_open_max(); 96 long maxfd = mp_open_max();
103 97
104 /* if maxfd is unnaturally high, we force it to a lower value 98 /* if maxfd is unnaturally high, we force it to a lower value
105 * ( e.g. on SunOS, when ulimit is set to unlimited: 2147483647 this would cause 99 * ( e.g. on SunOS, when ulimit is set to unlimited: 2147483647 this would cause
106 * a segfault when following calloc is called ... ) */ 100 * a segfault when following calloc is called ... ) */
107 101
108 if ( maxfd > MAXFD_LIMIT ) { 102 if (maxfd > MAXFD_LIMIT) {
109 maxfd = MAXFD_LIMIT; 103 maxfd = MAXFD_LIMIT;
110 } 104 }
111 105
112 if (!_cmd_pids) 106 if (!_cmd_pids)
113 _cmd_pids = calloc (maxfd, sizeof (pid_t)); 107 _cmd_pids = calloc(maxfd, sizeof(pid_t));
114} 108}
115 109
116
117/* Start running a command, array style */ 110/* Start running a command, array style */
118static int 111static int _cmd_open(char *const *argv, int *pfd, int *pfderr) {
119_cmd_open (char *const *argv, int *pfd, int *pfderr)
120{
121 pid_t pid; 112 pid_t pid;
122#ifdef RLIMIT_CORE 113#ifdef RLIMIT_CORE
123 struct rlimit limit; 114 struct rlimit limit;
@@ -130,26 +121,26 @@ _cmd_open (char *const *argv, int *pfd, int *pfderr)
130 121
131 setenv("LC_ALL", "C", 1); 122 setenv("LC_ALL", "C", 1);
132 123
133 if (pipe (pfd) < 0 || pipe (pfderr) < 0 || (pid = fork ()) < 0) 124 if (pipe(pfd) < 0 || pipe(pfderr) < 0 || (pid = fork()) < 0)
134 return -1; /* errno set by the failing function */ 125 return -1; /* errno set by the failing function */
135 126
136 /* child runs exceve() and _exit. */ 127 /* child runs exceve() and _exit. */
137 if (pid == 0) { 128 if (pid == 0) {
138#ifdef RLIMIT_CORE 129#ifdef RLIMIT_CORE
139 /* the program we execve shouldn't leave core files */ 130 /* the program we execve shouldn't leave core files */
140 getrlimit (RLIMIT_CORE, &limit); 131 getrlimit(RLIMIT_CORE, &limit);
141 limit.rlim_cur = 0; 132 limit.rlim_cur = 0;
142 setrlimit (RLIMIT_CORE, &limit); 133 setrlimit(RLIMIT_CORE, &limit);
143#endif 134#endif
144 close (pfd[0]); 135 close(pfd[0]);
145 if (pfd[1] != STDOUT_FILENO) { 136 if (pfd[1] != STDOUT_FILENO) {
146 dup2 (pfd[1], STDOUT_FILENO); 137 dup2(pfd[1], STDOUT_FILENO);
147 close (pfd[1]); 138 close(pfd[1]);
148 } 139 }
149 close (pfderr[0]); 140 close(pfderr[0]);
150 if (pfderr[1] != STDERR_FILENO) { 141 if (pfderr[1] != STDERR_FILENO) {
151 dup2 (pfderr[1], STDERR_FILENO); 142 dup2(pfderr[1], STDERR_FILENO);
152 close (pfderr[1]); 143 close(pfderr[1]);
153 } 144 }
154 145
155 /* close all descriptors in _cmd_pids[] 146 /* close all descriptors in _cmd_pids[]
@@ -158,16 +149,16 @@ _cmd_open (char *const *argv, int *pfd, int *pfderr)
158 long maxfd = mp_open_max(); 149 long maxfd = mp_open_max();
159 for (i = 0; i < maxfd; i++) 150 for (i = 0; i < maxfd; i++)
160 if (_cmd_pids[i] > 0) 151 if (_cmd_pids[i] > 0)
161 close (i); 152 close(i);
162 153
163 execve (argv[0], argv, environ); 154 execve(argv[0], argv, environ);
164 _exit (STATE_UNKNOWN); 155 _exit(STATE_UNKNOWN);
165 } 156 }
166 157
167 /* parent picks up execution here */ 158 /* parent picks up execution here */
168 /* close children descriptors in our address space */ 159 /* close children descriptors in our address space */
169 close (pfd[1]); 160 close(pfd[1]);
170 close (pfderr[1]); 161 close(pfderr[1]);
171 162
172 /* tag our file's entry in the pid-list and return it */ 163 /* tag our file's entry in the pid-list and return it */
173 _cmd_pids[pfd[0]] = pid; 164 _cmd_pids[pfd[0]] = pid;
@@ -175,9 +166,7 @@ _cmd_open (char *const *argv, int *pfd, int *pfderr)
175 return pfd[0]; 166 return pfd[0];
176} 167}
177 168
178static int 169static int _cmd_close(int fd) {
179_cmd_close (int fd)
180{
181 int status; 170 int status;
182 pid_t pid; 171 pid_t pid;
183 172
@@ -187,40 +176,37 @@ _cmd_close (int fd)
187 return -1; 176 return -1;
188 177
189 _cmd_pids[fd] = 0; 178 _cmd_pids[fd] = 0;
190 if (close (fd) == -1) 179 if (close(fd) == -1)
191 return -1; 180 return -1;
192 181
193 /* EINTR is ok (sort of), everything else is bad */ 182 /* EINTR is ok (sort of), everything else is bad */
194 while (waitpid (pid, &status, 0) < 0) 183 while (waitpid(pid, &status, 0) < 0)
195 if (errno != EINTR) 184 if (errno != EINTR)
196 return -1; 185 return -1;
197 186
198 /* return child's termination status */ 187 /* return child's termination status */
199 return (WIFEXITED (status)) ? WEXITSTATUS (status) : -1; 188 return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1;
200} 189}
201 190
202 191static int _cmd_fetch_output(int fd, output *op, int flags) {
203static int
204_cmd_fetch_output (int fd, output * op, int flags)
205{
206 size_t len = 0, i = 0, lineno = 0; 192 size_t len = 0, i = 0, lineno = 0;
207 size_t rsf = 6, ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */ 193 size_t rsf = 6, ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */
208 char *buf = NULL; 194 char *buf = NULL;
209 int ret; 195 int ret;
210 char tmpbuf[4096]; 196 char tmpbuf[4096];
211 197
212 op->buf = NULL; 198 op->buf = NULL;
213 op->buflen = 0; 199 op->buflen = 0;
214 while ((ret = read (fd, tmpbuf, sizeof (tmpbuf))) > 0) { 200 while ((ret = read(fd, tmpbuf, sizeof(tmpbuf))) > 0) {
215 len = (size_t) ret; 201 len = (size_t)ret;
216 op->buf = realloc (op->buf, op->buflen + len + 1); 202 op->buf = realloc(op->buf, op->buflen + len + 1);
217 memcpy (op->buf + op->buflen, tmpbuf, len); 203 memcpy(op->buf + op->buflen, tmpbuf, len);
218 op->buflen += len; 204 op->buflen += len;
219 i++; 205 i++;
220 } 206 }
221 207
222 if (ret < 0) { 208 if (ret < 0) {
223 printf ("read() returned %d: %s\n", ret, strerror (errno)); 209 printf("read() returned %d: %s\n", ret, strerror(errno));
224 return ret; 210 return ret;
225 } 211 }
226 212
@@ -231,10 +217,9 @@ _cmd_fetch_output (int fd, output * op, int flags)
231 217
232 /* and some may want both */ 218 /* and some may want both */
233 if (flags & CMD_NO_ASSOC) { 219 if (flags & CMD_NO_ASSOC) {
234 buf = malloc (op->buflen); 220 buf = malloc(op->buflen);
235 memcpy (buf, op->buf, op->buflen); 221 memcpy(buf, op->buf, op->buflen);
236 } 222 } else
237 else
238 buf = op->buf; 223 buf = op->buf;
239 224
240 op->line = NULL; 225 op->line = NULL;
@@ -248,8 +233,8 @@ _cmd_fetch_output (int fd, output * op, int flags)
248 ary_size = op->buflen >> --rsf; 233 ary_size = op->buflen >> --rsf;
249 } while (!ary_size); 234 } while (!ary_size);
250 235
251 op->line = realloc (op->line, ary_size * sizeof (char *)); 236 op->line = realloc(op->line, ary_size * sizeof(char *));
252 op->lens = realloc (op->lens, ary_size * sizeof (size_t)); 237 op->lens = realloc(op->lens, ary_size * sizeof(size_t));
253 } 238 }
254 239
255 /* set the pointer to the string */ 240 /* set the pointer to the string */
@@ -261,7 +246,7 @@ _cmd_fetch_output (int fd, output * op, int flags)
261 buf[i] = '\0'; 246 buf[i] = '\0';
262 247
263 /* calculate the string length using pointer difference */ 248 /* calculate the string length using pointer difference */
264 op->lens[lineno] = (size_t) & buf[i] - (size_t) op->line[lineno]; 249 op->lens[lineno] = (size_t)&buf[i] - (size_t)op->line[lineno];
265 250
266 lineno++; 251 lineno++;
267 i++; 252 i++;
@@ -270,10 +255,7 @@ _cmd_fetch_output (int fd, output * op, int flags)
270 return lineno; 255 return lineno;
271} 256}
272 257
273 258int cmd_run(const char *cmdstring, output *out, output *err, int flags) {
274int
275cmd_run (const char *cmdstring, output * out, output * err, int flags)
276{
277 int i = 0, argc; 259 int i = 0, argc;
278 size_t cmdlen; 260 size_t cmdlen;
279 char **argv = NULL; 261 char **argv = NULL;
@@ -285,120 +267,114 @@ cmd_run (const char *cmdstring, output * out, output * err, int flags)
285 267
286 /* initialize the structs */ 268 /* initialize the structs */
287 if (out) 269 if (out)
288 memset (out, 0, sizeof (output)); 270 memset(out, 0, sizeof(output));
289 if (err) 271 if (err)
290 memset (err, 0, sizeof (output)); 272 memset(err, 0, sizeof(output));
291 273
292 /* make copy of command string so strtok() doesn't silently modify it */ 274 /* make copy of command string so strtok() doesn't silently modify it */
293 /* (the calling program may want to access it later) */ 275 /* (the calling program may want to access it later) */
294 cmdlen = strlen (cmdstring); 276 cmdlen = strlen(cmdstring);
295 if ((cmd = malloc (cmdlen + 1)) == NULL) 277 if ((cmd = malloc(cmdlen + 1)) == NULL)
296 return -1; 278 return -1;
297 memcpy (cmd, cmdstring, cmdlen); 279 memcpy(cmd, cmdstring, cmdlen);
298 cmd[cmdlen] = '\0'; 280 cmd[cmdlen] = '\0';
299 281
300 /* This is not a shell, so we don't handle "???" */ 282 /* This is not a shell, so we don't handle "???" */
301 if (strstr (cmdstring, "\"")) return -1; 283 if (strstr(cmdstring, "\""))
284 return -1;
302 285
303 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */ 286 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */
304 if (strstr (cmdstring, " ' ") || strstr (cmdstring, "'''")) 287 if (strstr(cmdstring, " ' ") || strstr(cmdstring, "'''"))
305 return -1; 288 return -1;
306 289
307 /* each arg must be whitespace-separated, so args can be a maximum 290 /* each arg must be whitespace-separated, so args can be a maximum
308 * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */ 291 * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */
309 argc = (cmdlen >> 1) + 2; 292 argc = (cmdlen >> 1) + 2;
310 argv = calloc (sizeof (char *), argc); 293 argv = calloc((size_t)argc, sizeof(char *));
311 294
312 if (argv == NULL) { 295 if (argv == NULL) {
313 printf ("%s\n", _("Could not malloc argv array in popen()")); 296 printf("%s\n", _("Could not malloc argv array in popen()"));
314 return -1; 297 return -1;
315 } 298 }
316 299
317 /* get command arguments (stupidly, but fairly quickly) */ 300 /* get command arguments (stupidly, but fairly quickly) */
318 while (cmd) { 301 while (cmd) {
319 str = cmd; 302 str = cmd;
320 str += strspn (str, " \t\r\n"); /* trim any leading whitespace */ 303 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */
321 304
322 if (strstr (str, "'") == str) { /* handle SIMPLE quoted strings */ 305 if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */
323 str++; 306 str++;
324 if (!strstr (str, "'")) 307 if (!strstr(str, "'"))
325 return -1; /* balanced? */ 308 return -1; /* balanced? */
326 cmd = 1 + strstr (str, "'"); 309 cmd = 1 + strstr(str, "'");
327 str[strcspn (str, "'")] = 0; 310 str[strcspn(str, "'")] = 0;
328 } 311 } else {
329 else { 312 if (strpbrk(str, " \t\r\n")) {
330 if (strpbrk (str, " \t\r\n")) { 313 cmd = 1 + strpbrk(str, " \t\r\n");
331 cmd = 1 + strpbrk (str, " \t\r\n"); 314 str[strcspn(str, " \t\r\n")] = 0;
332 str[strcspn (str, " \t\r\n")] = 0; 315 } else {
333 }
334 else {
335 cmd = NULL; 316 cmd = NULL;
336 } 317 }
337 } 318 }
338 319
339 if (cmd && strlen (cmd) == strspn (cmd, " \t\r\n")) 320 if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n"))
340 cmd = NULL; 321 cmd = NULL;
341 322
342 argv[i++] = str; 323 argv[i++] = str;
343 } 324 }
344 325
345 return cmd_run_array (argv, out, err, flags); 326 return cmd_run_array(argv, out, err, flags);
346} 327}
347 328
348int 329int cmd_run_array(char *const *argv, output *out, output *err, int flags) {
349cmd_run_array (char *const *argv, output * out, output * err, int flags)
350{
351 int fd, pfd_out[2], pfd_err[2]; 330 int fd, pfd_out[2], pfd_err[2];
352 331
353 /* initialize the structs */ 332 /* initialize the structs */
354 if (out) 333 if (out)
355 memset (out, 0, sizeof (output)); 334 memset(out, 0, sizeof(output));
356 if (err) 335 if (err)
357 memset (err, 0, sizeof (output)); 336 memset(err, 0, sizeof(output));
358 337
359 if ((fd = _cmd_open (argv, pfd_out, pfd_err)) == -1) 338 if ((fd = _cmd_open(argv, pfd_out, pfd_err)) == -1)
360 die (STATE_UNKNOWN, _("Could not open pipe: %s\n"), argv[0]); 339 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), argv[0]);
361 340
362 if (out) 341 if (out)
363 out->lines = _cmd_fetch_output (pfd_out[0], out, flags); 342 out->lines = _cmd_fetch_output(pfd_out[0], out, flags);
364 if (err) 343 if (err)
365 err->lines = _cmd_fetch_output (pfd_err[0], err, flags); 344 err->lines = _cmd_fetch_output(pfd_err[0], err, flags);
366 345
367 return _cmd_close (fd); 346 return _cmd_close(fd);
368} 347}
369 348
370int 349int cmd_file_read(const char *filename, output *out, int flags) {
371cmd_file_read ( char *filename, output *out, int flags)
372{
373 int fd; 350 int fd;
374 if(out) 351 if (out)
375 memset (out, 0, sizeof(output)); 352 memset(out, 0, sizeof(output));
376 353
377 if ((fd = open(filename, O_RDONLY)) == -1) { 354 if ((fd = open(filename, O_RDONLY)) == -1) {
378 die( STATE_UNKNOWN, _("Error opening %s: %s"), filename, strerror(errno) ); 355 die(STATE_UNKNOWN, _("Error opening %s: %s"), filename, strerror(errno));
379 } 356 }
380 357
381 if(out) 358 if (out)
382 out->lines = _cmd_fetch_output (fd, out, flags); 359 out->lines = _cmd_fetch_output(fd, out, flags);
383 360
384 if (close(fd) == -1) 361 if (close(fd) == -1)
385 die( STATE_UNKNOWN, _("Error closing %s: %s"), filename, strerror(errno) ); 362 die(STATE_UNKNOWN, _("Error closing %s: %s"), filename, strerror(errno));
386 363
387 return 0; 364 return 0;
388} 365}
389 366
390void 367void timeout_alarm_handler(int signo) {
391timeout_alarm_handler (int signo)
392{
393 if (signo == SIGALRM) { 368 if (signo == SIGALRM) {
394 printf (_("%s - Plugin timed out after %d seconds\n"), 369 printf(_("%s - Plugin timed out after %d seconds\n"), state_text(timeout_state), timeout_interval);
395 state_text(timeout_state), timeout_interval);
396 370
397 long maxfd = mp_open_max(); 371 long maxfd = mp_open_max();
398 if(_cmd_pids) for(long int i = 0; i < maxfd; i++) { 372 if (_cmd_pids)
399 if(_cmd_pids[i] != 0) kill(_cmd_pids[i], SIGKILL); 373 for (long int i = 0; i < maxfd; i++) {
400 } 374 if (_cmd_pids[i] != 0)
375 kill(_cmd_pids[i], SIGKILL);
376 }
401 377
402 exit (timeout_state); 378 exit(timeout_state);
403 } 379 }
404} 380}
diff --git a/lib/utils_cmd.h b/lib/utils_cmd.h
index 061f5d4f..728ece23 100644
--- a/lib/utils_cmd.h
+++ b/lib/utils_cmd.h
@@ -4,12 +4,10 @@
4/* 4/*
5 * Header file for Monitoring Plugins utils_cmd.c 5 * Header file for Monitoring Plugins utils_cmd.c
6 * 6 *
7 *
8 */ 7 */
9 8
10/** types **/ 9/** types **/
11struct output 10struct output {
12{
13 char *buf; /* output buffer */ 11 char *buf; /* output buffer */
14 size_t buflen; /* output buffer content length */ 12 size_t buflen; /* output buffer content length */
15 char **line; /* array of lines (points to buf) */ 13 char **line; /* array of lines (points to buf) */
@@ -20,20 +18,18 @@ struct output
20typedef struct output output; 18typedef struct output output;
21 19
22/** prototypes **/ 20/** prototypes **/
23int cmd_run (const char *, output *, output *, int); 21int cmd_run(const char *, output *, output *, int);
24int cmd_run_array (char *const *, output *, output *, int); 22int cmd_run_array(char *const *, output *, output *, int);
25int cmd_file_read (char *, output *, int); 23int cmd_file_read(const char *, output *, int);
26 24
27/* only multi-threaded plugins need to bother with this */ 25/* only multi-threaded plugins need to bother with this */
28void cmd_init (void); 26void cmd_init(void);
29#define CMD_INIT cmd_init() 27#define CMD_INIT cmd_init()
30 28
31/* possible flags for cmd_run()'s fourth argument */ 29/* possible flags for cmd_run()'s fourth argument */
32#define CMD_NO_ARRAYS 0x01 /* don't populate arrays at all */ 30#define CMD_NO_ARRAYS 0x01 /* don't populate arrays at all */
33#define CMD_NO_ASSOC 0x02 /* output.line won't point to buf */ 31#define CMD_NO_ASSOC 0x02 /* output.line won't point to buf */
34
35
36void timeout_alarm_handler (int);
37 32
33void timeout_alarm_handler(int);
38 34
39#endif /* _UTILS_CMD_ */ 35#endif /* _UTILS_CMD_ */
diff --git a/lib/utils_disk.c b/lib/utils_disk.c
deleted file mode 100644
index 483be06d..00000000
--- a/lib/utils_disk.c
+++ /dev/null
@@ -1,270 +0,0 @@
1/*****************************************************************************
2*
3* Library for check_disk
4*
5* License: GPL
6* Copyright (c) 1999-2007 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
35np_add_name (struct name_list **list, const char *name)
36{
37 struct name_list *new_entry;
38 new_entry = (struct name_list *) malloc (sizeof *new_entry);
39 new_entry->name = (char *) name;
40 new_entry->next = *list;
41 *list = new_entry;
42}
43
44/* @brief Initialises a new regex at the begin of list via regcomp(3)
45 *
46 * @details if the regex fails to compile the error code of regcomp(3) is returned
47 * and list is not modified, otherwise list is modified to point to the new
48 * element
49 * @param list Pointer to a linked list of regex_list elements
50 * @param regex the string containing the regex which should be inserted into the list
51 * @param clags the cflags parameter for regcomp(3)
52 */
53int
54np_add_regex (struct regex_list **list, const char *regex, int cflags)
55{
56 struct regex_list *new_entry = (struct regex_list *) malloc (sizeof *new_entry);
57
58 if (new_entry == NULL) {
59 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"),
60 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 } else {
72 // regcomp failed
73 free(new_entry);
74
75 return regcomp_result;
76 }
77
78}
79
80/* Initialises a new parameter at the end of list */
81struct parameter_list *
82np_add_parameter(struct parameter_list **list, const char *name)
83{
84 struct parameter_list *current = *list;
85 struct parameter_list *new_path;
86 new_path = (struct parameter_list *) malloc (sizeof *new_path);
87 new_path->name = (char *) malloc(strlen(name) + 1);
88 new_path->best_match = NULL;
89 new_path->name_next = NULL;
90 new_path->name_prev = NULL;
91 new_path->freespace_bytes = NULL;
92 new_path->freespace_units = NULL;
93 new_path->freespace_percent = NULL;
94 new_path->usedspace_bytes = NULL;
95 new_path->usedspace_units = NULL;
96 new_path->usedspace_percent = NULL;
97 new_path->usedinodes_percent = NULL;
98 new_path->freeinodes_percent = NULL;
99 new_path->group = NULL;
100 new_path->dfree_pct = -1;
101 new_path->dused_pct = -1;
102 new_path->total = 0;
103 new_path->available = 0;
104 new_path->available_to_root = 0;
105 new_path->used = 0;
106 new_path->dused_units = 0;
107 new_path->dfree_units = 0;
108 new_path->dtotal_units = 0;
109 new_path->inodes_total = 0;
110 new_path->inodes_free = 0;
111 new_path->inodes_free_to_root = 0;
112 new_path->inodes_used = 0;
113 new_path->dused_inodes_percent = 0;
114 new_path->dfree_inodes_percent = 0;
115
116 strcpy(new_path->name, name);
117
118 if (current == NULL) {
119 *list = new_path;
120 new_path->name_prev = NULL;
121 } else {
122 while (current->name_next) {
123 current = current->name_next;
124 }
125 current->name_next = new_path;
126 new_path->name_prev = current;
127 }
128 return new_path;
129}
130
131/* Delete a given parameter from list and return pointer to next element*/
132struct parameter_list *
133np_del_parameter(struct parameter_list *item, struct parameter_list *prev)
134{
135 if (item == NULL) {
136 return NULL;
137 }
138 struct parameter_list *next;
139
140 if (item->name_next)
141 next = item->name_next;
142 else
143 next = NULL;
144
145 if (next)
146 next->name_prev = prev;
147
148 if (prev)
149 prev->name_next = next;
150
151 if (item->name) {
152 free(item->name);
153 }
154 free(item);
155
156 return next;
157}
158
159
160/* returns a pointer to the struct found in the list */
161struct parameter_list *
162np_find_parameter(struct parameter_list *list, const char *name)
163{
164 struct parameter_list *temp_list;
165 for (temp_list = list; temp_list; temp_list = temp_list->name_next) {
166 if (! strcmp(temp_list->name, name))
167 return temp_list;
168 }
169
170 return NULL;
171}
172
173void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount_list, bool exact) {
174 struct parameter_list *d;
175 for (d = desired; d; d= d->name_next) {
176 if (! d->best_match) {
177 struct mount_entry *me;
178 size_t name_len = strlen(d->name);
179 size_t best_match_len = 0;
180 struct mount_entry *best_match = NULL;
181 struct fs_usage fsp;
182
183 /* set best match if path name exactly matches a mounted device name */
184 for (me = mount_list; me; me = me->me_next) {
185 if (strcmp(me->me_devname, d->name)==0) {
186 if (get_fs_usage(me->me_mountdir, me->me_devname, &fsp) >= 0) {
187 best_match = me;
188 }
189 }
190 }
191
192 /* set best match by directory name if no match was found by devname */
193 if (! best_match) {
194 for (me = mount_list; me; me = me->me_next) {
195 size_t len = strlen (me->me_mountdir);
196 if ((!exact && (best_match_len <= len && len <= name_len &&
197 (len == 1 || strncmp (me->me_mountdir, d->name, len) == 0)))
198 || (exact && strcmp(me->me_mountdir, d->name)==0))
199 {
200 if (get_fs_usage(me->me_mountdir, me->me_devname, &fsp) >= 0) {
201 best_match = me;
202 best_match_len = len;
203 }
204 }
205 }
206 }
207
208 if (best_match) {
209 d->best_match = best_match;
210 } else {
211 d->best_match = NULL; /* Not sure why this is needed as it should be null on initialisation */
212 }
213 }
214 }
215}
216
217/* Returns true if name is in list */
218bool np_find_name (struct name_list *list, const char *name) {
219 const struct name_list *n;
220
221 if (list == NULL || name == NULL) {
222 return false;
223 }
224 for (n = list; n; n = n->next) {
225 if (!strcmp(name, n->name)) {
226 return true;
227 }
228 }
229 return false;
230}
231
232/* Returns true if name is in list */
233bool np_find_regmatch (struct regex_list *list, const char *name) {
234 int len;
235 regmatch_t m;
236
237 if (name == NULL) {
238 return false;
239 }
240
241 len = strlen(name);
242
243 for (; list; list = list->next) {
244 /* Emulate a full match as if surrounded with ^( )$
245 by checking whether the match spans the whole name */
246 if (!regexec(&list->regex, name, 1, &m, 0) && m.rm_so == 0 && m.rm_eo == len) {
247 return true;
248 }
249 }
250
251 return false;
252}
253
254bool np_seen_name(struct name_list *list, const char *name) {
255 const struct name_list *s;
256 for (s = list; s; s=s->next) {
257 if (!strcmp(s->name, name)) {
258 return true;
259 }
260 }
261 return false;
262}
263
264bool np_regex_match_mount_entry (struct mount_entry* me, regex_t* re) {
265 if (regexec(re, me->me_devname, (size_t) 0, NULL, 0) == 0 ||
266 regexec(re, me->me_mountdir, (size_t) 0, NULL, 0) == 0 ) {
267 return true;
268 }
269 return false;
270}
diff --git a/lib/utils_disk.h b/lib/utils_disk.h
deleted file mode 100644
index 5b2caf23..00000000
--- a/lib/utils_disk.h
+++ /dev/null
@@ -1,52 +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{
9 char *name;
10 struct name_list *next;
11};
12
13struct regex_list
14{
15 regex_t regex;
16 struct regex_list *next;
17};
18
19struct parameter_list
20{
21 char *name;
22 thresholds *freespace_bytes;
23 thresholds *freespace_units;
24 thresholds *freespace_percent;
25 thresholds *usedspace_bytes;
26 thresholds *usedspace_units;
27 thresholds *usedspace_percent;
28 thresholds *usedinodes_percent;
29 thresholds *freeinodes_percent;
30 char *group;
31 struct mount_entry *best_match;
32 struct parameter_list *name_next;
33 struct parameter_list *name_prev;
34 uintmax_t total, available, available_to_root, used,
35 inodes_free, inodes_free_to_root, inodes_used, inodes_total;
36 double dfree_pct, dused_pct;
37 uint64_t dused_units, dfree_units, dtotal_units;
38 double dused_inodes_percent, dfree_inodes_percent;
39};
40
41void np_add_name (struct name_list **list, const char *name);
42bool np_find_name (struct name_list *list, const char *name);
43bool np_seen_name (struct name_list *list, const char *name);
44int np_add_regex (struct regex_list **list, const char *regex, int cflags);
45bool np_find_regmatch (struct regex_list *list, const char *name);
46struct parameter_list *np_add_parameter(struct parameter_list **list, const char *name);
47struct parameter_list *np_find_parameter(struct parameter_list *list, const char *name);
48struct parameter_list *np_del_parameter(struct parameter_list *item, struct parameter_list *prev);
49
50int search_parameter_list (struct parameter_list *list, const char *name);
51void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount_list, bool exact);
52bool 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 23ee4a95..daae1d54 100644
--- a/lib/utils_tcp.c
+++ b/lib/utils_tcp.c
@@ -1,51 +1,46 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Library for check_tcp 3 * Library for check_tcp
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2013 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 utilities for check_tcp. These are tested by libtap 10 * This file contains utilities for check_tcp. These are tested by libtap
11* 11 *
12* 12 *
13* This program is free software: you can redistribute it and/or modify 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 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 15 * the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16 * (at your option) any later version.
17* 17 *
18* This program is distributed in the hope that it will be useful, 18 * This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21 * GNU General Public License for more details.
22* 22 *
23* You should have received a copy of the GNU General Public License 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/>. 24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25 *
26* 26 *
27*****************************************************************************/ 27 *****************************************************************************/
28 28
29#include "common.h" 29#include "common.h"
30#include "utils_tcp.h" 30#include "utils_tcp.h"
31 31
32#define VERBOSE(message) \ 32#define VERBOSE(message) \
33 do { \ 33 do { \
34 if (flags & NP_MATCH_VERBOSE) \ 34 if (flags & NP_MATCH_VERBOSE) \
35 puts(message); \ 35 puts(message); \
36 } while (0) 36 } while (0)
37 37
38enum np_match_result 38enum np_match_result np_expect_match(char *status, char **server_expect, int expect_count, int flags) {
39np_expect_match(char *status, char **server_expect, int expect_count, int flags)
40{
41 int i, match = 0, partial = 0; 39 int i, match = 0, partial = 0;
42 40
43 for (i = 0; i < expect_count; i++) { 41 for (i = 0; i < expect_count; i++) {
44 if (flags & NP_MATCH_VERBOSE) 42 if (flags & NP_MATCH_VERBOSE)
45 printf("looking for [%s] %s [%s]\n", server_expect[i], 43 printf("looking for [%s] %s [%s]\n", server_expect[i], (flags & NP_MATCH_EXACT) ? "in beginning of" : "anywhere in", status);
46 (flags & NP_MATCH_EXACT) ?
47 "in beginning of" : "anywhere in",
48 status);
49 44
50 if (flags & NP_MATCH_EXACT) { 45 if (flags & NP_MATCH_EXACT) {
51 if (strncmp(status, server_expect[i], strlen(server_expect[i])) == 0) { 46 if (strncmp(status, server_expect[i], strlen(server_expect[i])) == 0) {
@@ -58,15 +53,14 @@ np_expect_match(char *status, char **server_expect, int expect_count, int flags)
58 continue; 53 continue;
59 } 54 }
60 } else if (strstr(status, server_expect[i]) != NULL) { 55 } else if (strstr(status, server_expect[i]) != NULL) {
61 VERBOSE("found it"); 56 VERBOSE("found it");
62 match++; 57 match++;
63 continue; 58 continue;
64 } 59 }
65 VERBOSE("couldn't find it"); 60 VERBOSE("couldn't find it");
66 } 61 }
67 62
68 if ((flags & NP_MATCH_ALL && match == expect_count) || 63 if ((flags & NP_MATCH_ALL && match == expect_count) || (!(flags & NP_MATCH_ALL) && match >= 1))
69 (!(flags & NP_MATCH_ALL) && match >= 1))
70 return NP_MATCH_SUCCESS; 64 return NP_MATCH_SUCCESS;
71 else if (partial > 0 || !(flags & NP_MATCH_EXACT)) 65 else if (partial > 0 || !(flags & NP_MATCH_EXACT))
72 return NP_MATCH_RETRY; 66 return NP_MATCH_RETRY;
diff --git a/lib/utils_tcp.h b/lib/utils_tcp.h
index 0328a9cf..a7d83c59 100644
--- a/lib/utils_tcp.h
+++ b/lib/utils_tcp.h
@@ -1,8 +1,8 @@
1/* Header file for utils_tcp */ 1/* Header file for utils_tcp */
2 2
3#define NP_MATCH_ALL 0x1 3#define NP_MATCH_ALL 0x1
4#define NP_MATCH_EXACT 0x2 4#define NP_MATCH_EXACT 0x2
5#define NP_MATCH_VERBOSE 0x4 5#define NP_MATCH_VERBOSE 0x4
6 6
7/* 7/*
8 * The NP_MATCH_RETRY state indicates that matching might succeed if 8 * The NP_MATCH_RETRY state indicates that matching might succeed if
@@ -11,12 +11,10 @@
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, 20enum np_match_result np_expect_match(char *status, char **server_expect, int server_expect_count, int flags);
20 char **server_expect,
21 int server_expect_count,
22 int flags);
diff --git a/lib/vendor/cJSON/cJSON.c b/lib/vendor/cJSON/cJSON.c
new file mode 100644
index 00000000..12076e92
--- /dev/null
+++ b/lib/vendor/cJSON/cJSON.c
@@ -0,0 +1,3165 @@
1/*
2 Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21*/
22
23/* cJSON */
24/* JSON parser in C. */
25
26/* disable warnings about old C89 functions in MSVC */
27#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
28#define _CRT_SECURE_NO_DEPRECATE
29#endif
30
31#ifdef __GNUC__
32#pragma GCC visibility push(default)
33#endif
34#if defined(_MSC_VER)
35#pragma warning (push)
36/* disable warning about single line comments in system headers */
37#pragma warning (disable : 4001)
38#endif
39
40#include "../../../config.h"
41#include <string.h>
42#include <stdio.h>
43#include <math.h>
44#include <stdlib.h>
45#include <limits.h>
46#include <ctype.h>
47#include <float.h>
48
49#ifdef ENABLE_LOCALES
50#include <locale.h>
51#endif
52
53#if defined(_MSC_VER)
54#pragma warning (pop)
55#endif
56#ifdef __GNUC__
57#pragma GCC visibility pop
58#endif
59
60#include "cJSON.h"
61
62/* define our own boolean type */
63#ifdef true
64#undef true
65#endif
66#define true ((cJSON_bool)1)
67
68#ifdef false
69#undef false
70#endif
71#define false ((cJSON_bool)0)
72
73/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */
74#ifndef isinf
75#define isinf(d) (isnan((d - d)) && !isnan(d))
76#endif
77#ifndef isnan
78#define isnan(d) (d != d)
79#endif
80
81#ifndef NAN
82#ifdef _WIN32
83#define NAN sqrt(-1.0)
84#else
85#define NAN 0.0/0.0
86#endif
87#endif
88
89typedef struct {
90 const unsigned char *json;
91 size_t position;
92} error;
93static error global_error = { NULL, 0 };
94
95CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
96{
97 return (const char*) (global_error.json + global_error.position);
98}
99
100CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item)
101{
102 if (!cJSON_IsString(item))
103 {
104 return NULL;
105 }
106
107 return item->valuestring;
108}
109
110CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item)
111{
112 if (!cJSON_IsNumber(item))
113 {
114 return (double) NAN;
115 }
116
117 return item->valuedouble;
118}
119
120/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
121#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 18)
122 #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
123#endif
124
125CJSON_PUBLIC(const char*) cJSON_Version(void)
126{
127 static char version[15];
128 sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
129
130 return version;
131}
132
133/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */
134static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2)
135{
136 if ((string1 == NULL) || (string2 == NULL))
137 {
138 return 1;
139 }
140
141 if (string1 == string2)
142 {
143 return 0;
144 }
145
146 for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
147 {
148 if (*string1 == '\0')
149 {
150 return 0;
151 }
152 }
153
154 return tolower(*string1) - tolower(*string2);
155}
156
157typedef struct internal_hooks
158{
159 void *(CJSON_CDECL *allocate)(size_t size);
160 void (CJSON_CDECL *deallocate)(void *pointer);
161 void *(CJSON_CDECL *reallocate)(void *pointer, size_t size);
162} internal_hooks;
163
164#if defined(_MSC_VER)
165/* work around MSVC error C2322: '...' address of dllimport '...' is not static */
166static void * CJSON_CDECL internal_malloc(size_t size)
167{
168 return malloc(size);
169}
170static void CJSON_CDECL internal_free(void *pointer)
171{
172 free(pointer);
173}
174static void * CJSON_CDECL internal_realloc(void *pointer, size_t size)
175{
176 return realloc(pointer, size);
177}
178#else
179#define internal_malloc malloc
180#define internal_free free
181#define internal_realloc realloc
182#endif
183
184/* strlen of character literals resolved at compile time */
185#define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
186
187static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc };
188
189static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
190{
191 size_t length = 0;
192 unsigned char *copy = NULL;
193
194 if (string == NULL)
195 {
196 return NULL;
197 }
198
199 length = strlen((const char*)string) + sizeof("");
200 copy = (unsigned char*)hooks->allocate(length);
201 if (copy == NULL)
202 {
203 return NULL;
204 }
205 memcpy(copy, string, length);
206
207 return copy;
208}
209
210CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
211{
212 if (hooks == NULL)
213 {
214 /* Reset hooks */
215 global_hooks.allocate = malloc;
216 global_hooks.deallocate = free;
217 global_hooks.reallocate = realloc;
218 return;
219 }
220
221 global_hooks.allocate = malloc;
222 if (hooks->malloc_fn != NULL)
223 {
224 global_hooks.allocate = hooks->malloc_fn;
225 }
226
227 global_hooks.deallocate = free;
228 if (hooks->free_fn != NULL)
229 {
230 global_hooks.deallocate = hooks->free_fn;
231 }
232
233 /* use realloc only if both free and malloc are used */
234 global_hooks.reallocate = NULL;
235 if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))
236 {
237 global_hooks.reallocate = realloc;
238 }
239}
240
241/* Internal constructor. */
242static cJSON *cJSON_New_Item(const internal_hooks * const hooks)
243{
244 cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
245 if (node)
246 {
247 memset(node, '\0', sizeof(cJSON));
248 }
249
250 return node;
251}
252
253/* Delete a cJSON structure. */
254CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
255{
256 cJSON *next = NULL;
257 while (item != NULL)
258 {
259 next = item->next;
260 if (!(item->type & cJSON_IsReference) && (item->child != NULL))
261 {
262 cJSON_Delete(item->child);
263 }
264 if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
265 {
266 global_hooks.deallocate(item->valuestring);
267 item->valuestring = NULL;
268 }
269 if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
270 {
271 global_hooks.deallocate(item->string);
272 item->string = NULL;
273 }
274 global_hooks.deallocate(item);
275 item = next;
276 }
277}
278
279/* get the decimal point character of the current locale */
280static unsigned char get_decimal_point(void)
281{
282#ifdef ENABLE_LOCALES
283 struct lconv *lconv = localeconv();
284 return (unsigned char) lconv->decimal_point[0];
285#else
286 return '.';
287#endif
288}
289
290typedef struct
291{
292 const unsigned char *content;
293 size_t length;
294 size_t offset;
295 size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
296 internal_hooks hooks;
297} parse_buffer;
298
299/* check if the given size is left to read in a given parse buffer (starting with 1) */
300#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
301/* check if the buffer can be accessed at the given index (starting with 0) */
302#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
303#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
304/* get a pointer to the buffer at the position */
305#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
306
307/* Parse the input text to generate a number, and populate the result into item. */
308static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
309{
310 double number = 0;
311 unsigned char *after_end = NULL;
312 unsigned char number_c_string[64];
313 unsigned char decimal_point = get_decimal_point();
314 size_t i = 0;
315
316 if ((input_buffer == NULL) || (input_buffer->content == NULL))
317 {
318 return false;
319 }
320
321 /* copy the number into a temporary buffer and replace '.' with the decimal point
322 * of the current locale (for strtod)
323 * This also takes care of '\0' not necessarily being available for marking the end of the input */
324 for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
325 {
326 switch (buffer_at_offset(input_buffer)[i])
327 {
328 case '0':
329 case '1':
330 case '2':
331 case '3':
332 case '4':
333 case '5':
334 case '6':
335 case '7':
336 case '8':
337 case '9':
338 case '+':
339 case '-':
340 case 'e':
341 case 'E':
342 number_c_string[i] = buffer_at_offset(input_buffer)[i];
343 break;
344
345 case '.':
346 number_c_string[i] = decimal_point;
347 break;
348
349 default:
350 goto loop_end;
351 }
352 }
353loop_end:
354 number_c_string[i] = '\0';
355
356 number = strtod((const char*)number_c_string, (char**)&after_end);
357 if (number_c_string == after_end)
358 {
359 return false; /* parse_error */
360 }
361
362 item->valuedouble = number;
363
364 /* use saturation in case of overflow */
365 if (number >= INT_MAX)
366 {
367 item->valueint = INT_MAX;
368 }
369 else if (number <= (double)INT_MIN)
370 {
371 item->valueint = INT_MIN;
372 }
373 else
374 {
375 item->valueint = (int)number;
376 }
377
378 item->type = cJSON_Number;
379
380 input_buffer->offset += (size_t)(after_end - number_c_string);
381 return true;
382}
383
384/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
385CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
386{
387 if (number >= INT_MAX)
388 {
389 object->valueint = INT_MAX;
390 }
391 else if (number <= (double)INT_MIN)
392 {
393 object->valueint = INT_MIN;
394 }
395 else
396 {
397 object->valueint = (int)number;
398 }
399
400 return object->valuedouble = number;
401}
402
403/* Note: when passing a NULL valuestring, cJSON_SetValuestring treats this as an error and return NULL */
404CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
405{
406 char *copy = NULL;
407 size_t v1_len;
408 size_t v2_len;
409 /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */
410 if ((object == NULL) || !(object->type & cJSON_String) || (object->type & cJSON_IsReference))
411 {
412 return NULL;
413 }
414 /* return NULL if the object is corrupted or valuestring is NULL */
415 if (object->valuestring == NULL || valuestring == NULL)
416 {
417 return NULL;
418 }
419
420 v1_len = strlen(valuestring);
421 v2_len = strlen(object->valuestring);
422
423 if (v1_len <= v2_len)
424 {
425 /* strcpy does not handle overlapping string: [X1, X2] [Y1, Y2] => X2 < Y1 or Y2 < X1 */
426 if (!( valuestring + v1_len < object->valuestring || object->valuestring + v2_len < valuestring ))
427 {
428 return NULL;
429 }
430 strcpy(object->valuestring, valuestring);
431 return object->valuestring;
432 }
433 copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks);
434 if (copy == NULL)
435 {
436 return NULL;
437 }
438 if (object->valuestring != NULL)
439 {
440 cJSON_free(object->valuestring);
441 }
442 object->valuestring = copy;
443
444 return copy;
445}
446
447typedef struct
448{
449 unsigned char *buffer;
450 size_t length;
451 size_t offset;
452 size_t depth; /* current nesting depth (for formatted printing) */
453 cJSON_bool noalloc;
454 cJSON_bool format; /* is this print a formatted print */
455 internal_hooks hooks;
456} printbuffer;
457
458/* realloc printbuffer if necessary to have at least "needed" bytes more */
459static unsigned char* ensure(printbuffer * const p, size_t needed)
460{
461 unsigned char *newbuffer = NULL;
462 size_t newsize = 0;
463
464 if ((p == NULL) || (p->buffer == NULL))
465 {
466 return NULL;
467 }
468
469 if ((p->length > 0) && (p->offset >= p->length))
470 {
471 /* make sure that offset is valid */
472 return NULL;
473 }
474
475 if (needed > INT_MAX)
476 {
477 /* sizes bigger than INT_MAX are currently not supported */
478 return NULL;
479 }
480
481 needed += p->offset + 1;
482 if (needed <= p->length)
483 {
484 return p->buffer + p->offset;
485 }
486
487 if (p->noalloc) {
488 return NULL;
489 }
490
491 /* calculate new buffer size */
492 if (needed > (INT_MAX / 2))
493 {
494 /* overflow of int, use INT_MAX if possible */
495 if (needed <= INT_MAX)
496 {
497 newsize = INT_MAX;
498 }
499 else
500 {
501 return NULL;
502 }
503 }
504 else
505 {
506 newsize = needed * 2;
507 }
508
509 if (p->hooks.reallocate != NULL)
510 {
511 /* reallocate with realloc if available */
512 newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);
513 if (newbuffer == NULL)
514 {
515 p->hooks.deallocate(p->buffer);
516 p->length = 0;
517 p->buffer = NULL;
518
519 return NULL;
520 }
521 }
522 else
523 {
524 /* otherwise reallocate manually */
525 newbuffer = (unsigned char*)p->hooks.allocate(newsize);
526 if (!newbuffer)
527 {
528 p->hooks.deallocate(p->buffer);
529 p->length = 0;
530 p->buffer = NULL;
531
532 return NULL;
533 }
534
535 memcpy(newbuffer, p->buffer, p->offset + 1);
536 p->hooks.deallocate(p->buffer);
537 }
538 p->length = newsize;
539 p->buffer = newbuffer;
540
541 return newbuffer + p->offset;
542}
543
544/* calculate the new length of the string in a printbuffer and update the offset */
545static void update_offset(printbuffer * const buffer)
546{
547 const unsigned char *buffer_pointer = NULL;
548 if ((buffer == NULL) || (buffer->buffer == NULL))
549 {
550 return;
551 }
552 buffer_pointer = buffer->buffer + buffer->offset;
553
554 buffer->offset += strlen((const char*)buffer_pointer);
555}
556
557/* securely comparison of floating-point variables */
558static cJSON_bool compare_double(double a, double b)
559{
560 double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
561 return (fabs(a - b) <= maxVal * DBL_EPSILON);
562}
563
564/* Render the number nicely from the given item into a string. */
565static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
566{
567 unsigned char *output_pointer = NULL;
568 double d = item->valuedouble;
569 int length = 0;
570 size_t i = 0;
571 unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */
572 unsigned char decimal_point = get_decimal_point();
573 double test = 0.0;
574
575 if (output_buffer == NULL)
576 {
577 return false;
578 }
579
580 /* This checks for NaN and Infinity */
581 if (isnan(d) || isinf(d))
582 {
583 length = sprintf((char*)number_buffer, "null");
584 }
585 else if(d == (double)item->valueint)
586 {
587 length = sprintf((char*)number_buffer, "%d", item->valueint);
588 }
589 else
590 {
591 /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
592 length = sprintf((char*)number_buffer, "%1.15g", d);
593
594 /* Check whether the original double can be recovered */
595 if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d))
596 {
597 /* If not, print with 17 decimal places of precision */
598 length = sprintf((char*)number_buffer, "%1.17g", d);
599 }
600 }
601
602 /* sprintf failed or buffer overrun occurred */
603 if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
604 {
605 return false;
606 }
607
608 /* reserve appropriate space in the output */
609 output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
610 if (output_pointer == NULL)
611 {
612 return false;
613 }
614
615 /* copy the printed number to the output and replace locale
616 * dependent decimal point with '.' */
617 for (i = 0; i < ((size_t)length); i++)
618 {
619 if (number_buffer[i] == decimal_point)
620 {
621 output_pointer[i] = '.';
622 continue;
623 }
624
625 output_pointer[i] = number_buffer[i];
626 }
627 output_pointer[i] = '\0';
628
629 output_buffer->offset += (size_t)length;
630
631 return true;
632}
633
634/* parse 4 digit hexadecimal number */
635static unsigned parse_hex4(const unsigned char * const input)
636{
637 unsigned int h = 0;
638 size_t i = 0;
639
640 for (i = 0; i < 4; i++)
641 {
642 /* parse digit */
643 if ((input[i] >= '0') && (input[i] <= '9'))
644 {
645 h += (unsigned int) input[i] - '0';
646 }
647 else if ((input[i] >= 'A') && (input[i] <= 'F'))
648 {
649 h += (unsigned int) 10 + input[i] - 'A';
650 }
651 else if ((input[i] >= 'a') && (input[i] <= 'f'))
652 {
653 h += (unsigned int) 10 + input[i] - 'a';
654 }
655 else /* invalid */
656 {
657 return 0;
658 }
659
660 if (i < 3)
661 {
662 /* shift left to make place for the next nibble */
663 h = h << 4;
664 }
665 }
666
667 return h;
668}
669
670/* converts a UTF-16 literal to UTF-8
671 * A literal can be one or two sequences of the form \uXXXX */
672static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer)
673{
674 long unsigned int codepoint = 0;
675 unsigned int first_code = 0;
676 const unsigned char *first_sequence = input_pointer;
677 unsigned char utf8_length = 0;
678 unsigned char utf8_position = 0;
679 unsigned char sequence_length = 0;
680 unsigned char first_byte_mark = 0;
681
682 if ((input_end - first_sequence) < 6)
683 {
684 /* input ends unexpectedly */
685 goto fail;
686 }
687
688 /* get the first utf16 sequence */
689 first_code = parse_hex4(first_sequence + 2);
690
691 /* check that the code is valid */
692 if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))
693 {
694 goto fail;
695 }
696
697 /* UTF16 surrogate pair */
698 if ((first_code >= 0xD800) && (first_code <= 0xDBFF))
699 {
700 const unsigned char *second_sequence = first_sequence + 6;
701 unsigned int second_code = 0;
702 sequence_length = 12; /* \uXXXX\uXXXX */
703
704 if ((input_end - second_sequence) < 6)
705 {
706 /* input ends unexpectedly */
707 goto fail;
708 }
709
710 if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u'))
711 {
712 /* missing second half of the surrogate pair */
713 goto fail;
714 }
715
716 /* get the second utf16 sequence */
717 second_code = parse_hex4(second_sequence + 2);
718 /* check that the code is valid */
719 if ((second_code < 0xDC00) || (second_code > 0xDFFF))
720 {
721 /* invalid second half of the surrogate pair */
722 goto fail;
723 }
724
725
726 /* calculate the unicode codepoint from the surrogate pair */
727 codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
728 }
729 else
730 {
731 sequence_length = 6; /* \uXXXX */
732 codepoint = first_code;
733 }
734
735 /* encode as UTF-8
736 * takes at maximum 4 bytes to encode:
737 * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
738 if (codepoint < 0x80)
739 {
740 /* normal ascii, encoding 0xxxxxxx */
741 utf8_length = 1;
742 }
743 else if (codepoint < 0x800)
744 {
745 /* two bytes, encoding 110xxxxx 10xxxxxx */
746 utf8_length = 2;
747 first_byte_mark = 0xC0; /* 11000000 */
748 }
749 else if (codepoint < 0x10000)
750 {
751 /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
752 utf8_length = 3;
753 first_byte_mark = 0xE0; /* 11100000 */
754 }
755 else if (codepoint <= 0x10FFFF)
756 {
757 /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
758 utf8_length = 4;
759 first_byte_mark = 0xF0; /* 11110000 */
760 }
761 else
762 {
763 /* invalid unicode codepoint */
764 goto fail;
765 }
766
767 /* encode as utf8 */
768 for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)
769 {
770 /* 10xxxxxx */
771 (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
772 codepoint >>= 6;
773 }
774 /* encode first byte */
775 if (utf8_length > 1)
776 {
777 (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
778 }
779 else
780 {
781 (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
782 }
783
784 *output_pointer += utf8_length;
785
786 return sequence_length;
787
788fail:
789 return 0;
790}
791
792/* Parse the input text into an unescaped cinput, and populate item. */
793static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer)
794{
795 const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
796 const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
797 unsigned char *output_pointer = NULL;
798 unsigned char *output = NULL;
799
800 /* not a string */
801 if (buffer_at_offset(input_buffer)[0] != '\"')
802 {
803 goto fail;
804 }
805
806 {
807 /* calculate approximate size of the output (overestimate) */
808 size_t allocation_length = 0;
809 size_t skipped_bytes = 0;
810 while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"'))
811 {
812 /* is escape sequence */
813 if (input_end[0] == '\\')
814 {
815 if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
816 {
817 /* prevent buffer overflow when last input character is a backslash */
818 goto fail;
819 }
820 skipped_bytes++;
821 input_end++;
822 }
823 input_end++;
824 }
825 if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"'))
826 {
827 goto fail; /* string ended unexpectedly */
828 }
829
830 /* This is at most how much we need for the output */
831 allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
832 output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(""));
833 if (output == NULL)
834 {
835 goto fail; /* allocation failure */
836 }
837 }
838
839 output_pointer = output;
840 /* loop through the string literal */
841 while (input_pointer < input_end)
842 {
843 if (*input_pointer != '\\')
844 {
845 *output_pointer++ = *input_pointer++;
846 }
847 /* escape sequence */
848 else
849 {
850 unsigned char sequence_length = 2;
851 if ((input_end - input_pointer) < 1)
852 {
853 goto fail;
854 }
855
856 switch (input_pointer[1])
857 {
858 case 'b':
859 *output_pointer++ = '\b';
860 break;
861 case 'f':
862 *output_pointer++ = '\f';
863 break;
864 case 'n':
865 *output_pointer++ = '\n';
866 break;
867 case 'r':
868 *output_pointer++ = '\r';
869 break;
870 case 't':
871 *output_pointer++ = '\t';
872 break;
873 case '\"':
874 case '\\':
875 case '/':
876 *output_pointer++ = input_pointer[1];
877 break;
878
879 /* UTF-16 literal */
880 case 'u':
881 sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
882 if (sequence_length == 0)
883 {
884 /* failed to convert UTF16-literal to UTF-8 */
885 goto fail;
886 }
887 break;
888
889 default:
890 goto fail;
891 }
892 input_pointer += sequence_length;
893 }
894 }
895
896 /* zero terminate the output */
897 *output_pointer = '\0';
898
899 item->type = cJSON_String;
900 item->valuestring = (char*)output;
901
902 input_buffer->offset = (size_t) (input_end - input_buffer->content);
903 input_buffer->offset++;
904
905 return true;
906
907fail:
908 if (output != NULL)
909 {
910 input_buffer->hooks.deallocate(output);
911 output = NULL;
912 }
913
914 if (input_pointer != NULL)
915 {
916 input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
917 }
918
919 return false;
920}
921
922/* Render the cstring provided to an escaped version that can be printed. */
923static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
924{
925 const unsigned char *input_pointer = NULL;
926 unsigned char *output = NULL;
927 unsigned char *output_pointer = NULL;
928 size_t output_length = 0;
929 /* numbers of additional characters needed for escaping */
930 size_t escape_characters = 0;
931
932 if (output_buffer == NULL)
933 {
934 return false;
935 }
936
937 /* empty string */
938 if (input == NULL)
939 {
940 output = ensure(output_buffer, sizeof("\"\""));
941 if (output == NULL)
942 {
943 return false;
944 }
945 strcpy((char*)output, "\"\"");
946
947 return true;
948 }
949
950 /* set "flag" to 1 if something needs to be escaped */
951 for (input_pointer = input; *input_pointer; input_pointer++)
952 {
953 switch (*input_pointer)
954 {
955 case '\"':
956 case '\\':
957 case '\b':
958 case '\f':
959 case '\n':
960 case '\r':
961 case '\t':
962 /* one character escape sequence */
963 escape_characters++;
964 break;
965 default:
966 if (*input_pointer < 32)
967 {
968 /* UTF-16 escape sequence uXXXX */
969 escape_characters += 5;
970 }
971 break;
972 }
973 }
974 output_length = (size_t)(input_pointer - input) + escape_characters;
975
976 output = ensure(output_buffer, output_length + sizeof("\"\""));
977 if (output == NULL)
978 {
979 return false;
980 }
981
982 /* no characters have to be escaped */
983 if (escape_characters == 0)
984 {
985 output[0] = '\"';
986 memcpy(output + 1, input, output_length);
987 output[output_length + 1] = '\"';
988 output[output_length + 2] = '\0';
989
990 return true;
991 }
992
993 output[0] = '\"';
994 output_pointer = output + 1;
995 /* copy the string */
996 for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
997 {
998 if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
999 {
1000 /* normal character, copy */
1001 *output_pointer = *input_pointer;
1002 }
1003 else
1004 {
1005 /* character needs to be escaped */
1006 *output_pointer++ = '\\';
1007 switch (*input_pointer)
1008 {
1009 case '\\':
1010 *output_pointer = '\\';
1011 break;
1012 case '\"':
1013 *output_pointer = '\"';
1014 break;
1015 case '\b':
1016 *output_pointer = 'b';
1017 break;
1018 case '\f':
1019 *output_pointer = 'f';
1020 break;
1021 case '\n':
1022 *output_pointer = 'n';
1023 break;
1024 case '\r':
1025 *output_pointer = 'r';
1026 break;
1027 case '\t':
1028 *output_pointer = 't';
1029 break;
1030 default:
1031 /* escape and print as unicode codepoint */
1032 sprintf((char*)output_pointer, "u%04x", *input_pointer);
1033 output_pointer += 4;
1034 break;
1035 }
1036 }
1037 }
1038 output[output_length + 1] = '\"';
1039 output[output_length + 2] = '\0';
1040
1041 return true;
1042}
1043
1044/* Invoke print_string_ptr (which is useful) on an item. */
1045static cJSON_bool print_string(const cJSON * const item, printbuffer * const p)
1046{
1047 return print_string_ptr((unsigned char*)item->valuestring, p);
1048}
1049
1050/* Predeclare these prototypes. */
1051static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer);
1052static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer);
1053static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer);
1054static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer);
1055static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer);
1056static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer);
1057
1058/* Utility to jump whitespace and cr/lf */
1059static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
1060{
1061 if ((buffer == NULL) || (buffer->content == NULL))
1062 {
1063 return NULL;
1064 }
1065
1066 if (cannot_access_at_index(buffer, 0))
1067 {
1068 return buffer;
1069 }
1070
1071 while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
1072 {
1073 buffer->offset++;
1074 }
1075
1076 if (buffer->offset == buffer->length)
1077 {
1078 buffer->offset--;
1079 }
1080
1081 return buffer;
1082}
1083
1084/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
1085static parse_buffer *skip_utf8_bom(parse_buffer * const buffer)
1086{
1087 if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0))
1088 {
1089 return NULL;
1090 }
1091
1092 if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0))
1093 {
1094 buffer->offset += 3;
1095 }
1096
1097 return buffer;
1098}
1099
1100CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
1101{
1102 size_t buffer_length;
1103
1104 if (NULL == value)
1105 {
1106 return NULL;
1107 }
1108
1109 /* Adding null character size due to require_null_terminated. */
1110 buffer_length = strlen(value) + sizeof("");
1111
1112 return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated);
1113}
1114
1115/* Parse an object - create a new root, and populate. */
1116CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated)
1117{
1118 parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
1119 cJSON *item = NULL;
1120
1121 /* reset error position */
1122 global_error.json = NULL;
1123 global_error.position = 0;
1124
1125 if (value == NULL || 0 == buffer_length)
1126 {
1127 goto fail;
1128 }
1129
1130 buffer.content = (const unsigned char*)value;
1131 buffer.length = buffer_length;
1132 buffer.offset = 0;
1133 buffer.hooks = global_hooks;
1134
1135 item = cJSON_New_Item(&global_hooks);
1136 if (item == NULL) /* memory fail */
1137 {
1138 goto fail;
1139 }
1140
1141 if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer))))
1142 {
1143 /* parse failure. ep is set. */
1144 goto fail;
1145 }
1146
1147 /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
1148 if (require_null_terminated)
1149 {
1150 buffer_skip_whitespace(&buffer);
1151 if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0')
1152 {
1153 goto fail;
1154 }
1155 }
1156 if (return_parse_end)
1157 {
1158 *return_parse_end = (const char*)buffer_at_offset(&buffer);
1159 }
1160
1161 return item;
1162
1163fail:
1164 if (item != NULL)
1165 {
1166 cJSON_Delete(item);
1167 }
1168
1169 if (value != NULL)
1170 {
1171 error local_error;
1172 local_error.json = (const unsigned char*)value;
1173 local_error.position = 0;
1174
1175 if (buffer.offset < buffer.length)
1176 {
1177 local_error.position = buffer.offset;
1178 }
1179 else if (buffer.length > 0)
1180 {
1181 local_error.position = buffer.length - 1;
1182 }
1183
1184 if (return_parse_end != NULL)
1185 {
1186 *return_parse_end = (const char*)local_error.json + local_error.position;
1187 }
1188
1189 global_error = local_error;
1190 }
1191
1192 return NULL;
1193}
1194
1195/* Default options for cJSON_Parse */
1196CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
1197{
1198 return cJSON_ParseWithOpts(value, 0, 0);
1199}
1200
1201CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length)
1202{
1203 return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0);
1204}
1205
1206#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
1207
1208static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
1209{
1210 static const size_t default_buffer_size = 256;
1211 printbuffer buffer[1];
1212 unsigned char *printed = NULL;
1213
1214 memset(buffer, 0, sizeof(buffer));
1215
1216 /* create buffer */
1217 buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size);
1218 buffer->length = default_buffer_size;
1219 buffer->format = format;
1220 buffer->hooks = *hooks;
1221 if (buffer->buffer == NULL)
1222 {
1223 goto fail;
1224 }
1225
1226 /* print the value */
1227 if (!print_value(item, buffer))
1228 {
1229 goto fail;
1230 }
1231 update_offset(buffer);
1232
1233 /* check if reallocate is available */
1234 if (hooks->reallocate != NULL)
1235 {
1236 printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1);
1237 if (printed == NULL) {
1238 goto fail;
1239 }
1240 buffer->buffer = NULL;
1241 }
1242 else /* otherwise copy the JSON over to a new buffer */
1243 {
1244 printed = (unsigned char*) hooks->allocate(buffer->offset + 1);
1245 if (printed == NULL)
1246 {
1247 goto fail;
1248 }
1249 memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
1250 printed[buffer->offset] = '\0'; /* just to be sure */
1251
1252 /* free the buffer */
1253 hooks->deallocate(buffer->buffer);
1254 buffer->buffer = NULL;
1255 }
1256
1257 return printed;
1258
1259fail:
1260 if (buffer->buffer != NULL)
1261 {
1262 hooks->deallocate(buffer->buffer);
1263 buffer->buffer = NULL;
1264 }
1265
1266 if (printed != NULL)
1267 {
1268 hooks->deallocate(printed);
1269 printed = NULL;
1270 }
1271
1272 return NULL;
1273}
1274
1275/* Render a cJSON item/entity/structure to text. */
1276CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item)
1277{
1278 return (char*)print(item, true, &global_hooks);
1279}
1280
1281CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item)
1282{
1283 return (char*)print(item, false, &global_hooks);
1284}
1285
1286CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
1287{
1288 printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
1289
1290 if (prebuffer < 0)
1291 {
1292 return NULL;
1293 }
1294
1295 p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer);
1296 if (!p.buffer)
1297 {
1298 return NULL;
1299 }
1300
1301 p.length = (size_t)prebuffer;
1302 p.offset = 0;
1303 p.noalloc = false;
1304 p.format = fmt;
1305 p.hooks = global_hooks;
1306
1307 if (!print_value(item, &p))
1308 {
1309 global_hooks.deallocate(p.buffer);
1310 p.buffer = NULL;
1311 return NULL;
1312 }
1313
1314 return (char*)p.buffer;
1315}
1316
1317CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)
1318{
1319 printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
1320
1321 if ((length < 0) || (buffer == NULL))
1322 {
1323 return false;
1324 }
1325
1326 p.buffer = (unsigned char*)buffer;
1327 p.length = (size_t)length;
1328 p.offset = 0;
1329 p.noalloc = true;
1330 p.format = format;
1331 p.hooks = global_hooks;
1332
1333 return print_value(item, &p);
1334}
1335
1336/* Parser core - when encountering text, process appropriately. */
1337static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer)
1338{
1339 if ((input_buffer == NULL) || (input_buffer->content == NULL))
1340 {
1341 return false; /* no input */
1342 }
1343
1344 /* parse the different types of values */
1345 /* null */
1346 if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
1347 {
1348 item->type = cJSON_NULL;
1349 input_buffer->offset += 4;
1350 return true;
1351 }
1352 /* false */
1353 if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
1354 {
1355 item->type = cJSON_False;
1356 input_buffer->offset += 5;
1357 return true;
1358 }
1359 /* true */
1360 if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
1361 {
1362 item->type = cJSON_True;
1363 item->valueint = 1;
1364 input_buffer->offset += 4;
1365 return true;
1366 }
1367 /* string */
1368 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
1369 {
1370 return parse_string(item, input_buffer);
1371 }
1372 /* number */
1373 if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9'))))
1374 {
1375 return parse_number(item, input_buffer);
1376 }
1377 /* array */
1378 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
1379 {
1380 return parse_array(item, input_buffer);
1381 }
1382 /* object */
1383 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
1384 {
1385 return parse_object(item, input_buffer);
1386 }
1387
1388 return false;
1389}
1390
1391/* Render a value to text. */
1392static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer)
1393{
1394 unsigned char *output = NULL;
1395
1396 if ((item == NULL) || (output_buffer == NULL))
1397 {
1398 return false;
1399 }
1400
1401 switch ((item->type) & 0xFF)
1402 {
1403 case cJSON_NULL:
1404 output = ensure(output_buffer, 5);
1405 if (output == NULL)
1406 {
1407 return false;
1408 }
1409 strcpy((char*)output, "null");
1410 return true;
1411
1412 case cJSON_False:
1413 output = ensure(output_buffer, 6);
1414 if (output == NULL)
1415 {
1416 return false;
1417 }
1418 strcpy((char*)output, "false");
1419 return true;
1420
1421 case cJSON_True:
1422 output = ensure(output_buffer, 5);
1423 if (output == NULL)
1424 {
1425 return false;
1426 }
1427 strcpy((char*)output, "true");
1428 return true;
1429
1430 case cJSON_Number:
1431 return print_number(item, output_buffer);
1432
1433 case cJSON_Raw:
1434 {
1435 size_t raw_length = 0;
1436 if (item->valuestring == NULL)
1437 {
1438 return false;
1439 }
1440
1441 raw_length = strlen(item->valuestring) + sizeof("");
1442 output = ensure(output_buffer, raw_length);
1443 if (output == NULL)
1444 {
1445 return false;
1446 }
1447 memcpy(output, item->valuestring, raw_length);
1448 return true;
1449 }
1450
1451 case cJSON_String:
1452 return print_string(item, output_buffer);
1453
1454 case cJSON_Array:
1455 return print_array(item, output_buffer);
1456
1457 case cJSON_Object:
1458 return print_object(item, output_buffer);
1459
1460 default:
1461 return false;
1462 }
1463}
1464
1465/* Build an array from input text. */
1466static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer)
1467{
1468 cJSON *head = NULL; /* head of the linked list */
1469 cJSON *current_item = NULL;
1470
1471 if (input_buffer->depth >= CJSON_NESTING_LIMIT)
1472 {
1473 return false; /* to deeply nested */
1474 }
1475 input_buffer->depth++;
1476
1477 if (buffer_at_offset(input_buffer)[0] != '[')
1478 {
1479 /* not an array */
1480 goto fail;
1481 }
1482
1483 input_buffer->offset++;
1484 buffer_skip_whitespace(input_buffer);
1485 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
1486 {
1487 /* empty array */
1488 goto success;
1489 }
1490
1491 /* check if we skipped to the end of the buffer */
1492 if (cannot_access_at_index(input_buffer, 0))
1493 {
1494 input_buffer->offset--;
1495 goto fail;
1496 }
1497
1498 /* step back to character in front of the first element */
1499 input_buffer->offset--;
1500 /* loop through the comma separated array elements */
1501 do
1502 {
1503 /* allocate next item */
1504 cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
1505 if (new_item == NULL)
1506 {
1507 goto fail; /* allocation failure */
1508 }
1509
1510 /* attach next item to list */
1511 if (head == NULL)
1512 {
1513 /* start the linked list */
1514 current_item = head = new_item;
1515 }
1516 else
1517 {
1518 /* add to the end and advance */
1519 current_item->next = new_item;
1520 new_item->prev = current_item;
1521 current_item = new_item;
1522 }
1523
1524 /* parse next value */
1525 input_buffer->offset++;
1526 buffer_skip_whitespace(input_buffer);
1527 if (!parse_value(current_item, input_buffer))
1528 {
1529 goto fail; /* failed to parse value */
1530 }
1531 buffer_skip_whitespace(input_buffer);
1532 }
1533 while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1534
1535 if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
1536 {
1537 goto fail; /* expected end of array */
1538 }
1539
1540success:
1541 input_buffer->depth--;
1542
1543 if (head != NULL) {
1544 head->prev = current_item;
1545 }
1546
1547 item->type = cJSON_Array;
1548 item->child = head;
1549
1550 input_buffer->offset++;
1551
1552 return true;
1553
1554fail:
1555 if (head != NULL)
1556 {
1557 cJSON_Delete(head);
1558 }
1559
1560 return false;
1561}
1562
1563/* Render an array to text */
1564static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer)
1565{
1566 unsigned char *output_pointer = NULL;
1567 size_t length = 0;
1568 cJSON *current_element = item->child;
1569
1570 if (output_buffer == NULL)
1571 {
1572 return false;
1573 }
1574
1575 /* Compose the output array. */
1576 /* opening square bracket */
1577 output_pointer = ensure(output_buffer, 1);
1578 if (output_pointer == NULL)
1579 {
1580 return false;
1581 }
1582
1583 *output_pointer = '[';
1584 output_buffer->offset++;
1585 output_buffer->depth++;
1586
1587 while (current_element != NULL)
1588 {
1589 if (!print_value(current_element, output_buffer))
1590 {
1591 return false;
1592 }
1593 update_offset(output_buffer);
1594 if (current_element->next)
1595 {
1596 length = (size_t) (output_buffer->format ? 2 : 1);
1597 output_pointer = ensure(output_buffer, length + 1);
1598 if (output_pointer == NULL)
1599 {
1600 return false;
1601 }
1602 *output_pointer++ = ',';
1603 if(output_buffer->format)
1604 {
1605 *output_pointer++ = ' ';
1606 }
1607 *output_pointer = '\0';
1608 output_buffer->offset += length;
1609 }
1610 current_element = current_element->next;
1611 }
1612
1613 output_pointer = ensure(output_buffer, 2);
1614 if (output_pointer == NULL)
1615 {
1616 return false;
1617 }
1618 *output_pointer++ = ']';
1619 *output_pointer = '\0';
1620 output_buffer->depth--;
1621
1622 return true;
1623}
1624
1625/* Build an object from the text. */
1626static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer)
1627{
1628 cJSON *head = NULL; /* linked list head */
1629 cJSON *current_item = NULL;
1630
1631 if (input_buffer->depth >= CJSON_NESTING_LIMIT)
1632 {
1633 return false; /* to deeply nested */
1634 }
1635 input_buffer->depth++;
1636
1637 if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
1638 {
1639 goto fail; /* not an object */
1640 }
1641
1642 input_buffer->offset++;
1643 buffer_skip_whitespace(input_buffer);
1644 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
1645 {
1646 goto success; /* empty object */
1647 }
1648
1649 /* check if we skipped to the end of the buffer */
1650 if (cannot_access_at_index(input_buffer, 0))
1651 {
1652 input_buffer->offset--;
1653 goto fail;
1654 }
1655
1656 /* step back to character in front of the first element */
1657 input_buffer->offset--;
1658 /* loop through the comma separated array elements */
1659 do
1660 {
1661 /* allocate next item */
1662 cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
1663 if (new_item == NULL)
1664 {
1665 goto fail; /* allocation failure */
1666 }
1667
1668 /* attach next item to list */
1669 if (head == NULL)
1670 {
1671 /* start the linked list */
1672 current_item = head = new_item;
1673 }
1674 else
1675 {
1676 /* add to the end and advance */
1677 current_item->next = new_item;
1678 new_item->prev = current_item;
1679 current_item = new_item;
1680 }
1681
1682 if (cannot_access_at_index(input_buffer, 1))
1683 {
1684 goto fail; /* nothing comes after the comma */
1685 }
1686
1687 /* parse the name of the child */
1688 input_buffer->offset++;
1689 buffer_skip_whitespace(input_buffer);
1690 if (!parse_string(current_item, input_buffer))
1691 {
1692 goto fail; /* failed to parse name */
1693 }
1694 buffer_skip_whitespace(input_buffer);
1695
1696 /* swap valuestring and string, because we parsed the name */
1697 current_item->string = current_item->valuestring;
1698 current_item->valuestring = NULL;
1699
1700 if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
1701 {
1702 goto fail; /* invalid object */
1703 }
1704
1705 /* parse the value */
1706 input_buffer->offset++;
1707 buffer_skip_whitespace(input_buffer);
1708 if (!parse_value(current_item, input_buffer))
1709 {
1710 goto fail; /* failed to parse value */
1711 }
1712 buffer_skip_whitespace(input_buffer);
1713 }
1714 while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
1715
1716 if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
1717 {
1718 goto fail; /* expected end of object */
1719 }
1720
1721success:
1722 input_buffer->depth--;
1723
1724 if (head != NULL) {
1725 head->prev = current_item;
1726 }
1727
1728 item->type = cJSON_Object;
1729 item->child = head;
1730
1731 input_buffer->offset++;
1732 return true;
1733
1734fail:
1735 if (head != NULL)
1736 {
1737 cJSON_Delete(head);
1738 }
1739
1740 return false;
1741}
1742
1743/* Render an object to text. */
1744static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer)
1745{
1746 unsigned char *output_pointer = NULL;
1747 size_t length = 0;
1748 cJSON *current_item = item->child;
1749
1750 if (output_buffer == NULL)
1751 {
1752 return false;
1753 }
1754
1755 /* Compose the output: */
1756 length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */
1757 output_pointer = ensure(output_buffer, length + 1);
1758 if (output_pointer == NULL)
1759 {
1760 return false;
1761 }
1762
1763 *output_pointer++ = '{';
1764 output_buffer->depth++;
1765 if (output_buffer->format)
1766 {
1767 *output_pointer++ = '\n';
1768 }
1769 output_buffer->offset += length;
1770
1771 while (current_item)
1772 {
1773 if (output_buffer->format)
1774 {
1775 size_t i;
1776 output_pointer = ensure(output_buffer, output_buffer->depth);
1777 if (output_pointer == NULL)
1778 {
1779 return false;
1780 }
1781 for (i = 0; i < output_buffer->depth; i++)
1782 {
1783 *output_pointer++ = '\t';
1784 }
1785 output_buffer->offset += output_buffer->depth;
1786 }
1787
1788 /* print key */
1789 if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
1790 {
1791 return false;
1792 }
1793 update_offset(output_buffer);
1794
1795 length = (size_t) (output_buffer->format ? 2 : 1);
1796 output_pointer = ensure(output_buffer, length);
1797 if (output_pointer == NULL)
1798 {
1799 return false;
1800 }
1801 *output_pointer++ = ':';
1802 if (output_buffer->format)
1803 {
1804 *output_pointer++ = '\t';
1805 }
1806 output_buffer->offset += length;
1807
1808 /* print value */
1809 if (!print_value(current_item, output_buffer))
1810 {
1811 return false;
1812 }
1813 update_offset(output_buffer);
1814
1815 /* print comma if not last */
1816 length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
1817 output_pointer = ensure(output_buffer, length + 1);
1818 if (output_pointer == NULL)
1819 {
1820 return false;
1821 }
1822 if (current_item->next)
1823 {
1824 *output_pointer++ = ',';
1825 }
1826
1827 if (output_buffer->format)
1828 {
1829 *output_pointer++ = '\n';
1830 }
1831 *output_pointer = '\0';
1832 output_buffer->offset += length;
1833
1834 current_item = current_item->next;
1835 }
1836
1837 output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
1838 if (output_pointer == NULL)
1839 {
1840 return false;
1841 }
1842 if (output_buffer->format)
1843 {
1844 size_t i;
1845 for (i = 0; i < (output_buffer->depth - 1); i++)
1846 {
1847 *output_pointer++ = '\t';
1848 }
1849 }
1850 *output_pointer++ = '}';
1851 *output_pointer = '\0';
1852 output_buffer->depth--;
1853
1854 return true;
1855}
1856
1857/* Get Array size/item / object item. */
1858CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
1859{
1860 cJSON *child = NULL;
1861 size_t size = 0;
1862
1863 if (array == NULL)
1864 {
1865 return 0;
1866 }
1867
1868 child = array->child;
1869
1870 while(child != NULL)
1871 {
1872 size++;
1873 child = child->next;
1874 }
1875
1876 /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
1877
1878 return (int)size;
1879}
1880
1881static cJSON* get_array_item(const cJSON *array, size_t index)
1882{
1883 cJSON *current_child = NULL;
1884
1885 if (array == NULL)
1886 {
1887 return NULL;
1888 }
1889
1890 current_child = array->child;
1891 while ((current_child != NULL) && (index > 0))
1892 {
1893 index--;
1894 current_child = current_child->next;
1895 }
1896
1897 return current_child;
1898}
1899
1900CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index)
1901{
1902 if (index < 0)
1903 {
1904 return NULL;
1905 }
1906
1907 return get_array_item(array, (size_t)index);
1908}
1909
1910static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive)
1911{
1912 cJSON *current_element = NULL;
1913
1914 if ((object == NULL) || (name == NULL))
1915 {
1916 return NULL;
1917 }
1918
1919 current_element = object->child;
1920 if (case_sensitive)
1921 {
1922 while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0))
1923 {
1924 current_element = current_element->next;
1925 }
1926 }
1927 else
1928 {
1929 while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0))
1930 {
1931 current_element = current_element->next;
1932 }
1933 }
1934
1935 if ((current_element == NULL) || (current_element->string == NULL)) {
1936 return NULL;
1937 }
1938
1939 return current_element;
1940}
1941
1942CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string)
1943{
1944 return get_object_item(object, string, false);
1945}
1946
1947CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string)
1948{
1949 return get_object_item(object, string, true);
1950}
1951
1952CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string)
1953{
1954 return cJSON_GetObjectItem(object, string) ? 1 : 0;
1955}
1956
1957/* Utility for array list handling. */
1958static void suffix_object(cJSON *prev, cJSON *item)
1959{
1960 prev->next = item;
1961 item->prev = prev;
1962}
1963
1964/* Utility for handling references. */
1965static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks)
1966{
1967 cJSON *reference = NULL;
1968 if (item == NULL)
1969 {
1970 return NULL;
1971 }
1972
1973 reference = cJSON_New_Item(hooks);
1974 if (reference == NULL)
1975 {
1976 return NULL;
1977 }
1978
1979 memcpy(reference, item, sizeof(cJSON));
1980 reference->string = NULL;
1981 reference->type |= cJSON_IsReference;
1982 reference->next = reference->prev = NULL;
1983 return reference;
1984}
1985
1986static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
1987{
1988 cJSON *child = NULL;
1989
1990 if ((item == NULL) || (array == NULL) || (array == item))
1991 {
1992 return false;
1993 }
1994
1995 child = array->child;
1996 /*
1997 * To find the last item in array quickly, we use prev in array
1998 */
1999 if (child == NULL)
2000 {
2001 /* list is empty, start new one */
2002 array->child = item;
2003 item->prev = item;
2004 item->next = NULL;
2005 }
2006 else
2007 {
2008 /* append to the end */
2009 if (child->prev)
2010 {
2011 suffix_object(child->prev, item);
2012 array->child->prev = item;
2013 }
2014 }
2015
2016 return true;
2017}
2018
2019/* Add item to array/object. */
2020CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item)
2021{
2022 return add_item_to_array(array, item);
2023}
2024
2025#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
2026 #pragma GCC diagnostic push
2027#endif
2028#ifdef __GNUC__
2029#pragma GCC diagnostic ignored "-Wcast-qual"
2030#endif
2031/* helper function to cast away const */
2032static void* cast_away_const(const void* string)
2033{
2034 return (void*)string;
2035}
2036#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
2037 #pragma GCC diagnostic pop
2038#endif
2039
2040
2041static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key)
2042{
2043 char *new_key = NULL;
2044 int new_type = cJSON_Invalid;
2045
2046 if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item))
2047 {
2048 return false;
2049 }
2050
2051 if (constant_key)
2052 {
2053 new_key = (char*)cast_away_const(string);
2054 new_type = item->type | cJSON_StringIsConst;
2055 }
2056 else
2057 {
2058 new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
2059 if (new_key == NULL)
2060 {
2061 return false;
2062 }
2063
2064 new_type = item->type & ~cJSON_StringIsConst;
2065 }
2066
2067 if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
2068 {
2069 hooks->deallocate(item->string);
2070 }
2071
2072 item->string = new_key;
2073 item->type = new_type;
2074
2075 return add_item_to_array(object, item);
2076}
2077
2078CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
2079{
2080 return add_item_to_object(object, string, item, &global_hooks, false);
2081}
2082
2083/* Add an item to an object with constant string as key */
2084CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
2085{
2086 return add_item_to_object(object, string, item, &global_hooks, true);
2087}
2088
2089CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
2090{
2091 if (array == NULL)
2092 {
2093 return false;
2094 }
2095
2096 return add_item_to_array(array, create_reference(item, &global_hooks));
2097}
2098
2099CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
2100{
2101 if ((object == NULL) || (string == NULL))
2102 {
2103 return false;
2104 }
2105
2106 return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false);
2107}
2108
2109CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name)
2110{
2111 cJSON *null = cJSON_CreateNull();
2112 if (add_item_to_object(object, name, null, &global_hooks, false))
2113 {
2114 return null;
2115 }
2116
2117 cJSON_Delete(null);
2118 return NULL;
2119}
2120
2121CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name)
2122{
2123 cJSON *true_item = cJSON_CreateTrue();
2124 if (add_item_to_object(object, name, true_item, &global_hooks, false))
2125 {
2126 return true_item;
2127 }
2128
2129 cJSON_Delete(true_item);
2130 return NULL;
2131}
2132
2133CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name)
2134{
2135 cJSON *false_item = cJSON_CreateFalse();
2136 if (add_item_to_object(object, name, false_item, &global_hooks, false))
2137 {
2138 return false_item;
2139 }
2140
2141 cJSON_Delete(false_item);
2142 return NULL;
2143}
2144
2145CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean)
2146{
2147 cJSON *bool_item = cJSON_CreateBool(boolean);
2148 if (add_item_to_object(object, name, bool_item, &global_hooks, false))
2149 {
2150 return bool_item;
2151 }
2152
2153 cJSON_Delete(bool_item);
2154 return NULL;
2155}
2156
2157CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number)
2158{
2159 cJSON *number_item = cJSON_CreateNumber(number);
2160 if (add_item_to_object(object, name, number_item, &global_hooks, false))
2161 {
2162 return number_item;
2163 }
2164
2165 cJSON_Delete(number_item);
2166 return NULL;
2167}
2168
2169CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string)
2170{
2171 cJSON *string_item = cJSON_CreateString(string);
2172 if (add_item_to_object(object, name, string_item, &global_hooks, false))
2173 {
2174 return string_item;
2175 }
2176
2177 cJSON_Delete(string_item);
2178 return NULL;
2179}
2180
2181CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw)
2182{
2183 cJSON *raw_item = cJSON_CreateRaw(raw);
2184 if (add_item_to_object(object, name, raw_item, &global_hooks, false))
2185 {
2186 return raw_item;
2187 }
2188
2189 cJSON_Delete(raw_item);
2190 return NULL;
2191}
2192
2193CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name)
2194{
2195 cJSON *object_item = cJSON_CreateObject();
2196 if (add_item_to_object(object, name, object_item, &global_hooks, false))
2197 {
2198 return object_item;
2199 }
2200
2201 cJSON_Delete(object_item);
2202 return NULL;
2203}
2204
2205CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name)
2206{
2207 cJSON *array = cJSON_CreateArray();
2208 if (add_item_to_object(object, name, array, &global_hooks, false))
2209 {
2210 return array;
2211 }
2212
2213 cJSON_Delete(array);
2214 return NULL;
2215}
2216
2217CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
2218{
2219 if ((parent == NULL) || (item == NULL) || (item != parent->child && item->prev == NULL))
2220 {
2221 return NULL;
2222 }
2223
2224 if (item != parent->child)
2225 {
2226 /* not the first element */
2227 item->prev->next = item->next;
2228 }
2229 if (item->next != NULL)
2230 {
2231 /* not the last element */
2232 item->next->prev = item->prev;
2233 }
2234
2235 if (item == parent->child)
2236 {
2237 /* first element */
2238 parent->child = item->next;
2239 }
2240 else if (item->next == NULL)
2241 {
2242 /* last element */
2243 parent->child->prev = item->prev;
2244 }
2245
2246 /* make sure the detached item doesn't point anywhere anymore */
2247 item->prev = NULL;
2248 item->next = NULL;
2249
2250 return item;
2251}
2252
2253CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)
2254{
2255 if (which < 0)
2256 {
2257 return NULL;
2258 }
2259
2260 return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
2261}
2262
2263CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
2264{
2265 cJSON_Delete(cJSON_DetachItemFromArray(array, which));
2266}
2267
2268CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string)
2269{
2270 cJSON *to_detach = cJSON_GetObjectItem(object, string);
2271
2272 return cJSON_DetachItemViaPointer(object, to_detach);
2273}
2274
2275CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string)
2276{
2277 cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);
2278
2279 return cJSON_DetachItemViaPointer(object, to_detach);
2280}
2281
2282CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
2283{
2284 cJSON_Delete(cJSON_DetachItemFromObject(object, string));
2285}
2286
2287CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string)
2288{
2289 cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
2290}
2291
2292/* Replace array/object items with new ones. */
2293CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
2294{
2295 cJSON *after_inserted = NULL;
2296
2297 if (which < 0 || newitem == NULL)
2298 {
2299 return false;
2300 }
2301
2302 after_inserted = get_array_item(array, (size_t)which);
2303 if (after_inserted == NULL)
2304 {
2305 return add_item_to_array(array, newitem);
2306 }
2307
2308 if (after_inserted != array->child && after_inserted->prev == NULL) {
2309 /* return false if after_inserted is a corrupted array item */
2310 return false;
2311 }
2312
2313 newitem->next = after_inserted;
2314 newitem->prev = after_inserted->prev;
2315 after_inserted->prev = newitem;
2316 if (after_inserted == array->child)
2317 {
2318 array->child = newitem;
2319 }
2320 else
2321 {
2322 newitem->prev->next = newitem;
2323 }
2324 return true;
2325}
2326
2327CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)
2328{
2329 if ((parent == NULL) || (parent->child == NULL) || (replacement == NULL) || (item == NULL))
2330 {
2331 return false;
2332 }
2333
2334 if (replacement == item)
2335 {
2336 return true;
2337 }
2338
2339 replacement->next = item->next;
2340 replacement->prev = item->prev;
2341
2342 if (replacement->next != NULL)
2343 {
2344 replacement->next->prev = replacement;
2345 }
2346 if (parent->child == item)
2347 {
2348 if (parent->child->prev == parent->child)
2349 {
2350 replacement->prev = replacement;
2351 }
2352 parent->child = replacement;
2353 }
2354 else
2355 { /*
2356 * To find the last item in array quickly, we use prev in array.
2357 * We can't modify the last item's next pointer where this item was the parent's child
2358 */
2359 if (replacement->prev != NULL)
2360 {
2361 replacement->prev->next = replacement;
2362 }
2363 if (replacement->next == NULL)
2364 {
2365 parent->child->prev = replacement;
2366 }
2367 }
2368
2369 item->next = NULL;
2370 item->prev = NULL;
2371 cJSON_Delete(item);
2372
2373 return true;
2374}
2375
2376CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
2377{
2378 if (which < 0)
2379 {
2380 return false;
2381 }
2382
2383 return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
2384}
2385
2386static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive)
2387{
2388 if ((replacement == NULL) || (string == NULL))
2389 {
2390 return false;
2391 }
2392
2393 /* replace the name in the replacement */
2394 if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))
2395 {
2396 cJSON_free(replacement->string);
2397 }
2398 replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
2399 if (replacement->string == NULL)
2400 {
2401 return false;
2402 }
2403
2404 replacement->type &= ~cJSON_StringIsConst;
2405
2406 return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
2407}
2408
2409CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
2410{
2411 return replace_item_in_object(object, string, newitem, false);
2412}
2413
2414CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
2415{
2416 return replace_item_in_object(object, string, newitem, true);
2417}
2418
2419/* Create basic types: */
2420CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void)
2421{
2422 cJSON *item = cJSON_New_Item(&global_hooks);
2423 if(item)
2424 {
2425 item->type = cJSON_NULL;
2426 }
2427
2428 return item;
2429}
2430
2431CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void)
2432{
2433 cJSON *item = cJSON_New_Item(&global_hooks);
2434 if(item)
2435 {
2436 item->type = cJSON_True;
2437 }
2438
2439 return item;
2440}
2441
2442CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
2443{
2444 cJSON *item = cJSON_New_Item(&global_hooks);
2445 if(item)
2446 {
2447 item->type = cJSON_False;
2448 }
2449
2450 return item;
2451}
2452
2453CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean)
2454{
2455 cJSON *item = cJSON_New_Item(&global_hooks);
2456 if(item)
2457 {
2458 item->type = boolean ? cJSON_True : cJSON_False;
2459 }
2460
2461 return item;
2462}
2463
2464CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
2465{
2466 cJSON *item = cJSON_New_Item(&global_hooks);
2467 if(item)
2468 {
2469 item->type = cJSON_Number;
2470 item->valuedouble = num;
2471
2472 /* use saturation in case of overflow */
2473 if (num >= INT_MAX)
2474 {
2475 item->valueint = INT_MAX;
2476 }
2477 else if (num <= (double)INT_MIN)
2478 {
2479 item->valueint = INT_MIN;
2480 }
2481 else
2482 {
2483 item->valueint = (int)num;
2484 }
2485 }
2486
2487 return item;
2488}
2489
2490CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
2491{
2492 cJSON *item = cJSON_New_Item(&global_hooks);
2493 if(item)
2494 {
2495 item->type = cJSON_String;
2496 item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
2497 if(!item->valuestring)
2498 {
2499 cJSON_Delete(item);
2500 return NULL;
2501 }
2502 }
2503
2504 return item;
2505}
2506
2507CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string)
2508{
2509 cJSON *item = cJSON_New_Item(&global_hooks);
2510 if (item != NULL)
2511 {
2512 item->type = cJSON_String | cJSON_IsReference;
2513 item->valuestring = (char*)cast_away_const(string);
2514 }
2515
2516 return item;
2517}
2518
2519CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child)
2520{
2521 cJSON *item = cJSON_New_Item(&global_hooks);
2522 if (item != NULL) {
2523 item->type = cJSON_Object | cJSON_IsReference;
2524 item->child = (cJSON*)cast_away_const(child);
2525 }
2526
2527 return item;
2528}
2529
2530CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) {
2531 cJSON *item = cJSON_New_Item(&global_hooks);
2532 if (item != NULL) {
2533 item->type = cJSON_Array | cJSON_IsReference;
2534 item->child = (cJSON*)cast_away_const(child);
2535 }
2536
2537 return item;
2538}
2539
2540CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
2541{
2542 cJSON *item = cJSON_New_Item(&global_hooks);
2543 if(item)
2544 {
2545 item->type = cJSON_Raw;
2546 item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
2547 if(!item->valuestring)
2548 {
2549 cJSON_Delete(item);
2550 return NULL;
2551 }
2552 }
2553
2554 return item;
2555}
2556
2557CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void)
2558{
2559 cJSON *item = cJSON_New_Item(&global_hooks);
2560 if(item)
2561 {
2562 item->type=cJSON_Array;
2563 }
2564
2565 return item;
2566}
2567
2568CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)
2569{
2570 cJSON *item = cJSON_New_Item(&global_hooks);
2571 if (item)
2572 {
2573 item->type = cJSON_Object;
2574 }
2575
2576 return item;
2577}
2578
2579/* Create Arrays: */
2580CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
2581{
2582 size_t i = 0;
2583 cJSON *n = NULL;
2584 cJSON *p = NULL;
2585 cJSON *a = NULL;
2586
2587 if ((count < 0) || (numbers == NULL))
2588 {
2589 return NULL;
2590 }
2591
2592 a = cJSON_CreateArray();
2593
2594 for(i = 0; a && (i < (size_t)count); i++)
2595 {
2596 n = cJSON_CreateNumber(numbers[i]);
2597 if (!n)
2598 {
2599 cJSON_Delete(a);
2600 return NULL;
2601 }
2602 if(!i)
2603 {
2604 a->child = n;
2605 }
2606 else
2607 {
2608 suffix_object(p, n);
2609 }
2610 p = n;
2611 }
2612
2613 if (a && a->child) {
2614 a->child->prev = n;
2615 }
2616
2617 return a;
2618}
2619
2620CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
2621{
2622 size_t i = 0;
2623 cJSON *n = NULL;
2624 cJSON *p = NULL;
2625 cJSON *a = NULL;
2626
2627 if ((count < 0) || (numbers == NULL))
2628 {
2629 return NULL;
2630 }
2631
2632 a = cJSON_CreateArray();
2633
2634 for(i = 0; a && (i < (size_t)count); i++)
2635 {
2636 n = cJSON_CreateNumber((double)numbers[i]);
2637 if(!n)
2638 {
2639 cJSON_Delete(a);
2640 return NULL;
2641 }
2642 if(!i)
2643 {
2644 a->child = n;
2645 }
2646 else
2647 {
2648 suffix_object(p, n);
2649 }
2650 p = n;
2651 }
2652
2653 if (a && a->child) {
2654 a->child->prev = n;
2655 }
2656
2657 return a;
2658}
2659
2660CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
2661{
2662 size_t i = 0;
2663 cJSON *n = NULL;
2664 cJSON *p = NULL;
2665 cJSON *a = NULL;
2666
2667 if ((count < 0) || (numbers == NULL))
2668 {
2669 return NULL;
2670 }
2671
2672 a = cJSON_CreateArray();
2673
2674 for(i = 0; a && (i < (size_t)count); i++)
2675 {
2676 n = cJSON_CreateNumber(numbers[i]);
2677 if(!n)
2678 {
2679 cJSON_Delete(a);
2680 return NULL;
2681 }
2682 if(!i)
2683 {
2684 a->child = n;
2685 }
2686 else
2687 {
2688 suffix_object(p, n);
2689 }
2690 p = n;
2691 }
2692
2693 if (a && a->child) {
2694 a->child->prev = n;
2695 }
2696
2697 return a;
2698}
2699
2700CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count)
2701{
2702 size_t i = 0;
2703 cJSON *n = NULL;
2704 cJSON *p = NULL;
2705 cJSON *a = NULL;
2706
2707 if ((count < 0) || (strings == NULL))
2708 {
2709 return NULL;
2710 }
2711
2712 a = cJSON_CreateArray();
2713
2714 for (i = 0; a && (i < (size_t)count); i++)
2715 {
2716 n = cJSON_CreateString(strings[i]);
2717 if(!n)
2718 {
2719 cJSON_Delete(a);
2720 return NULL;
2721 }
2722 if(!i)
2723 {
2724 a->child = n;
2725 }
2726 else
2727 {
2728 suffix_object(p,n);
2729 }
2730 p = n;
2731 }
2732
2733 if (a && a->child) {
2734 a->child->prev = n;
2735 }
2736
2737 return a;
2738}
2739
2740/* Duplication */
2741cJSON * cJSON_Duplicate_rec(const cJSON *item, size_t depth, cJSON_bool recurse);
2742
2743CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
2744{
2745 return cJSON_Duplicate_rec(item, 0, recurse );
2746}
2747
2748cJSON * cJSON_Duplicate_rec(const cJSON *item, size_t depth, cJSON_bool recurse)
2749{
2750 cJSON *newitem = NULL;
2751 cJSON *child = NULL;
2752 cJSON *next = NULL;
2753 cJSON *newchild = NULL;
2754
2755 /* Bail on bad ptr */
2756 if (!item)
2757 {
2758 goto fail;
2759 }
2760 /* Create new item */
2761 newitem = cJSON_New_Item(&global_hooks);
2762 if (!newitem)
2763 {
2764 goto fail;
2765 }
2766 /* Copy over all vars */
2767 newitem->type = item->type & (~cJSON_IsReference);
2768 newitem->valueint = item->valueint;
2769 newitem->valuedouble = item->valuedouble;
2770 if (item->valuestring)
2771 {
2772 newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
2773 if (!newitem->valuestring)
2774 {
2775 goto fail;
2776 }
2777 }
2778 if (item->string)
2779 {
2780 newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks);
2781 if (!newitem->string)
2782 {
2783 goto fail;
2784 }
2785 }
2786 /* If non-recursive, then we're done! */
2787 if (!recurse)
2788 {
2789 return newitem;
2790 }
2791 /* Walk the ->next chain for the child. */
2792 child = item->child;
2793 while (child != NULL)
2794 {
2795 if(depth >= CJSON_CIRCULAR_LIMIT) {
2796 goto fail;
2797 }
2798 newchild = cJSON_Duplicate_rec(child, depth + 1, true); /* Duplicate (with recurse) each item in the ->next chain */
2799 if (!newchild)
2800 {
2801 goto fail;
2802 }
2803 if (next != NULL)
2804 {
2805 /* If newitem->child already set, then crosswire ->prev and ->next and move on */
2806 next->next = newchild;
2807 newchild->prev = next;
2808 next = newchild;
2809 }
2810 else
2811 {
2812 /* Set newitem->child and move to it */
2813 newitem->child = newchild;
2814 next = newchild;
2815 }
2816 child = child->next;
2817 }
2818 if (newitem && newitem->child)
2819 {
2820 newitem->child->prev = newchild;
2821 }
2822
2823 return newitem;
2824
2825fail:
2826 if (newitem != NULL)
2827 {
2828 cJSON_Delete(newitem);
2829 }
2830
2831 return NULL;
2832}
2833
2834static void skip_oneline_comment(char **input)
2835{
2836 *input += static_strlen("//");
2837
2838 for (; (*input)[0] != '\0'; ++(*input))
2839 {
2840 if ((*input)[0] == '\n') {
2841 *input += static_strlen("\n");
2842 return;
2843 }
2844 }
2845}
2846
2847static void skip_multiline_comment(char **input)
2848{
2849 *input += static_strlen("/*");
2850
2851 for (; (*input)[0] != '\0'; ++(*input))
2852 {
2853 if (((*input)[0] == '*') && ((*input)[1] == '/'))
2854 {
2855 *input += static_strlen("*/");
2856 return;
2857 }
2858 }
2859}
2860
2861static void minify_string(char **input, char **output) {
2862 (*output)[0] = (*input)[0];
2863 *input += static_strlen("\"");
2864 *output += static_strlen("\"");
2865
2866
2867 for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
2868 (*output)[0] = (*input)[0];
2869
2870 if ((*input)[0] == '\"') {
2871 (*output)[0] = '\"';
2872 *input += static_strlen("\"");
2873 *output += static_strlen("\"");
2874 return;
2875 } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
2876 (*output)[1] = (*input)[1];
2877 *input += static_strlen("\"");
2878 *output += static_strlen("\"");
2879 }
2880 }
2881}
2882
2883CJSON_PUBLIC(void) cJSON_Minify(char *json)
2884{
2885 char *into = json;
2886
2887 if (json == NULL)
2888 {
2889 return;
2890 }
2891
2892 while (json[0] != '\0')
2893 {
2894 switch (json[0])
2895 {
2896 case ' ':
2897 case '\t':
2898 case '\r':
2899 case '\n':
2900 json++;
2901 break;
2902
2903 case '/':
2904 if (json[1] == '/')
2905 {
2906 skip_oneline_comment(&json);
2907 }
2908 else if (json[1] == '*')
2909 {
2910 skip_multiline_comment(&json);
2911 } else {
2912 json++;
2913 }
2914 break;
2915
2916 case '\"':
2917 minify_string(&json, (char**)&into);
2918 break;
2919
2920 default:
2921 into[0] = json[0];
2922 json++;
2923 into++;
2924 }
2925 }
2926
2927 /* and null-terminate. */
2928 *into = '\0';
2929}
2930
2931CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item)
2932{
2933 if (item == NULL)
2934 {
2935 return false;
2936 }
2937
2938 return (item->type & 0xFF) == cJSON_Invalid;
2939}
2940
2941CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item)
2942{
2943 if (item == NULL)
2944 {
2945 return false;
2946 }
2947
2948 return (item->type & 0xFF) == cJSON_False;
2949}
2950
2951CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item)
2952{
2953 if (item == NULL)
2954 {
2955 return false;
2956 }
2957
2958 return (item->type & 0xff) == cJSON_True;
2959}
2960
2961
2962CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item)
2963{
2964 if (item == NULL)
2965 {
2966 return false;
2967 }
2968
2969 return (item->type & (cJSON_True | cJSON_False)) != 0;
2970}
2971CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item)
2972{
2973 if (item == NULL)
2974 {
2975 return false;
2976 }
2977
2978 return (item->type & 0xFF) == cJSON_NULL;
2979}
2980
2981CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)
2982{
2983 if (item == NULL)
2984 {
2985 return false;
2986 }
2987
2988 return (item->type & 0xFF) == cJSON_Number;
2989}
2990
2991CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)
2992{
2993 if (item == NULL)
2994 {
2995 return false;
2996 }
2997
2998 return (item->type & 0xFF) == cJSON_String;
2999}
3000
3001CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item)
3002{
3003 if (item == NULL)
3004 {
3005 return false;
3006 }
3007
3008 return (item->type & 0xFF) == cJSON_Array;
3009}
3010
3011CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item)
3012{
3013 if (item == NULL)
3014 {
3015 return false;
3016 }
3017
3018 return (item->type & 0xFF) == cJSON_Object;
3019}
3020
3021CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item)
3022{
3023 if (item == NULL)
3024 {
3025 return false;
3026 }
3027
3028 return (item->type & 0xFF) == cJSON_Raw;
3029}
3030
3031CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive)
3032{
3033 if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)))
3034 {
3035 return false;
3036 }
3037
3038 /* check if type is valid */
3039 switch (a->type & 0xFF)
3040 {
3041 case cJSON_False:
3042 case cJSON_True:
3043 case cJSON_NULL:
3044 case cJSON_Number:
3045 case cJSON_String:
3046 case cJSON_Raw:
3047 case cJSON_Array:
3048 case cJSON_Object:
3049 break;
3050
3051 default:
3052 return false;
3053 }
3054
3055 /* identical objects are equal */
3056 if (a == b)
3057 {
3058 return true;
3059 }
3060
3061 switch (a->type & 0xFF)
3062 {
3063 /* in these cases and equal type is enough */
3064 case cJSON_False:
3065 case cJSON_True:
3066 case cJSON_NULL:
3067 return true;
3068
3069 case cJSON_Number:
3070 if (compare_double(a->valuedouble, b->valuedouble))
3071 {
3072 return true;
3073 }
3074 return false;
3075
3076 case cJSON_String:
3077 case cJSON_Raw:
3078 if ((a->valuestring == NULL) || (b->valuestring == NULL))
3079 {
3080 return false;
3081 }
3082 if (strcmp(a->valuestring, b->valuestring) == 0)
3083 {
3084 return true;
3085 }
3086
3087 return false;
3088
3089 case cJSON_Array:
3090 {
3091 cJSON *a_element = a->child;
3092 cJSON *b_element = b->child;
3093
3094 for (; (a_element != NULL) && (b_element != NULL);)
3095 {
3096 if (!cJSON_Compare(a_element, b_element, case_sensitive))
3097 {
3098 return false;
3099 }
3100
3101 a_element = a_element->next;
3102 b_element = b_element->next;
3103 }
3104
3105 /* one of the arrays is longer than the other */
3106 if (a_element != b_element) {
3107 return false;
3108 }
3109
3110 return true;
3111 }
3112
3113 case cJSON_Object:
3114 {
3115 cJSON *a_element = NULL;
3116 cJSON *b_element = NULL;
3117 cJSON_ArrayForEach(a_element, a)
3118 {
3119 /* TODO This has O(n^2) runtime, which is horrible! */
3120 b_element = get_object_item(b, a_element->string, case_sensitive);
3121 if (b_element == NULL)
3122 {
3123 return false;
3124 }
3125
3126 if (!cJSON_Compare(a_element, b_element, case_sensitive))
3127 {
3128 return false;
3129 }
3130 }
3131
3132 /* doing this twice, once on a and b to prevent true comparison if a subset of b
3133 * TODO: Do this the proper way, this is just a fix for now */
3134 cJSON_ArrayForEach(b_element, b)
3135 {
3136 a_element = get_object_item(a, b_element->string, case_sensitive);
3137 if (a_element == NULL)
3138 {
3139 return false;
3140 }
3141
3142 if (!cJSON_Compare(b_element, a_element, case_sensitive))
3143 {
3144 return false;
3145 }
3146 }
3147
3148 return true;
3149 }
3150
3151 default:
3152 return false;
3153 }
3154}
3155
3156CJSON_PUBLIC(void *) cJSON_malloc(size_t size)
3157{
3158 return global_hooks.allocate(size);
3159}
3160
3161CJSON_PUBLIC(void) cJSON_free(void *object)
3162{
3163 global_hooks.deallocate(object);
3164 object = NULL;
3165}
diff --git a/lib/vendor/cJSON/cJSON.h b/lib/vendor/cJSON/cJSON.h
new file mode 100644
index 00000000..37520bbc
--- /dev/null
+++ b/lib/vendor/cJSON/cJSON.h
@@ -0,0 +1,306 @@
1/*
2 Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21*/
22
23#ifndef cJSON__h
24#define cJSON__h
25
26#ifdef __cplusplus
27extern "C"
28{
29#endif
30
31#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
32#define __WINDOWS__
33#endif
34
35#ifdef __WINDOWS__
36
37/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
38
39CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
40CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
41CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
42
43For *nix builds that support visibility attribute, you can define similar behavior by
44
45setting default visibility to hidden by adding
46-fvisibility=hidden (for gcc)
47or
48-xldscope=hidden (for sun cc)
49to CFLAGS
50
51then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
52
53*/
54
55#define CJSON_CDECL __cdecl
56#define CJSON_STDCALL __stdcall
57
58/* export symbols by default, this is necessary for copy pasting the C and header file */
59#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
60#define CJSON_EXPORT_SYMBOLS
61#endif
62
63#if defined(CJSON_HIDE_SYMBOLS)
64#define CJSON_PUBLIC(type) type CJSON_STDCALL
65#elif defined(CJSON_EXPORT_SYMBOLS)
66#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
67#elif defined(CJSON_IMPORT_SYMBOLS)
68#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
69#endif
70#else /* !__WINDOWS__ */
71#define CJSON_CDECL
72#define CJSON_STDCALL
73
74#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
75#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
76#else
77#define CJSON_PUBLIC(type) type
78#endif
79#endif
80
81/* project version */
82#define CJSON_VERSION_MAJOR 1
83#define CJSON_VERSION_MINOR 7
84#define CJSON_VERSION_PATCH 18
85
86#include <stddef.h>
87
88/* cJSON Types: */
89#define cJSON_Invalid (0)
90#define cJSON_False (1 << 0)
91#define cJSON_True (1 << 1)
92#define cJSON_NULL (1 << 2)
93#define cJSON_Number (1 << 3)
94#define cJSON_String (1 << 4)
95#define cJSON_Array (1 << 5)
96#define cJSON_Object (1 << 6)
97#define cJSON_Raw (1 << 7) /* raw json */
98
99#define cJSON_IsReference 256
100#define cJSON_StringIsConst 512
101
102/* The cJSON structure: */
103typedef struct cJSON
104{
105 /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
106 struct cJSON *next;
107 struct cJSON *prev;
108 /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
109 struct cJSON *child;
110
111 /* The type of the item, as above. */
112 int type;
113
114 /* The item's string, if type==cJSON_String and type == cJSON_Raw */
115 char *valuestring;
116 /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
117 int valueint;
118 /* The item's number, if type==cJSON_Number */
119 double valuedouble;
120
121 /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
122 char *string;
123} cJSON;
124
125typedef struct cJSON_Hooks
126{
127 /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
128 void *(CJSON_CDECL *malloc_fn)(size_t sz);
129 void (CJSON_CDECL *free_fn)(void *ptr);
130} cJSON_Hooks;
131
132typedef int cJSON_bool;
133
134/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
135 * This is to prevent stack overflows. */
136#ifndef CJSON_NESTING_LIMIT
137#define CJSON_NESTING_LIMIT 1000
138#endif
139
140/* Limits the length of circular references can be before cJSON rejects to parse them.
141 * This is to prevent stack overflows. */
142#ifndef CJSON_CIRCULAR_LIMIT
143#define CJSON_CIRCULAR_LIMIT 10000
144#endif
145
146/* returns the version of cJSON as a string */
147CJSON_PUBLIC(const char*) cJSON_Version(void);
148
149/* Supply malloc, realloc and free functions to cJSON */
150CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
151
152/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
153/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
154CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
155CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
156/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
157/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
158CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
159CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
160
161/* Render a cJSON entity to text for transfer/storage. */
162CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
163/* Render a cJSON entity to text for transfer/storage without any formatting. */
164CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
165/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
166CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
167/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
168/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
169CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
170/* Delete a cJSON entity and all subentities. */
171CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
172
173/* Returns the number of items in an array (or object). */
174CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
175/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
176CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
177/* Get item "string" from object. Case insensitive. */
178CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
179CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
180CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
181/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
182CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
183
184/* Check item type and return its value */
185CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
186CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
187
188/* These functions check the type of an item */
189CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
190CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
191CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
192CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
193CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
194CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
195CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
196CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
197CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
198CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
199
200/* These calls create a cJSON item of the appropriate type. */
201CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
202CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
203CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
204CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
205CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
206CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
207/* raw json */
208CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
209CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
210CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
211
212/* Create a string where valuestring references a string so
213 * it will not be freed by cJSON_Delete */
214CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
215/* Create an object/array that only references it's elements so
216 * they will not be freed by cJSON_Delete */
217CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
218CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
219
220/* These utilities create an Array of count items.
221 * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
222CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
223CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
224CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
225CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
226
227/* Append item to the specified array/object. */
228CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
229CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
230/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
231 * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
232 * writing to `item->string` */
233CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
234/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
235CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
236CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
237
238/* Remove/Detach items from Arrays/Objects. */
239CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
240CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
241CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
242CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
243CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
244CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
245CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
246
247/* Update array items. */
248CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
249CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
250CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
251CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
252CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
253
254/* Duplicate a cJSON item */
255CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
256/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
257 * need to be released. With recurse!=0, it will duplicate any children connected to the item.
258 * The item->next and ->prev pointers are always zero on return from Duplicate. */
259/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
260 * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
261CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
262
263/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
264 * The input pointer json cannot point to a read-only address area, such as a string constant,
265 * but should point to a readable and writable address area. */
266CJSON_PUBLIC(void) cJSON_Minify(char *json);
267
268/* Helper functions for creating and adding items to an object at the same time.
269 * They return the added item or NULL on failure. */
270CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
271CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
272CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
273CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
274CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
275CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
276CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
277CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
278CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
279
280/* When assigning an integer value, it needs to be propagated to valuedouble too. */
281#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
282/* helper for the cJSON_SetNumberValue macro */
283CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
284#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
285/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
286CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
287
288/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
289#define cJSON_SetBoolValue(object, boolValue) ( \
290 (object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
291 (object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
292 cJSON_Invalid\
293)
294
295/* Macro for iterating over an array or object */
296#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
297
298/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
299CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
300CJSON_PUBLIC(void) cJSON_free(void *object);
301
302#ifdef __cplusplus
303}
304#endif
305
306#endif
diff --git a/opttest.pl b/opttest.pl
deleted file mode 100755
index 85e3b494..00000000
--- a/opttest.pl
+++ /dev/null
@@ -1,50 +0,0 @@
1#!/usr/bin/perl -w
2use strict;
3use Test;
4
5use vars qw($dir $file $prog $idx $state $output %progs @dirs);
6
7my $tests = 0;
8
9@dirs = qw(plugins plugins-scripts);
10
11foreach $dir (@dirs) {
12 opendir(DIR, $dir) || die "can't opendir $dir: $!";
13 while ($file = readdir(DIR)) {
14 if (-x "$dir/$file" && -f "$dir/$file") {
15 $tests++;
16 $progs{"$dir/$file"} = $file;
17 }
18 }
19 closedir DIR;
20}
21
22plan tests => $tests;
23
24for $prog (keys %progs) {
25 $state = 0;
26 $file = `basename $prog`;
27
28 $idx = 1;
29 $output = `$prog -h 2>&1`;
30 if($?) {$state++;print "$prog failed test $idx\n";}
31 unless ($output =~ m/$progs{$prog}/ms) {
32 $idx++; $state++;print "$output\n$prog failed test $idx\n";
33 }
34
35 $idx++;
36 `$prog --help 2>&1 > /dev/null`;
37 if($?) {$state++;print "$prog failed test $idx\n";}
38
39 $idx++;
40 `$prog -V 2>&1 > /dev/null`;
41 if($?) {$state++;print "$prog failed test $idx\n";}
42
43 $idx++;
44 `$prog --version 2>&1 > /dev/null`;
45 if($?) {$state++;print "$prog failed test $idx\n";}
46
47 print "$prog ($idx tests) ";
48 ok $state,0;
49}
50
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 4b8f5e27..daed9cb0 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-2007 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-2023"; 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>
@@ -59,45 +63,45 @@ const char *email = "devel@monitoring-plugins.org";
59#include <arpa/inet.h> 63#include <arpa/inet.h>
60 64
61#if HAVE_SYS_SOCKIO_H 65#if HAVE_SYS_SOCKIO_H
62#include <sys/sockio.h> 66# include <sys/sockio.h>
63#endif // HAVE_SYS_SOCKIO_H 67#endif // HAVE_SYS_SOCKIO_H
64 68
65#if defined( __linux__ ) 69#if defined(__linux__)
66 70
67#include <linux/if_ether.h> 71# include <linux/if_ether.h>
68#include <features.h> 72# include <features.h>
69 73
70#elif defined (__bsd__) 74#elif defined(__bsd__)
71 75
72#include <netinet/if_ether.h> 76# include <netinet/if_ether.h>
73#include <sys/param.h> 77# include <sys/param.h>
74#include <sys/sysctl.h> 78# include <sys/sysctl.h>
75#include <net/if_dl.h> 79# include <net/if_dl.h>
76 80
77#elif defined(__sun__) || defined(__solaris__) || defined(__hpux__) 81#elif defined(__sun__) || defined(__solaris__) || defined(__hpux__)
78 82
79#define INSAP 22 83# define INSAP 22
80#define OUTSAP 24 84# define OUTSAP 24
81 85
82#include <signal.h> 86# include <signal.h>
83#include <ctype.h> 87# include <ctype.h>
84#include <sys/stropts.h> 88# include <sys/stropts.h>
85#include <sys/poll.h> 89# include <sys/poll.h>
86#include <sys/dlpi.h> 90# include <sys/dlpi.h>
87 91
88#define bcopy(source, destination, length) memcpy(destination, source, length) 92# define bcopy(source, destination, length) memcpy(destination, source, length)
89 93
90#define AREA_SZ 5000 /* buffer length in bytes */ 94# define AREA_SZ 5000 /* buffer length in bytes */
91static u_long ctl_area[AREA_SZ]; 95static u_long ctl_area[AREA_SZ];
92static u_long dat_area[AREA_SZ]; 96static u_long dat_area[AREA_SZ];
93static struct strbuf ctl = {AREA_SZ, 0, (char *)ctl_area}; 97static struct strbuf ctl = {AREA_SZ, 0, (char *)ctl_area};
94static struct strbuf dat = {AREA_SZ, 0, (char *)dat_area}; 98static struct strbuf dat = {AREA_SZ, 0, (char *)dat_area};
95 99
96#define GOT_CTRL 1 100# define GOT_CTRL 1
97#define GOT_DATA 2 101# define GOT_DATA 2
98#define GOT_BOTH 3 102# define GOT_BOTH 3
99#define GOT_INTR 4 103# define GOT_INTR 4
100#define GOT_ERR 128 104# define GOT_ERR 128
101 105
102static int get_msg(int); 106static int get_msg(int);
103static int check_ctrl(int); 107static int check_ctrl(int);
@@ -105,226 +109,241 @@ static int put_ctrl(int, int, int);
105static int put_both(int, int, int, int); 109static int put_both(int, int, int, int);
106static int dl_open(const char *, int, int *); 110static int dl_open(const char *, int, int *);
107static int dl_bind(int, int, u_char *); 111static int dl_bind(int, int, u_char *);
108long mac_addr_dlpi( const char *, int, u_char *); 112static long mac_addr_dlpi(const char *, int, u_char *);
109 113
110#endif // __sun__ || __solaris__ || __hpux 114#endif // __sun__ || __solaris__ || __hpux
111 115
112
113
114/**** Common definitions ****/ 116/**** Common definitions ****/
115 117
116#define OK 0 118#define OK 0
117#define ERROR -1 119#define ERROR -1
118 120#define MAC_ADDR_LEN 6
119 121
120/**** DHCP definitions ****/ 122/**** DHCP definitions ****/
121 123
122#define MAX_DHCP_CHADDR_LENGTH 16 124#define MAX_DHCP_CHADDR_LENGTH 16
123#define MAX_DHCP_SNAME_LENGTH 64 125#define MAX_DHCP_SNAME_LENGTH 64
124#define MAX_DHCP_FILE_LENGTH 128 126#define MAX_DHCP_FILE_LENGTH 128
125#define MAX_DHCP_OPTIONS_LENGTH 312 127#define MAX_DHCP_OPTIONS_LENGTH 312
126 128
127 129typedef struct dhcp_packet_struct {
128typedef struct dhcp_packet_struct{ 130 uint8_t op; /* packet type */
129 uint8_t op; /* packet type */ 131 uint8_t htype; /* type of hardware address for this machine (Ethernet, etc) */
130 uint8_t htype; /* type of hardware address for this machine (Ethernet, etc) */ 132 uint8_t hlen; /* length of hardware address (of this machine) */
131 uint8_t hlen; /* length of hardware address (of this machine) */ 133 uint8_t hops; /* hops */
132 uint8_t hops; /* hops */ 134 uint32_t xid; /* random transaction id number - chosen by this machine */
133 uint32_t xid; /* random transaction id number - chosen by this machine */ 135 uint16_t secs; /* seconds used in timing */
134 uint16_t secs; /* seconds used in timing */ 136 uint16_t flags; /* flags */
135 uint16_t flags; /* flags */ 137 struct in_addr ciaddr; /* IP address of this machine (if we already have one) */
136 struct in_addr ciaddr; /* IP address of this machine (if we already have one) */ 138 struct in_addr yiaddr; /* IP address of this machine (offered by the DHCP server) */
137 struct in_addr yiaddr; /* IP address of this machine (offered by the DHCP server) */ 139 struct in_addr siaddr; /* IP address of next server */
138 struct in_addr siaddr; /* IP address of next server */ 140 struct in_addr giaddr; /* IP address of DHCP relay */
139 struct in_addr giaddr; /* IP address of DHCP relay */ 141 unsigned char chaddr[MAX_DHCP_CHADDR_LENGTH]; /* hardware address of this machine */
140 unsigned char chaddr [MAX_DHCP_CHADDR_LENGTH]; /* hardware address of this machine */ 142 char sname[MAX_DHCP_SNAME_LENGTH]; /* name of DHCP server */
141 char sname [MAX_DHCP_SNAME_LENGTH]; /* name of DHCP server */ 143 char file[MAX_DHCP_FILE_LENGTH]; /* boot file name (used for diskless booting?) */
142 char file [MAX_DHCP_FILE_LENGTH]; /* boot file name (used for diskless booting?) */ 144 char options[MAX_DHCP_OPTIONS_LENGTH]; /* options */
143 char options[MAX_DHCP_OPTIONS_LENGTH]; /* options */ 145} dhcp_packet;
144}dhcp_packet; 146
145 147typedef struct dhcp_offer_struct {
146 148 struct in_addr server_address; /* address of DHCP server that sent this offer */
147typedef struct dhcp_offer_struct{ 149 struct in_addr offered_address; /* the IP address that was offered to us */
148 struct in_addr server_address; /* address of DHCP server that sent this offer */
149 struct in_addr offered_address; /* the IP address that was offered to us */
150 uint32_t lease_time; /* lease time in seconds */ 150 uint32_t lease_time; /* lease time in seconds */
151 uint32_t renewal_time; /* renewal time in seconds */ 151 uint32_t renewal_time; /* renewal time in seconds */
152 uint32_t rebinding_time; /* rebinding time in seconds */ 152 uint32_t rebinding_time; /* rebinding time in seconds */
153 bool desired; /* is this offer desired (necessary in exclusive mode) */ 153 bool desired; /* is this offer desired (necessary in exclusive mode) */
154 struct dhcp_offer_struct *next; 154 struct dhcp_offer_struct *next;
155}dhcp_offer; 155} dhcp_offer;
156 156
157 157#define BOOTREQUEST 1
158typedef struct requested_server_struct{ 158#define BOOTREPLY 2
159 struct in_addr server_address; 159
160 bool answered; 160#define DHCPDISCOVER 1
161 struct requested_server_struct *next; 161#define DHCPOFFER 2
162}requested_server; 162#define DHCPREQUEST 3
163 163#define DHCPDECLINE 4
164 164#define DHCPACK 5
165#define BOOTREQUEST 1 165#define DHCPNACK 6
166#define BOOTREPLY 2 166#define DHCPRELEASE 7
167 167
168#define DHCPDISCOVER 1 168#define DHCP_OPTION_MESSAGE_TYPE 53
169#define DHCPOFFER 2 169#define DHCP_OPTION_HOST_NAME 12
170#define DHCPREQUEST 3 170#define DHCP_OPTION_BROADCAST_ADDRESS 28
171#define DHCPDECLINE 4 171#define DHCP_OPTION_REQUESTED_ADDRESS 50
172#define DHCPACK 5 172#define DHCP_OPTION_LEASE_TIME 51
173#define DHCPNACK 6 173#define DHCP_OPTION_SERVER_IDENTIFIER 54
174#define DHCPRELEASE 7 174#define DHCP_OPTION_RENEWAL_TIME 58
175 175#define DHCP_OPTION_REBINDING_TIME 59
176#define DHCP_OPTION_MESSAGE_TYPE 53 176#define DHCP_OPTION_END 255
177#define DHCP_OPTION_HOST_NAME 12 177
178#define DHCP_OPTION_BROADCAST_ADDRESS 28 178#define DHCP_INFINITE_TIME 0xFFFFFFFF
179#define DHCP_OPTION_REQUESTED_ADDRESS 50
180#define DHCP_OPTION_LEASE_TIME 51
181#define DHCP_OPTION_SERVER_IDENTIFIER 54
182#define DHCP_OPTION_RENEWAL_TIME 58
183#define DHCP_OPTION_REBINDING_TIME 59
184#define DHCP_OPTION_END 255
185
186#define DHCP_INFINITE_TIME 0xFFFFFFFF
187 179
188#define DHCP_BROADCAST_FLAG 32768 180#define DHCP_BROADCAST_FLAG 32768
189 181
190#define DHCP_SERVER_PORT 67 182#define DHCP_SERVER_PORT 67
191#define DHCP_CLIENT_PORT 68 183#define DHCP_CLIENT_PORT 68
192
193#define ETHERNET_HARDWARE_ADDRESS 1 /* used in htype field of dhcp packet */
194#define ETHERNET_HARDWARE_ADDRESS_LENGTH 6 /* length of Ethernet hardware addresses */
195
196bool unicast = false; /* unicast mode: mimic a DHCP relay */
197bool exclusive = false; /* exclusive mode aka "rogue DHCP server detection" */
198struct in_addr my_ip; /* our address (required for relay) */
199struct in_addr dhcp_ip; /* server to query (if in unicast mode) */
200unsigned char client_hardware_address[MAX_DHCP_CHADDR_LENGTH]="";
201unsigned char *user_specified_mac=NULL;
202 184
203char network_interface_name[IFNAMSIZ]="eth0"; 185#define ETHERNET_HARDWARE_ADDRESS 1 /* used in htype field of dhcp packet */
186#define ETHERNET_HARDWARE_ADDRESS_LENGTH 6 /* length of Ethernet hardware addresses */
204 187
205uint32_t packet_xid=0; 188static int verbose = 0;
206 189
207uint32_t dhcp_lease_time=0; 190typedef struct process_arguments_wrapper {
208uint32_t dhcp_renewal_time=0; 191 int error;
209uint32_t dhcp_rebinding_time=0; 192 check_dhcp_config config;
193} process_arguments_wrapper;
210 194
211int dhcpoffer_timeout=2; 195static process_arguments_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
212
213dhcp_offer *dhcp_offer_list=NULL;
214requested_server *requested_server_list=NULL;
215
216int valid_responses=0; /* number of valid DHCPOFFERs we received */
217int requested_servers=0;
218int requested_responses=0;
219
220bool request_specific_address=false;
221bool received_requested_address=false;
222int verbose=0;
223struct in_addr requested_address;
224
225
226int process_arguments(int, char **);
227int call_getopt(int, char **);
228int validate_arguments(int);
229void print_usage(void); 196void print_usage(void);
230void print_help(void); 197static void print_help(void);
231 198
232void resolve_host(const char *in,struct in_addr *out); 199static void resolve_host(const char * /*in*/, struct in_addr * /*out*/);
233unsigned char *mac_aton(const char *); 200static unsigned char *mac_aton(const char * /*string*/);
234void print_hardware_address(const unsigned char *); 201static void print_hardware_address(const unsigned char * /*address*/);
235int get_hardware_address(int,char *); 202static int get_hardware_address(int /*sock*/, char * /*interface_name*/, unsigned char *client_hardware_address);
236int get_ip_address(int,char *); 203
237 204typedef struct get_ip_address_wrapper {
238int send_dhcp_discover(int); 205 int error;
239int get_dhcp_offer(int); 206 struct in_addr my_ip;
207} get_ip_address_wrapper;
208static get_ip_address_wrapper get_ip_address(int /*sock*/, char * /*interface_name*/);
209
210typedef struct send_dhcp_discover_wrapper {
211 int error;
212 uint32_t packet_xid;
213} send_dhcp_discover_wrapper;
214static send_dhcp_discover_wrapper send_dhcp_discover(int socket, bool unicast, struct in_addr dhcp_ip, struct in_addr requested_address,
215 bool request_specific_address, struct in_addr my_ip,
216 unsigned char *client_hardware_address);
217typedef struct get_dhcp_offer_wrapper {
218 int error;
219 int valid_responses;
220 dhcp_offer *dhcp_offer_list;
221} get_dhcp_offer_wrapper;
222static get_dhcp_offer_wrapper get_dhcp_offer(int /*sock*/, int dhcpoffer_timeout, uint32_t packet_xid, dhcp_offer *dhcp_offer_list,
223 const unsigned char *client_hardware_address);
224
225static mp_subcheck get_results(bool exclusive, int requested_servers, struct in_addr requested_address, bool request_specific_address,
226 requested_server *requested_server_list, int valid_responses, dhcp_offer *dhcp_offer_list);
227
228typedef struct add_dhcp_offer_wrapper {
229 int error;
230 dhcp_offer *dhcp_offer_list;
231} add_dhcp_offer_wrapper;
232static add_dhcp_offer_wrapper add_dhcp_offer(struct in_addr /*source*/, dhcp_packet * /*offer_packet*/, dhcp_offer *dhcp_offer_list);
233static int free_dhcp_offer_list(dhcp_offer *dhcp_offer_list);
234static int free_requested_server_list(requested_server *requested_server_list);
235
236static int create_dhcp_socket(bool /*unicast*/, char *network_interface_name);
237static int close_dhcp_socket(int /*sock*/);
238static int send_dhcp_packet(void * /*buffer*/, int /*buffer_size*/, int /*sock*/, struct sockaddr_in * /*dest*/);
239static int receive_dhcp_packet(void * /*buffer*/, int /*buffer_size*/, int /*sock*/, int /*timeout*/, struct sockaddr_in * /*address*/);
240
241int main(int argc, char **argv) {
242 setlocale(LC_ALL, "");
243 bindtextdomain(PACKAGE, LOCALEDIR);
244 textdomain(PACKAGE);
240 245
241int get_results(void); 246 /* Parse extra opts if any */
242 247 argv = np_extra_opts(&argc, argv, progname);
243int add_dhcp_offer(struct in_addr,dhcp_packet *);
244int free_dhcp_offer_list(void);
245int free_requested_server_list(void);
246
247int create_dhcp_socket(void);
248int close_dhcp_socket(int);
249int send_dhcp_packet(void *,int,int,struct sockaddr_in *);
250int receive_dhcp_packet(void *,int,int,int,struct sockaddr_in *);
251
252
253
254int main(int argc, char **argv){
255 int dhcp_socket;
256 int result = STATE_UNKNOWN;
257 248
258 setlocale (LC_ALL, ""); 249 process_arguments_wrapper tmp = process_arguments(argc, argv);
259 bindtextdomain (PACKAGE, LOCALEDIR);
260 textdomain (PACKAGE);
261 250
262 /* Parse extra opts if any */ 251 if (tmp.error != OK) {
263 argv=np_extra_opts(&argc, argv, progname); 252 usage4(_("Could not parse arguments"));
253 }
264 254
265 if(process_arguments(argc,argv)!=OK){ 255 check_dhcp_config config = tmp.config;
266 usage4 (_("Could not parse arguments")); 256 if (config.output_format_is_set) {
257 mp_set_format(config.output_format);
267 } 258 }
268 259
269 /* create socket for DHCP communications */ 260 /* create socket for DHCP communications */
270 dhcp_socket=create_dhcp_socket(); 261 int dhcp_socket = create_dhcp_socket(config.unicast_mode, config.network_interface_name);
271 262
272 /* get hardware address of client machine */ 263 /* get hardware address of client machine */
273 if(user_specified_mac!=NULL) 264 unsigned char client_hardware_address[MAX_DHCP_CHADDR_LENGTH] = "";
274 memcpy(client_hardware_address,user_specified_mac,6); 265 if (config.user_specified_mac != NULL) {
275 else 266 memcpy(client_hardware_address, config.user_specified_mac, MAC_ADDR_LEN);
276 get_hardware_address(dhcp_socket,network_interface_name); 267 } else {
268 get_hardware_address(dhcp_socket, config.network_interface_name, client_hardware_address);
269 }
277 270
278 if(unicast) /* get IP address of client machine */ 271 struct in_addr my_ip = {0};
279 get_ip_address(dhcp_socket,network_interface_name); 272
273 if (config.unicast_mode) { /* get IP address of client machine */
274 get_ip_address_wrapper tmp_get_ip = get_ip_address(dhcp_socket, config.network_interface_name);
275 if (tmp_get_ip.error == OK) {
276 my_ip = tmp_get_ip.my_ip;
277 } else {
278 // TODO failed to get own IP
279 die(STATE_UNKNOWN, "Failed to retrieve my own IP address in unicast mode");
280 }
281 }
280 282
281 /* send DHCPDISCOVER packet */ 283 /* send DHCPDISCOVER packet */
282 send_dhcp_discover(dhcp_socket); 284 send_dhcp_discover_wrapper disco_res = send_dhcp_discover(dhcp_socket, config.unicast_mode, config.dhcp_ip, config.requested_address,
285 config.request_specific_address, my_ip, client_hardware_address);
286
287 if (disco_res.error != OK) {
288 // DO something?
289 die(STATE_UNKNOWN, "Failed to send DHCP discover");
290 }
283 291
284 /* wait for a DHCPOFFER packet */ 292 /* wait for a DHCPOFFER packet */
285 get_dhcp_offer(dhcp_socket); 293 get_dhcp_offer_wrapper offer_res =
294 get_dhcp_offer(dhcp_socket, config.dhcpoffer_timeout, disco_res.packet_xid, NULL, client_hardware_address);
295
296 int valid_responses = 0;
297 dhcp_offer *dhcp_offer_list = NULL;
298 if (offer_res.error == OK) {
299 valid_responses = offer_res.valid_responses;
300 dhcp_offer_list = offer_res.dhcp_offer_list;
301 } else {
302 die(STATE_UNKNOWN, "Failed to get DHCP offers");
303 }
286 304
287 /* close socket we created */ 305 /* close socket we created */
288 close_dhcp_socket(dhcp_socket); 306 close_dhcp_socket(dhcp_socket);
289 307
290 /* determine state/plugin output to return */ 308 mp_check overall = mp_check_init();
291 result=get_results();
292 309
310 /* determine state/plugin output to return */
311 mp_subcheck sc_res = get_results(config.exclusive_mode, config.num_of_requested_servers, config.requested_address,
312 config.request_specific_address, config.requested_server_list, valid_responses, dhcp_offer_list);
313 mp_add_subcheck_to_check(&overall, sc_res);
293 /* free allocated memory */ 314 /* free allocated memory */
294 free_dhcp_offer_list(); 315 free_dhcp_offer_list(dhcp_offer_list);
295 free_requested_server_list(); 316 free_requested_server_list(config.requested_server_list);
296 317
297 return result; 318 mp_exit(overall);
298} 319}
299 320
300
301
302/* determines hardware address on client machine */ 321/* determines hardware address on client machine */
303int get_hardware_address(int sock,char *interface_name){ 322int get_hardware_address(int sock, char *interface_name, unsigned char *client_hardware_address) {
304 323
305#if defined(__linux__) 324#if defined(__linux__)
306 struct ifreq ifr; 325 struct ifreq ifr;
307 326
308 strncpy((char *)&ifr.ifr_name,interface_name,sizeof(ifr.ifr_name)-1); 327 strncpy((char *)&ifr.ifr_name, interface_name, sizeof(ifr.ifr_name) - 1);
309 ifr.ifr_name[sizeof(ifr.ifr_name)-1]='\0'; 328 ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
310 329
311 /* try and grab hardware address of requested interface */ 330 /* try and grab hardware address of requested interface */
312 if(ioctl(sock,SIOCGIFHWADDR,&ifr)<0){ 331 if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
313 printf(_("Error: Could not get hardware address of interface '%s'\n"),interface_name); 332 printf(_("Error: Could not get hardware address of interface '%s'\n"), interface_name);
314 exit(STATE_UNKNOWN); 333 exit(STATE_UNKNOWN);
315 } 334 }
316 335
317 memcpy(&client_hardware_address[0],&ifr.ifr_hwaddr.sa_data,6); 336 memcpy(&client_hardware_address[0], &ifr.ifr_hwaddr.sa_data, MAC_ADDR_LEN);
318 337
319#elif defined(__bsd__) 338#elif defined(__bsd__)
320 /* King 2004 see ACKNOWLEDGEMENTS */ 339 /* King 2004 see ACKNOWLEDGEMENTS */
321 340
322 size_t len; 341 size_t len;
323 int mib[6]; 342 int mib[6];
324 char *buf; 343 char *buf;
325 unsigned char *ptr; 344 unsigned char *ptr;
326 struct if_msghdr *ifm; 345 struct if_msghdr *ifm;
327 struct sockaddr_dl *sdl; 346 struct sockaddr_dl *sdl;
328 347
329 mib[0] = CTL_NET; 348 mib[0] = CTL_NET;
330 mib[1] = AF_ROUTE; 349 mib[1] = AF_ROUTE;
@@ -332,22 +351,22 @@ int get_hardware_address(int sock,char *interface_name){
332 mib[3] = AF_LINK; 351 mib[3] = AF_LINK;
333 mib[4] = NET_RT_IFLIST; 352 mib[4] = NET_RT_IFLIST;
334 353
335 if((mib[5] = if_nametoindex(interface_name)) == 0){ 354 if ((mib[5] = if_nametoindex(interface_name)) == 0) {
336 printf(_("Error: if_nametoindex error - %s.\n"), strerror(errno)); 355 printf(_("Error: if_nametoindex error - %s.\n"), strerror(errno));
337 exit(STATE_UNKNOWN); 356 exit(STATE_UNKNOWN);
338 } 357 }
339 358
340 if(sysctl(mib, 6, NULL, &len, NULL, 0) < 0){ 359 if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
341 printf(_("Error: Couldn't get hardware address from %s. sysctl 1 error - %s.\n"), interface_name, strerror(errno)); 360 printf(_("Error: Couldn't get hardware address from %s. sysctl 1 error - %s.\n"), interface_name, strerror(errno));
342 exit(STATE_UNKNOWN); 361 exit(STATE_UNKNOWN);
343 } 362 }
344 363
345 if((buf = malloc(len)) == NULL){ 364 if ((buf = malloc(len)) == NULL) {
346 printf(_("Error: Couldn't get hardware address from interface %s. malloc error - %s.\n"), interface_name, strerror(errno)); 365 printf(_("Error: Couldn't get hardware address from interface %s. malloc error - %s.\n"), interface_name, strerror(errno));
347 exit(4); 366 exit(4);
348 } 367 }
349 368
350 if(sysctl(mib, 6, buf, &len, NULL, 0) < 0){ 369 if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
351 printf(_("Error: Couldn't get hardware address from %s. sysctl 2 error - %s.\n"), interface_name, strerror(errno)); 370 printf(_("Error: Couldn't get hardware address from %s. sysctl 2 error - %s.\n"), interface_name, strerror(errno));
352 exit(STATE_UNKNOWN); 371 exit(STATE_UNKNOWN);
353 } 372 }
@@ -355,7 +374,7 @@ int get_hardware_address(int sock,char *interface_name){
355 ifm = (struct if_msghdr *)buf; 374 ifm = (struct if_msghdr *)buf;
356 sdl = (struct sockaddr_dl *)(ifm + 1); 375 sdl = (struct sockaddr_dl *)(ifm + 1);
357 ptr = (unsigned char *)LLADDR(sdl); 376 ptr = (unsigned char *)LLADDR(sdl);
358 memcpy(&client_hardware_address[0], ptr, 6) ; 377 memcpy(&client_hardware_address[0], ptr, 6);
359 /* King 2004 */ 378 /* King 2004 */
360 379
361#elif defined(__sun__) || defined(__solaris__) 380#elif defined(__sun__) || defined(__solaris__)
@@ -368,22 +387,22 @@ int get_hardware_address(int sock,char *interface_name){
368 387
369 /* get last number from interfacename, eg lnc0, e1000g0*/ 388 /* get last number from interfacename, eg lnc0, e1000g0*/
370 int i; 389 int i;
371 p = interface_name + strlen(interface_name) -1; 390 p = interface_name + strlen(interface_name) - 1;
372 for(i = strlen(interface_name) -1; i > 0; p--) { 391 for (i = strlen(interface_name) - 1; i > 0; p--) {
373 if(isalpha(*p)) 392 if (isalpha(*p)) {
374 break; 393 break;
394 }
375 } 395 }
376 p++; 396 p++;
377 if( p != interface_name ){ 397 if (p != interface_name) {
378 unit = atoi(p) ; 398 unit = atoi(p);
379 strncat(dev, interface_name, 6) ; 399 strncat(dev, interface_name, 6);
380 } 400 } else {
381 else{
382 printf(_("Error: can't find unit number in interface_name (%s) - expecting TypeNumber eg lnc0.\n"), interface_name); 401 printf(_("Error: can't find unit number in interface_name (%s) - expecting TypeNumber eg lnc0.\n"), interface_name);
383 exit(STATE_UNKNOWN); 402 exit(STATE_UNKNOWN);
384 } 403 }
385 stat = mac_addr_dlpi(dev, unit, client_hardware_address); 404 stat = mac_addr_dlpi(dev, unit, client_hardware_address);
386 if(stat != 0){ 405 if (stat != 0) {
387 printf(_("Error: can't read MAC address from DLPI streams interface for device %s unit %d.\n"), dev, unit); 406 printf(_("Error: can't read MAC address from DLPI streams interface for device %s unit %d.\n"), dev, unit);
388 exit(STATE_UNKNOWN); 407 exit(STATE_UNKNOWN);
389 } 408 }
@@ -391,11 +410,11 @@ int get_hardware_address(int sock,char *interface_name){
391#elif defined(__hpux__) 410#elif defined(__hpux__)
392 411
393 long stat; 412 long stat;
394 char dev[20] = "/dev/dlpi" ; 413 char dev[20] = "/dev/dlpi";
395 int unit = 0; 414 int unit = 0;
396 415
397 stat = mac_addr_dlpi(dev, unit, client_hardware_address); 416 stat = mac_addr_dlpi(dev, unit, client_hardware_address);
398 if(stat != 0){ 417 if (stat != 0) {
399 printf(_("Error: can't read MAC address from DLPI streams interface for device %s unit %d.\n"), dev, unit); 418 printf(_("Error: can't read MAC address from DLPI streams interface for device %s unit %d.\n"), dev, unit);
400 exit(STATE_UNKNOWN); 419 exit(STATE_UNKNOWN);
401 } 420 }
@@ -406,68 +425,69 @@ int get_hardware_address(int sock,char *interface_name){
406 exit(STATE_UNKNOWN); 425 exit(STATE_UNKNOWN);
407#endif 426#endif
408 427
409 if(verbose) 428 if (verbose) {
410 print_hardware_address(client_hardware_address); 429 print_hardware_address(client_hardware_address);
430 }
411 431
412 return OK; 432 return OK;
413} 433}
414 434
415/* determines IP address of the client interface */ 435/* determines IP address of the client interface */
416int get_ip_address(int sock,char *interface_name){ 436get_ip_address_wrapper get_ip_address(int sock, char *interface_name) {
417#if defined(SIOCGIFADDR) 437#if defined(SIOCGIFADDR)
418 struct ifreq ifr; 438 struct ifreq ifr;
419 439
420 strncpy((char *)&ifr.ifr_name,interface_name,sizeof(ifr.ifr_name)-1); 440 strncpy((char *)&ifr.ifr_name, interface_name, sizeof(ifr.ifr_name) - 1);
421 ifr.ifr_name[sizeof(ifr.ifr_name)-1]='\0'; 441 ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
422 442
423 if(ioctl(sock,SIOCGIFADDR,&ifr)<0){ 443 if (ioctl(sock, SIOCGIFADDR, &ifr) < 0) {
424 printf(_("Error: Cannot determine IP address of interface %s\n"), 444 printf(_("Error: Cannot determine IP address of interface %s\n"), interface_name);
425 interface_name);
426 exit(STATE_UNKNOWN); 445 exit(STATE_UNKNOWN);
427 } 446 }
428 447
429 my_ip=((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
430
431#else 448#else
432 printf(_("Error: Cannot get interface IP address on this platform.\n")); 449 printf(_("Error: Cannot get interface IP address on this platform.\n"));
433 exit(STATE_UNKNOWN); 450 exit(STATE_UNKNOWN);
434#endif 451#endif
435 452
436 if(verbose) 453 get_ip_address_wrapper result = {
437 printf(_("Pretending to be relay client %s\n"),inet_ntoa(my_ip)); 454 .error = OK,
455 .my_ip = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr,
456 };
438 457
439 return OK; 458 if (verbose) {
459 printf(_("Pretending to be relay client %s\n"), inet_ntoa(result.my_ip));
460 }
461
462 return result;
440} 463}
441 464
442/* sends a DHCPDISCOVER broadcast message in an attempt to find DHCP servers */ 465/* sends a DHCPDISCOVER broadcast message in an attempt to find DHCP servers */
443int send_dhcp_discover(int sock){ 466static send_dhcp_discover_wrapper send_dhcp_discover(int sock, bool unicast, struct in_addr dhcp_ip, struct in_addr requested_address,
444 dhcp_packet discover_packet; 467 bool request_specific_address, struct in_addr my_ip,
445 struct sockaddr_in sockaddr_broadcast; 468 unsigned char *client_hardware_address) {
446 unsigned short opts; 469 dhcp_packet discover_packet = {0};
447
448
449 /* clear the packet data structure */
450 bzero(&discover_packet,sizeof(discover_packet));
451
452
453 /* boot request flag (backward compatible with BOOTP servers) */ 470 /* boot request flag (backward compatible with BOOTP servers) */
454 discover_packet.op=BOOTREQUEST; 471 discover_packet.op = BOOTREQUEST;
455 472
456 /* hardware address type */ 473 /* hardware address type */
457 discover_packet.htype=ETHERNET_HARDWARE_ADDRESS; 474 discover_packet.htype = ETHERNET_HARDWARE_ADDRESS;
458 475
459 /* length of our hardware address */ 476 /* length of our hardware address */
460 discover_packet.hlen=ETHERNET_HARDWARE_ADDRESS_LENGTH; 477 discover_packet.hlen = ETHERNET_HARDWARE_ADDRESS_LENGTH;
461 478
479 send_dhcp_discover_wrapper result = {
480 .error = OK,
481 };
462 /* 482 /*
463 * transaction ID is supposed to be random. 483 * transaction ID is supposed to be random.
464 */ 484 */
465 srand(time(NULL)^getpid()); 485 srand(time(NULL) ^ getpid());
466 packet_xid=random(); 486 result.packet_xid = random();
467 discover_packet.xid=htonl(packet_xid); 487 discover_packet.xid = htonl(result.packet_xid);
468 488
469 /*discover_packet.secs=htons(65535);*/ 489 /*discover_packet.secs=htons(65535);*/
470 discover_packet.secs=0xFF; 490 discover_packet.secs = 0xFF;
471 491
472 /* 492 /*
473 * server needs to know if it should broadcast or unicast its response: 493 * server needs to know if it should broadcast or unicast its response:
@@ -476,408 +496,414 @@ int send_dhcp_discover(int sock){
476 discover_packet.flags = unicast ? 0 : htons(DHCP_BROADCAST_FLAG); 496 discover_packet.flags = unicast ? 0 : htons(DHCP_BROADCAST_FLAG);
477 497
478 /* our hardware address */ 498 /* our hardware address */
479 memcpy(discover_packet.chaddr,client_hardware_address,ETHERNET_HARDWARE_ADDRESS_LENGTH); 499 memcpy(discover_packet.chaddr, client_hardware_address, ETHERNET_HARDWARE_ADDRESS_LENGTH);
480 500
481 /* first four bytes of options field is magic cookie (as per RFC 2132) */ 501 /* first four bytes of options field is magic cookie (as per RFC 2132) */
482 discover_packet.options[0]='\x63'; 502 discover_packet.options[0] = '\x63';
483 discover_packet.options[1]='\x82'; 503 discover_packet.options[1] = '\x82';
484 discover_packet.options[2]='\x53'; 504 discover_packet.options[2] = '\x53';
485 discover_packet.options[3]='\x63'; 505 discover_packet.options[3] = '\x63';
486 506
487 opts = 4; 507 unsigned short opts = 4;
488 /* DHCP message type is embedded in options field */ 508 /* DHCP message type is embedded in options field */
489 discover_packet.options[opts++]=DHCP_OPTION_MESSAGE_TYPE; /* DHCP message type option identifier */ 509 discover_packet.options[opts++] = DHCP_OPTION_MESSAGE_TYPE; /* DHCP message type option identifier */
490 discover_packet.options[opts++]='\x01'; /* DHCP message option length in bytes */ 510 discover_packet.options[opts++] = '\x01'; /* DHCP message option length in bytes */
491 discover_packet.options[opts++]=DHCPDISCOVER; 511 discover_packet.options[opts++] = DHCPDISCOVER;
492 512
493 /* the IP address we're requesting */ 513 /* the IP address we're requesting */
494 if(request_specific_address){ 514 if (request_specific_address) {
495 discover_packet.options[opts++]=DHCP_OPTION_REQUESTED_ADDRESS; 515 discover_packet.options[opts++] = DHCP_OPTION_REQUESTED_ADDRESS;
496 discover_packet.options[opts++]='\x04'; 516 discover_packet.options[opts++] = '\x04';
497 memcpy(&discover_packet.options[opts],&requested_address,sizeof(requested_address)); 517 memcpy(&discover_packet.options[opts], &requested_address, sizeof(requested_address));
498 opts += sizeof(requested_address); 518 opts += sizeof(requested_address);
499 } 519 }
500 discover_packet.options[opts++]= (char)DHCP_OPTION_END; 520 discover_packet.options[opts++] = (char)DHCP_OPTION_END;
501 521
502 /* unicast fields */ 522 /* unicast fields */
503 if(unicast) 523 if (unicast) {
504 discover_packet.giaddr.s_addr = my_ip.s_addr; 524 discover_packet.giaddr.s_addr = my_ip.s_addr;
525 }
505 526
506 /* see RFC 1542, 4.1.1 */ 527 /* see RFC 1542, 4.1.1 */
507 discover_packet.hops = unicast ? 1 : 0; 528 discover_packet.hops = unicast ? 1 : 0;
508 529
509 /* send the DHCPDISCOVER packet to broadcast address */ 530 /* send the DHCPDISCOVER packet to broadcast address */
510 sockaddr_broadcast.sin_family=AF_INET; 531 struct sockaddr_in sockaddr_broadcast = {
511 sockaddr_broadcast.sin_port=htons(DHCP_SERVER_PORT); 532 .sin_family = AF_INET,
512 sockaddr_broadcast.sin_addr.s_addr = unicast ? dhcp_ip.s_addr : INADDR_BROADCAST; 533 .sin_port = htons(DHCP_SERVER_PORT),
513 bzero(&sockaddr_broadcast.sin_zero,sizeof(sockaddr_broadcast.sin_zero)); 534 .sin_addr.s_addr = unicast ? dhcp_ip.s_addr : INADDR_BROADCAST,
514 535 };
515 536
516 if(verbose){ 537 if (verbose) {
517 printf(_("DHCPDISCOVER to %s port %d\n"),inet_ntoa(sockaddr_broadcast.sin_addr),ntohs(sockaddr_broadcast.sin_port)); 538 printf(_("DHCPDISCOVER to %s port %d\n"), inet_ntoa(sockaddr_broadcast.sin_addr), ntohs(sockaddr_broadcast.sin_port));
518 printf("DHCPDISCOVER XID: %u (0x%X)\n",ntohl(discover_packet.xid),ntohl(discover_packet.xid)); 539 printf("DHCPDISCOVER XID: %u (0x%X)\n", ntohl(discover_packet.xid), ntohl(discover_packet.xid));
519 printf("DHCDISCOVER ciaddr: %s\n",inet_ntoa(discover_packet.ciaddr)); 540 printf("DHCDISCOVER ciaddr: %s\n", inet_ntoa(discover_packet.ciaddr));
520 printf("DHCDISCOVER yiaddr: %s\n",inet_ntoa(discover_packet.yiaddr)); 541 printf("DHCDISCOVER yiaddr: %s\n", inet_ntoa(discover_packet.yiaddr));
521 printf("DHCDISCOVER siaddr: %s\n",inet_ntoa(discover_packet.siaddr)); 542 printf("DHCDISCOVER siaddr: %s\n", inet_ntoa(discover_packet.siaddr));
522 printf("DHCDISCOVER giaddr: %s\n",inet_ntoa(discover_packet.giaddr)); 543 printf("DHCDISCOVER giaddr: %s\n", inet_ntoa(discover_packet.giaddr));
523 } 544 }
524 545
525 /* send the DHCPDISCOVER packet out */ 546 /* send the DHCPDISCOVER packet out */
526 send_dhcp_packet(&discover_packet,sizeof(discover_packet),sock,&sockaddr_broadcast); 547 send_dhcp_packet(&discover_packet, sizeof(discover_packet), sock, &sockaddr_broadcast);
527 548
528 if(verbose) 549 if (verbose) {
529 printf("\n\n"); 550 printf("\n\n");
551 }
530 552
531 return OK; 553 return result;
532} 554}
533 555
534
535
536
537/* waits for a DHCPOFFER message from one or more DHCP servers */ 556/* waits for a DHCPOFFER message from one or more DHCP servers */
538int get_dhcp_offer(int sock){ 557get_dhcp_offer_wrapper get_dhcp_offer(int sock, int dhcpoffer_timeout, uint32_t packet_xid, dhcp_offer *dhcp_offer_list,
539 dhcp_packet offer_packet; 558 const unsigned char *client_hardware_address) {
540 struct sockaddr_in source;
541 struct sockaddr_in via;
542 int result=OK;
543 int responses=0;
544 int x;
545 time_t start_time; 559 time_t start_time;
546 time_t current_time;
547
548 time(&start_time); 560 time(&start_time);
549 561
562 int result = OK;
563 int responses = 0;
564 int valid_responses = 0;
550 /* receive as many responses as we can */ 565 /* receive as many responses as we can */
551 for(responses=0,valid_responses=0;;){ 566 for (;;) {
552 567 time_t current_time;
553 time(&current_time); 568 time(&current_time);
554 if((current_time-start_time)>=dhcpoffer_timeout) 569 if ((current_time - start_time) >= dhcpoffer_timeout) {
555 break; 570 break;
571 }
556 572
557 if(verbose) 573 if (verbose) {
558 printf("\n\n"); 574 printf("\n\n");
575 }
559 576
560 bzero(&source,sizeof(source)); 577 struct sockaddr_in source = {0};
561 bzero(&via,sizeof(via)); 578 dhcp_packet offer_packet = {0};
562 bzero(&offer_packet,sizeof(offer_packet));
563 579
564 result=OK; 580 result = OK;
565 result=receive_dhcp_packet(&offer_packet,sizeof(offer_packet),sock,dhcpoffer_timeout,&source); 581 result = receive_dhcp_packet(&offer_packet, sizeof(offer_packet), sock, dhcpoffer_timeout, &source);
566 582
567 if(result!=OK){ 583 if (result != OK) {
568 if(verbose) 584 if (verbose) {
569 printf(_("Result=ERROR\n")); 585 printf(_("Result=ERROR\n"));
586 }
570 587
571 continue; 588 continue;
572 } 589 }
573 else{ 590 if (verbose) {
574 if(verbose) 591 printf(_("Result=OK\n"));
575 printf(_("Result=OK\n"));
576
577 responses++;
578 } 592 }
579 593
594 responses++;
595
580 /* The "source" is either a server or a relay. */ 596 /* The "source" is either a server or a relay. */
581 /* Save a copy of "source" into "via" even if it's via itself */ 597 /* Save a copy of "source" into "via" even if it's via itself */
582 memcpy(&via,&source,sizeof(source)) ; 598 struct sockaddr_in via = {0};
599 memcpy(&via, &source, sizeof(source));
583 600
584 if(verbose){ 601 if (verbose) {
585 printf(_("DHCPOFFER from IP address %s"),inet_ntoa(source.sin_addr)); 602 printf(_("DHCPOFFER from IP address %s"), inet_ntoa(source.sin_addr));
586 printf(_(" via %s\n"),inet_ntoa(via.sin_addr)); 603 printf(_(" via %s\n"), inet_ntoa(via.sin_addr));
587 printf("DHCPOFFER XID: %u (0x%X)\n",ntohl(offer_packet.xid),ntohl(offer_packet.xid)); 604 printf("DHCPOFFER XID: %u (0x%X)\n", ntohl(offer_packet.xid), ntohl(offer_packet.xid));
588 } 605 }
589 606
590 /* check packet xid to see if its the same as the one we used in the discover packet */ 607 /* check packet xid to see if its the same as the one we used in the discover packet */
591 if(ntohl(offer_packet.xid)!=packet_xid){ 608 if (ntohl(offer_packet.xid) != packet_xid) {
592 if(verbose) 609 if (verbose) {
593 printf(_("DHCPOFFER XID (%u) did not match DHCPDISCOVER XID (%u) - ignoring packet\n"),ntohl(offer_packet.xid),packet_xid); 610 printf(_("DHCPOFFER XID (%u) did not match DHCPDISCOVER XID (%u) - ignoring packet\n"), ntohl(offer_packet.xid),
611 packet_xid);
612 }
594 613
595 continue; 614 continue;
596 } 615 }
597 616
598 /* check hardware address */ 617 /* check hardware address */
599 result=OK; 618 result = OK;
600 if(verbose) 619 if (verbose) {
601 printf("DHCPOFFER chaddr: "); 620 printf("DHCPOFFER chaddr: ");
621 }
602 622
603 for(x=0;x<ETHERNET_HARDWARE_ADDRESS_LENGTH;x++){ 623 for (int i = 0; i < ETHERNET_HARDWARE_ADDRESS_LENGTH; i++) {
604 if(verbose) 624 if (verbose) {
605 printf("%02X",(unsigned char)offer_packet.chaddr[x]); 625 printf("%02X", offer_packet.chaddr[i]);
626 }
606 627
607 if(offer_packet.chaddr[x]!=client_hardware_address[x]) 628 if (offer_packet.chaddr[i] != client_hardware_address[i]) {
608 result=ERROR; 629 result = ERROR;
630 }
609 } 631 }
610 if(verbose) 632 if (verbose) {
611 printf("\n"); 633 printf("\n");
634 }
612 635
613 if(result==ERROR){ 636 if (result == ERROR) {
614 if(verbose) 637 if (verbose) {
615 printf(_("DHCPOFFER hardware address did not match our own - ignoring packet\n")); 638 printf(_("DHCPOFFER hardware address did not match our own - ignoring packet\n"));
639 }
616 640
617 continue; 641 continue;
618 } 642 }
619 643
620 if(verbose){ 644 if (verbose) {
621 printf("DHCPOFFER ciaddr: %s\n",inet_ntoa(offer_packet.ciaddr)); 645 printf("DHCPOFFER ciaddr: %s\n", inet_ntoa(offer_packet.ciaddr));
622 printf("DHCPOFFER yiaddr: %s\n",inet_ntoa(offer_packet.yiaddr)); 646 printf("DHCPOFFER yiaddr: %s\n", inet_ntoa(offer_packet.yiaddr));
623 printf("DHCPOFFER siaddr: %s\n",inet_ntoa(offer_packet.siaddr)); 647 printf("DHCPOFFER siaddr: %s\n", inet_ntoa(offer_packet.siaddr));
624 printf("DHCPOFFER giaddr: %s\n",inet_ntoa(offer_packet.giaddr)); 648 printf("DHCPOFFER giaddr: %s\n", inet_ntoa(offer_packet.giaddr));
625 } 649 }
626 650
627 add_dhcp_offer(source.sin_addr,&offer_packet); 651 add_dhcp_offer_wrapper add_res = add_dhcp_offer(source.sin_addr, &offer_packet, dhcp_offer_list);
652 if (add_res.error != OK) {
653 // TODO
654 } else {
655 dhcp_offer_list = add_res.dhcp_offer_list;
656 }
628 657
629 valid_responses++; 658 valid_responses++;
630 } 659 }
631 660
632 if(verbose){ 661 if (verbose) {
633 printf(_("Total responses seen on the wire: %d\n"),responses); 662 printf(_("Total responses seen on the wire: %d\n"), responses);
634 printf(_("Valid responses for this machine: %d\n"),valid_responses); 663 printf(_("Valid responses for this machine: %d\n"), valid_responses);
635 } 664 }
636 665
637 return OK; 666 get_dhcp_offer_wrapper ret_val = {
667 .error = OK,
668 .valid_responses = valid_responses,
669 .dhcp_offer_list = dhcp_offer_list,
670 };
671 return ret_val;
638} 672}
639 673
640
641
642/* sends a DHCP packet */ 674/* sends a DHCP packet */
643int send_dhcp_packet(void *buffer, int buffer_size, int sock, struct sockaddr_in *dest){ 675int send_dhcp_packet(void *buffer, int buffer_size, int sock, struct sockaddr_in *dest) {
644 int result; 676 int result = sendto(sock, (char *)buffer, buffer_size, 0, (struct sockaddr *)dest, sizeof(*dest));
645
646 result=sendto(sock,(char *)buffer,buffer_size,0,(struct sockaddr *)dest,sizeof(*dest));
647 677
648 if(verbose) 678 if (verbose) {
649 printf(_("send_dhcp_packet result: %d\n"),result); 679 printf(_("send_dhcp_packet result: %d\n"), result);
680 }
650 681
651 if(result<0) 682 if (result < 0) {
652 return ERROR; 683 return ERROR;
684 }
653 685
654 return OK; 686 return OK;
655} 687}
656 688
657
658
659/* receives a DHCP packet */ 689/* receives a DHCP packet */
660int receive_dhcp_packet(void *buffer, int buffer_size, int sock, int timeout, struct sockaddr_in *address){ 690int receive_dhcp_packet(void *buffer, int buffer_size, int sock, int timeout, struct sockaddr_in *address) {
661 struct timeval tv;
662 fd_set readfds;
663 fd_set oobfds;
664 int recv_result;
665 socklen_t address_size;
666 struct sockaddr_in source_address;
667 int nfound;
668
669
670 /* wait for data to arrive (up time timeout) */ 691 /* wait for data to arrive (up time timeout) */
671 tv.tv_sec=timeout; 692 struct timeval timeout_val = {
672 tv.tv_usec=0; 693 .tv_sec = timeout,
694 .tv_usec = 0,
695 };
696 fd_set readfds;
673 FD_ZERO(&readfds); 697 FD_ZERO(&readfds);
698 fd_set oobfds;
674 FD_ZERO(&oobfds); 699 FD_ZERO(&oobfds);
675 FD_SET(sock,&readfds); 700 FD_SET(sock, &readfds);
676 FD_SET(sock,&oobfds); 701 FD_SET(sock, &oobfds);
677 nfound = select(sock+1,&readfds,NULL,&oobfds,&tv); 702 int nfound = select(sock + 1, &readfds, NULL, &oobfds, &timeout_val);
678 703
679 /* make sure some data has arrived */ 704 /* make sure some data has arrived */
680 if(!FD_ISSET(sock,&readfds)){ 705 if (!FD_ISSET(sock, &readfds)) {
681 if(verbose) 706 if (verbose) {
682 printf(_("No (more) data received (nfound: %d)\n"), nfound); 707 printf(_("No (more) data received (nfound: %d)\n"), nfound);
708 }
683 return ERROR; 709 return ERROR;
684 } 710 }
685 711
686 else{ 712 struct sockaddr_in source_address = {0};
687 bzero(&source_address,sizeof(source_address)); 713 socklen_t address_size = sizeof(source_address);
688 address_size=sizeof(source_address); 714 int recv_result = recvfrom(sock, (char *)buffer, buffer_size, 0, (struct sockaddr *)&source_address, &address_size);
689 recv_result=recvfrom(sock,(char *)buffer,buffer_size,0,(struct sockaddr *)&source_address,&address_size); 715 if (verbose) {
690 if(verbose) 716 printf("recv_result: %d\n", recv_result);
691 printf("recv_result: %d\n",recv_result); 717 }
692
693 if(recv_result==-1){
694 if(verbose){
695 printf(_("recvfrom() failed, "));
696 printf("errno: (%d) -> %s\n",errno,strerror(errno));
697 }
698 return ERROR;
699 }
700 else{
701 if(verbose){
702 printf(_("receive_dhcp_packet() result: %d\n"),recv_result);
703 printf(_("receive_dhcp_packet() source: %s\n"),inet_ntoa(source_address.sin_addr));
704 }
705 718
706 memcpy(address,&source_address,sizeof(source_address)); 719 if (recv_result == -1) {
707 return OK; 720 if (verbose) {
721 printf(_("recvfrom() failed, "));
722 printf("errno: (%d) -> %s\n", errno, strerror(errno));
708 } 723 }
724 return ERROR;
725 }
726 if (verbose) {
727 printf(_("receive_dhcp_packet() result: %d\n"), recv_result);
728 printf(_("receive_dhcp_packet() source: %s\n"), inet_ntoa(source_address.sin_addr));
709 } 729 }
710 730
731 memcpy(address, &source_address, sizeof(source_address));
711 return OK; 732 return OK;
712} 733}
713 734
714
715/* creates a socket for DHCP communication */ 735/* creates a socket for DHCP communication */
716int create_dhcp_socket(void){ 736int create_dhcp_socket(bool unicast, char *network_interface_name) {
717 struct sockaddr_in myname;
718 struct ifreq interface;
719 int sock;
720 int flag=1;
721
722 /* Set up the address we're going to bind to. */ 737 /* Set up the address we're going to bind to. */
723 bzero(&myname,sizeof(myname));
724 myname.sin_family=AF_INET;
725 /* listen to DHCP server port if we're in unicast mode */ 738 /* listen to DHCP server port if we're in unicast mode */
726 myname.sin_port = htons(unicast ? DHCP_SERVER_PORT : DHCP_CLIENT_PORT); 739 struct sockaddr_in myname = {
727 myname.sin_addr.s_addr = unicast ? my_ip.s_addr : INADDR_ANY; 740 .sin_family = AF_INET,
728 bzero(&myname.sin_zero,sizeof(myname.sin_zero)); 741 .sin_port = htons(unicast ? DHCP_SERVER_PORT : DHCP_CLIENT_PORT),
742 // TODO previously the next line was trying to use our own IP, we was not set
743 // until some point later, so it was removed. Recheck whether it is actually
744 // necessary/useful
745 .sin_addr.s_addr = INADDR_ANY,
746 };
729 747
730 /* create a socket for DHCP communications */ 748 /* create a socket for DHCP communications */
731 sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); 749 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
732 if(sock<0){ 750 if (sock < 0) {
733 printf(_("Error: Could not create socket!\n")); 751 printf(_("Error: Could not create socket!\n"));
734 exit(STATE_UNKNOWN); 752 exit(STATE_UNKNOWN);
735 } 753 }
736 754
737 if(verbose) 755 if (verbose) {
738 printf("DHCP socket: %d\n",sock); 756 printf("DHCP socket: %d\n", sock);
757 }
739 758
740 /* set the reuse address flag so we don't get errors when restarting */ 759 /* set the reuse address flag so we don't get errors when restarting */
741 flag=1; 760 int flag = 1;
742 if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&flag,sizeof(flag))<0){ 761 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof(flag)) < 0) {
743 printf(_("Error: Could not set reuse address option on DHCP socket!\n")); 762 printf(_("Error: Could not set reuse address option on DHCP socket!\n"));
744 exit(STATE_UNKNOWN); 763 exit(STATE_UNKNOWN);
745 } 764 }
746 765
747 /* set the broadcast option - we need this to listen to DHCP broadcast messages */ 766 /* set the broadcast option - we need this to listen to DHCP broadcast messages */
748 if(!unicast && setsockopt(sock,SOL_SOCKET,SO_BROADCAST,(char *)&flag,sizeof flag)<0){ 767 if (!unicast && setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&flag, sizeof flag) < 0) {
749 printf(_("Error: Could not set broadcast option on DHCP socket!\n")); 768 printf(_("Error: Could not set broadcast option on DHCP socket!\n"));
750 exit(STATE_UNKNOWN); 769 exit(STATE_UNKNOWN);
751 } 770 }
752 771
772 struct ifreq interface;
753 /* bind socket to interface */ 773 /* bind socket to interface */
754#if defined(__linux__) 774#if defined(__linux__)
755 strncpy(interface.ifr_ifrn.ifrn_name,network_interface_name,IFNAMSIZ-1); 775 strncpy(interface.ifr_ifrn.ifrn_name, network_interface_name, IFNAMSIZ - 1);
756 interface.ifr_ifrn.ifrn_name[IFNAMSIZ-1]='\0'; 776 interface.ifr_ifrn.ifrn_name[IFNAMSIZ - 1] = '\0';
757 if(setsockopt(sock,SOL_SOCKET,SO_BINDTODEVICE,(char *)&interface,sizeof(interface))<0){ 777 if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (char *)&interface, sizeof(interface)) < 0) {
758 printf(_("Error: Could not bind socket to interface %s. Check your privileges...\n"),network_interface_name); 778 printf(_("Error: Could not bind socket to interface %s. Check your privileges...\n"), network_interface_name);
759 exit(STATE_UNKNOWN); 779 exit(STATE_UNKNOWN);
760 } 780 }
761 781
762#else 782#else
763 strncpy(interface.ifr_name,network_interface_name,IFNAMSIZ-1); 783 strncpy(interface.ifr_name, network_interface_name, IFNAMSIZ - 1);
764 interface.ifr_name[IFNAMSIZ-1]='\0'; 784 interface.ifr_name[IFNAMSIZ - 1] = '\0';
765#endif 785#endif
766 786
767 /* bind the socket */ 787 /* bind the socket */
768 if(bind(sock,(struct sockaddr *)&myname,sizeof(myname))<0){ 788 if (bind(sock, (struct sockaddr *)&myname, sizeof(myname)) < 0) {
769 printf(_("Error: Could not bind to DHCP socket (port %d)! Check your privileges...\n"),DHCP_CLIENT_PORT); 789 printf(_("Error: Could not bind to DHCP socket (port %d)! Check your privileges...\n"), DHCP_CLIENT_PORT);
770 exit(STATE_UNKNOWN); 790 exit(STATE_UNKNOWN);
771 } 791 }
772 792
773 return sock; 793 return sock;
774} 794}
775 795
776
777/* closes DHCP socket */ 796/* closes DHCP socket */
778int close_dhcp_socket(int sock){ 797int close_dhcp_socket(int sock) {
779
780 close(sock); 798 close(sock);
781
782 return OK; 799 return OK;
783} 800}
784 801
785
786/* adds a requested server address to list in memory */ 802/* adds a requested server address to list in memory */
787int add_requested_server(struct in_addr server_address){ 803int add_requested_server(struct in_addr server_address, int *requested_servers, requested_server **requested_server_list) {
788 requested_server *new_server; 804 requested_server *new_server = (requested_server *)malloc(sizeof(requested_server));
789 805 if (new_server == NULL) {
790 new_server=(requested_server *)malloc(sizeof(requested_server));
791 if(new_server==NULL)
792 return ERROR; 806 return ERROR;
807 }
793 808
794 new_server->server_address=server_address; 809 new_server->server_address = server_address;
795 new_server->answered=false; 810 new_server->answered = false;
796 811
797 new_server->next=requested_server_list; 812 new_server->next = *requested_server_list;
798 requested_server_list=new_server; 813 *requested_server_list = new_server;
799 814
800 requested_servers++; 815 *requested_servers += 1;
801 816
802 if(verbose) 817 if (verbose) {
803 printf(_("Requested server address: %s\n"),inet_ntoa(new_server->server_address)); 818 printf(_("Requested server address: %s\n"), inet_ntoa(new_server->server_address));
819 }
804 820
805 return OK; 821 return OK;
806} 822}
807 823
808
809
810
811/* adds a DHCP OFFER to list in memory */ 824/* adds a DHCP OFFER to list in memory */
812int add_dhcp_offer(struct in_addr source,dhcp_packet *offer_packet){ 825add_dhcp_offer_wrapper add_dhcp_offer(struct in_addr source, dhcp_packet *offer_packet, dhcp_offer *dhcp_offer_list) {
826 if (offer_packet == NULL) {
827 add_dhcp_offer_wrapper tmp = {
828 .error = ERROR,
829 };
830 return tmp;
831 }
832
833 uint32_t dhcp_lease_time = 0;
834 uint32_t dhcp_renewal_time = 0;
835 uint32_t dhcp_rebinding_time = 0;
813 dhcp_offer *new_offer; 836 dhcp_offer *new_offer;
814 int x;
815 unsigned option_type;
816 unsigned option_length;
817 struct in_addr serv_ident = {0}; 837 struct in_addr serv_ident = {0};
818
819 if(offer_packet==NULL)
820 return ERROR;
821
822 /* process all DHCP options present in the packet */ 838 /* process all DHCP options present in the packet */
823 for(x=4;x<MAX_DHCP_OPTIONS_LENGTH-1;){ 839 for (int dchp_opt_idx = 4; dchp_opt_idx < MAX_DHCP_OPTIONS_LENGTH - 1;) {
824 840
825 if((int)offer_packet->options[x]==-1) 841 if ((int)offer_packet->options[dchp_opt_idx] == -1) {
826 break; 842 break;
843 }
827 844
828 /* get option type */ 845 /* get option type */
829 option_type=offer_packet->options[x++]; 846 unsigned option_type = offer_packet->options[dchp_opt_idx++];
830 847
831 /* get option length */ 848 /* get option length */
832 option_length=offer_packet->options[x++]; 849 unsigned option_length = offer_packet->options[dchp_opt_idx++];
833 850
834 if(verbose) 851 if (verbose) {
835 printf("Option: %d (0x%02X)\n",option_type,option_length); 852 printf("Option: %d (0x%02X)\n", option_type, option_length);
853 }
836 854
837 /* get option data */ 855 /* get option data */
838 switch(option_type){ 856 switch (option_type) {
839 case DHCP_OPTION_LEASE_TIME: 857 case DHCP_OPTION_LEASE_TIME:
840 memcpy(&dhcp_lease_time, &offer_packet->options[x],sizeof(dhcp_lease_time)); 858 memcpy(&dhcp_lease_time, &offer_packet->options[dchp_opt_idx], sizeof(dhcp_lease_time));
841 dhcp_lease_time = ntohl(dhcp_lease_time); 859 dhcp_lease_time = ntohl(dhcp_lease_time);
842 break; 860 break;
843 case DHCP_OPTION_RENEWAL_TIME: 861 case DHCP_OPTION_RENEWAL_TIME:
844 memcpy(&dhcp_renewal_time, &offer_packet->options[x],sizeof(dhcp_renewal_time)); 862 memcpy(&dhcp_renewal_time, &offer_packet->options[dchp_opt_idx], sizeof(dhcp_renewal_time));
845 dhcp_renewal_time = ntohl(dhcp_renewal_time); 863 dhcp_renewal_time = ntohl(dhcp_renewal_time);
846 break; 864 break;
847 case DHCP_OPTION_REBINDING_TIME: 865 case DHCP_OPTION_REBINDING_TIME:
848 memcpy(&dhcp_rebinding_time, &offer_packet->options[x],sizeof(dhcp_rebinding_time)); 866 memcpy(&dhcp_rebinding_time, &offer_packet->options[dchp_opt_idx], sizeof(dhcp_rebinding_time));
849 dhcp_rebinding_time = ntohl(dhcp_rebinding_time); 867 dhcp_rebinding_time = ntohl(dhcp_rebinding_time);
850 break; 868 break;
851 case DHCP_OPTION_SERVER_IDENTIFIER: 869 case DHCP_OPTION_SERVER_IDENTIFIER:
852 memcpy(&serv_ident.s_addr, &offer_packet->options[x],sizeof(serv_ident.s_addr)); 870 memcpy(&serv_ident.s_addr, &offer_packet->options[dchp_opt_idx], sizeof(serv_ident.s_addr));
853 break; 871 break;
854 } 872 }
855 873
856 /* skip option data we're ignoring */ 874 /* skip option data we're ignoring */
857 if(option_type==0) /* "pad" option, see RFC 2132 (3.1) */ 875 if (option_type == 0) { /* "pad" option, see RFC 2132 (3.1) */
858 x+=1; 876 dchp_opt_idx += 1;
859 else 877 } else {
860 x+=option_length; 878 dchp_opt_idx += option_length;
879 }
861 } 880 }
862 881
863 if(verbose){ 882 if (verbose) {
864 if(dhcp_lease_time==DHCP_INFINITE_TIME) 883 if (dhcp_lease_time == DHCP_INFINITE_TIME) {
865 printf(_("Lease Time: Infinite\n")); 884 printf(_("Lease Time: Infinite\n"));
866 else 885 } else {
867 printf(_("Lease Time: %lu seconds\n"),(unsigned long)dhcp_lease_time); 886 printf(_("Lease Time: %lu seconds\n"), (unsigned long)dhcp_lease_time);
868 if(dhcp_renewal_time==DHCP_INFINITE_TIME) 887 }
888 if (dhcp_renewal_time == DHCP_INFINITE_TIME) {
869 printf(_("Renewal Time: Infinite\n")); 889 printf(_("Renewal Time: Infinite\n"));
870 else 890 } else {
871 printf(_("Renewal Time: %lu seconds\n"),(unsigned long)dhcp_renewal_time); 891 printf(_("Renewal Time: %lu seconds\n"), (unsigned long)dhcp_renewal_time);
872 if(dhcp_rebinding_time==DHCP_INFINITE_TIME) 892 }
893 if (dhcp_rebinding_time == DHCP_INFINITE_TIME) {
873 printf(_("Rebinding Time: Infinite\n")); 894 printf(_("Rebinding Time: Infinite\n"));
874 printf(_("Rebinding Time: %lu seconds\n"),(unsigned long)dhcp_rebinding_time); 895 }
896 printf(_("Rebinding Time: %lu seconds\n"), (unsigned long)dhcp_rebinding_time);
875 } 897 }
876 898
877 new_offer=(dhcp_offer *)malloc(sizeof(dhcp_offer)); 899 new_offer = (dhcp_offer *)malloc(sizeof(dhcp_offer));
878 900
879 if(new_offer==NULL) 901 if (new_offer == NULL) {
880 return ERROR; 902 add_dhcp_offer_wrapper tmp = {
903 .error = ERROR,
904 };
905 return tmp;
906 }
881 907
882 /* 908 /*
883 * RFC 2131 (2.) says: "DHCP clarifies the interpretation of the 909 * RFC 2131 (2.) says: "DHCP clarifies the interpretation of the
@@ -891,298 +917,336 @@ int add_dhcp_offer(struct in_addr source,dhcp_packet *offer_packet){
891 * DHCPOFFER from. If 'serv_ident' isn't available for some reason, we 917 * DHCPOFFER from. If 'serv_ident' isn't available for some reason, we
892 * use 'source'. 918 * use 'source'.
893 */ 919 */
894 new_offer->server_address=serv_ident.s_addr?serv_ident:source; 920 new_offer->server_address = serv_ident.s_addr ? serv_ident : source;
895 new_offer->offered_address=offer_packet->yiaddr; 921 new_offer->offered_address = offer_packet->yiaddr;
896 new_offer->lease_time=dhcp_lease_time; 922 new_offer->lease_time = dhcp_lease_time;
897 new_offer->renewal_time=dhcp_renewal_time; 923 new_offer->renewal_time = dhcp_renewal_time;
898 new_offer->rebinding_time=dhcp_rebinding_time; 924 new_offer->rebinding_time = dhcp_rebinding_time;
899 new_offer->desired=false; /* exclusive mode: we'll check that in get_results */ 925 new_offer->desired = false; /* exclusive mode: we'll check that in get_results */
900 926
901 927 if (verbose) {
902 if(verbose){ 928 printf(_("Added offer from server @ %s"), inet_ntoa(new_offer->server_address));
903 printf(_("Added offer from server @ %s"),inet_ntoa(new_offer->server_address)); 929 printf(_(" of IP address %s\n"), inet_ntoa(new_offer->offered_address));
904 printf(_(" of IP address %s\n"),inet_ntoa(new_offer->offered_address));
905 } 930 }
906 931
907 /* add new offer to head of list */ 932 /* add new offer to head of list */
908 new_offer->next=dhcp_offer_list; 933 new_offer->next = dhcp_offer_list;
909 dhcp_offer_list=new_offer; 934 dhcp_offer_list = new_offer;
910 935
911 return OK; 936 add_dhcp_offer_wrapper result = {
912} 937 .error = OK,
938 .dhcp_offer_list = dhcp_offer_list,
939 };
913 940
941 return result;
942}
914 943
915/* frees memory allocated to DHCP OFFER list */ 944/* frees memory allocated to DHCP OFFER list */
916int free_dhcp_offer_list(void){ 945int free_dhcp_offer_list(dhcp_offer *dhcp_offer_list) {
917 dhcp_offer *this_offer;
918 dhcp_offer *next_offer; 946 dhcp_offer *next_offer;
919 947 for (dhcp_offer *this_offer = dhcp_offer_list; this_offer != NULL; this_offer = next_offer) {
920 for(this_offer=dhcp_offer_list;this_offer!=NULL;this_offer=next_offer){ 948 next_offer = this_offer->next;
921 next_offer=this_offer->next;
922 free(this_offer); 949 free(this_offer);
923 } 950 }
924 951
925 return OK; 952 return OK;
926} 953}
927 954
928
929/* frees memory allocated to requested server list */ 955/* frees memory allocated to requested server list */
930int free_requested_server_list(void){ 956int free_requested_server_list(requested_server *requested_server_list) {
931 requested_server *this_server;
932 requested_server *next_server; 957 requested_server *next_server;
933 958 for (requested_server *this_server = requested_server_list; this_server != NULL; this_server = next_server) {
934 for(this_server=requested_server_list;this_server!=NULL;this_server=next_server){ 959 next_server = this_server->next;
935 next_server=this_server->next;
936 free(this_server); 960 free(this_server);
937 } 961 }
938 962
939 return OK; 963 return OK;
940} 964}
941 965
942
943/* gets state and plugin output to return */ 966/* gets state and plugin output to return */
944int get_results(void){ 967mp_subcheck get_results(bool exclusive, const int requested_servers, const struct in_addr requested_address, bool request_specific_address,
945 dhcp_offer *temp_offer, *undesired_offer=NULL; 968 requested_server *requested_server_list, int valid_responses, dhcp_offer *dhcp_offer_list) {
946 requested_server *temp_server; 969 mp_subcheck sc_dhcp_results = mp_subcheck_init();
947 int result; 970 sc_dhcp_results = mp_set_subcheck_default_state(sc_dhcp_results, STATE_OK);
948 uint32_t max_lease_time=0;
949
950 received_requested_address=false;
951 971
952 /* checks responses from requested servers */ 972 /* we didn't receive any DHCPOFFERs */
953 requested_responses=0; 973 if (dhcp_offer_list == NULL) {
954 if(requested_servers>0){ 974 sc_dhcp_results = mp_set_subcheck_state(sc_dhcp_results, STATE_CRITICAL);
975 xasprintf(&sc_dhcp_results.output, "%s", "No DHCPOFFERs were received");
976 return sc_dhcp_results;
977 }
955 978
956 for(temp_server=requested_server_list;temp_server!=NULL;temp_server=temp_server->next){ 979 if (valid_responses == 0) {
980 // No valid responses at all, so early exit here
981 sc_dhcp_results = mp_set_subcheck_state(sc_dhcp_results, STATE_CRITICAL);
982 xasprintf(&sc_dhcp_results.output, "No valid responses received");
983 return sc_dhcp_results;
984 }
957 985
958 for(temp_offer=dhcp_offer_list;temp_offer!=NULL;temp_offer=temp_offer->next){ 986 if (valid_responses == 1) {
987 xasprintf(&sc_dhcp_results.output, "Received %d DHCPOFFER", valid_responses);
988 } else {
989 xasprintf(&sc_dhcp_results.output, "Received %d DHCPOFFERs", valid_responses);
990 }
959 991
992 bool received_requested_address = false;
993 dhcp_offer *undesired_offer = NULL;
994 uint32_t max_lease_time = 0;
995 /* checks responses from requested servers */
996 int requested_responses = 0;
997 if (requested_servers > 0) {
998 for (requested_server *temp_server = requested_server_list; temp_server != NULL; temp_server = temp_server->next) {
999 for (dhcp_offer *temp_offer = dhcp_offer_list; temp_offer != NULL; temp_offer = temp_offer->next) {
960 /* get max lease time we were offered */ 1000 /* get max lease time we were offered */
961 if(temp_offer->lease_time>max_lease_time || temp_offer->lease_time==DHCP_INFINITE_TIME) 1001 if (temp_offer->lease_time > max_lease_time || temp_offer->lease_time == DHCP_INFINITE_TIME) {
962 max_lease_time=temp_offer->lease_time; 1002 max_lease_time = temp_offer->lease_time;
1003 }
963 1004
964 /* see if we got the address we requested */ 1005 /* see if we got the address we requested */
965 if(!memcmp(&requested_address,&temp_offer->offered_address,sizeof(requested_address))) 1006 if (!memcmp(&requested_address, &temp_offer->offered_address, sizeof(requested_address))) {
966 received_requested_address=true; 1007 received_requested_address = true;
967 1008 }
968 /* see if the servers we wanted a response from talked to us or not */ 1009
969 if(!memcmp(&temp_offer->server_address,&temp_server->server_address,sizeof(temp_server->server_address))){ 1010 /* see if the servers we wanted a response from, talked to us or not */
970 if(verbose){ 1011 if (!memcmp(&temp_offer->server_address, &temp_server->server_address, sizeof(temp_server->server_address))) {
971 printf(_("DHCP Server Match: Offerer=%s"),inet_ntoa(temp_offer->server_address)); 1012 if (verbose) {
972 printf(_(" Requested=%s"),inet_ntoa(temp_server->server_address)); 1013 printf(_("DHCP Server Match: Offerer=%s"), inet_ntoa(temp_offer->server_address));
973 if(temp_server->answered) 1014 printf(_(" Requested=%s"), inet_ntoa(temp_server->server_address));
1015 if (temp_server->answered) {
974 printf(_(" (duplicate)")); 1016 printf(_(" (duplicate)"));
1017 }
975 printf(_("\n")); 1018 printf(_("\n"));
976 } 1019 }
977 if(!temp_server->answered){ 1020
1021 if (!temp_server->answered) {
978 requested_responses++; 1022 requested_responses++;
979 temp_server->answered=true; 1023 temp_server->answered = true;
980 temp_offer->desired=true; 1024 temp_offer->desired = true;
981 } 1025 }
982 } 1026 }
983 } 1027 }
984 } 1028 }
985 1029
986 /* exclusive mode: check for undesired offers */ 1030 /* exclusive mode: check for undesired offers */
987 for(temp_offer=dhcp_offer_list;temp_offer!=NULL;temp_offer=temp_offer->next) { 1031 for (dhcp_offer *temp_offer = dhcp_offer_list; temp_offer != NULL; temp_offer = temp_offer->next) {
988 if (!temp_offer->desired) { 1032 if (!temp_offer->desired) {
989 undesired_offer=temp_offer; /* Checks only for the first undesired offer */ 1033 undesired_offer = temp_offer; /* Checks only for the first undesired offer */
990 break; /* no further checks needed */ 1034 break; /* no further checks needed */
991 } 1035 }
992 } 1036 }
993 }
994
995 /* else check and see if we got our requested address from any server */
996 else{
997 1037
998 for(temp_offer=dhcp_offer_list;temp_offer!=NULL;temp_offer=temp_offer->next){ 1038 mp_subcheck sc_rqust_srvs = mp_subcheck_init();
1039 xasprintf(&sc_rqust_srvs.output, "%d of %d requested servers responded", requested_responses, requested_servers);
1040
1041 if (requested_responses == requested_servers) {
1042 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_OK);
1043 } else if (requested_responses == 0) {
1044 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_CRITICAL);
1045 } else if (requested_responses < requested_servers) {
1046 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_WARNING);
1047 } else {
1048 // We received more(!) responses than we asked for?
1049 // This case shouldn't happen, but is here for completion
1050 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_WARNING);
1051 }
1052 mp_add_subcheck_to_subcheck(&sc_dhcp_results, sc_rqust_srvs);
999 1053
1054 } else {
1055 /* else check and see if we got our requested address from any server */
1056 for (dhcp_offer *temp_offer = dhcp_offer_list; temp_offer != NULL; temp_offer = temp_offer->next) {
1000 /* get max lease time we were offered */ 1057 /* get max lease time we were offered */
1001 if(temp_offer->lease_time>max_lease_time || temp_offer->lease_time==DHCP_INFINITE_TIME) 1058 if (temp_offer->lease_time > max_lease_time || temp_offer->lease_time == DHCP_INFINITE_TIME) {
1002 max_lease_time=temp_offer->lease_time; 1059 max_lease_time = temp_offer->lease_time;
1060 }
1003 1061
1004 /* see if we got the address we requested */ 1062 /* see if we got the address we requested */
1005 if(!memcmp(&requested_address,&temp_offer->offered_address,sizeof(requested_address))) 1063 if (!memcmp(&requested_address, &temp_offer->offered_address, sizeof(requested_address))) {
1006 received_requested_address=true; 1064 received_requested_address = true;
1065 }
1007 } 1066 }
1008 } 1067 }
1009 1068
1010 result=STATE_OK; 1069 if (max_lease_time == DHCP_INFINITE_TIME) {
1011 if(valid_responses==0) 1070 xasprintf(&sc_dhcp_results.output, "%s, max lease time = Infinity", sc_dhcp_results.output);
1012 result=STATE_CRITICAL; 1071 } else {
1013 else if(requested_servers>0 && requested_responses==0) 1072 xasprintf(&sc_dhcp_results.output, "%s, max lease time = %" PRIu32 " seconds", sc_dhcp_results.output, max_lease_time);
1014 result=STATE_CRITICAL;
1015 else if(requested_responses<requested_servers)
1016 result=STATE_WARNING;
1017 else if(request_specific_address && !received_requested_address)
1018 result=STATE_WARNING;
1019
1020 if(exclusive && undesired_offer)
1021 result=STATE_CRITICAL;
1022
1023 if(result==0) /* garrett honeycutt 2005 */
1024 printf("OK: ");
1025 else if(result==1)
1026 printf("WARNING: ");
1027 else if(result==2)
1028 printf("CRITICAL: ");
1029 else if(result==3)
1030 printf("UNKNOWN: ");
1031
1032 /* we didn't receive any DHCPOFFERs */
1033 if(dhcp_offer_list==NULL){
1034 printf(_("No DHCPOFFERs were received.\n"));
1035 return result;
1036 } 1073 }
1037 1074
1038 printf(_("Received %d DHCPOFFER(s)"),valid_responses); 1075 if (exclusive) {
1076 mp_subcheck sc_rogue_server = mp_subcheck_init();
1039 1077
1078 if (undesired_offer != NULL) {
1079 // We wanted to get a DHCPOFFER exclusively from one machine, but another one
1080 // sent one (too)
1081 sc_rogue_server = mp_set_subcheck_state(sc_rogue_server, STATE_CRITICAL);
1040 1082
1041 if(exclusive && undesired_offer){ 1083 // Get the addresses for printout
1042 printf(_(", Rogue DHCP Server detected! Server %s"),inet_ntoa(undesired_offer->server_address)); 1084 // 1.address of the sending server
1043 printf(_(" offered %s \n"),inet_ntoa(undesired_offer->offered_address)); 1085 char server_address[INET_ADDRSTRLEN];
1044 return result; 1086 const char *server_address_transformed =
1045 } 1087 inet_ntop(AF_INET, &undesired_offer->server_address, server_address, sizeof(server_address));
1046 1088
1047 if(requested_servers>0) 1089 if (server_address != server_address_transformed) {
1048 printf(_(", %s%d of %d requested servers responded"),((requested_responses<requested_servers) && requested_responses>0)?"only ":"",requested_responses,requested_servers); 1090 die(STATE_UNKNOWN, "inet_ntop failed");
1091 }
1049 1092
1050 if(request_specific_address) 1093 // 2.address offered
1051 printf(_(", requested address (%s) was %soffered"),inet_ntoa(requested_address),(received_requested_address)?"":_("not ")); 1094 char offered_address[INET_ADDRSTRLEN];
1095 const char *offered_address_transformed =
1096 inet_ntop(AF_INET, &undesired_offer->offered_address, offered_address, sizeof(offered_address));
1052 1097
1053 printf(_(", max lease time = ")); 1098 if (offered_address != offered_address_transformed) {
1054 if(max_lease_time==DHCP_INFINITE_TIME) 1099 die(STATE_UNKNOWN, "inet_ntop failed");
1055 printf(_("Infinity")); 1100 }
1056 else
1057 printf("%lu sec",(unsigned long)max_lease_time);
1058 1101
1059 printf(".\n"); 1102 xasprintf(&sc_rogue_server.output, "Rogue DHCP Server detected! Server %s offered %s", server_address, offered_address);
1103 } else {
1104 sc_rogue_server = mp_set_subcheck_state(sc_rogue_server, STATE_OK);
1105 xasprintf(&sc_rogue_server.output, "No Rogue DHCP Server detected");
1106 }
1107 mp_add_subcheck_to_subcheck(&sc_dhcp_results, sc_rogue_server);
1108 }
1060 1109
1061 return result; 1110 if (request_specific_address) {
1062} 1111 mp_subcheck sc_rqustd_addr = mp_subcheck_init();
1063 1112
1113 if (received_requested_address) {
1114 sc_rqustd_addr = mp_set_subcheck_state(sc_rqustd_addr, STATE_OK);
1115 xasprintf(&sc_rqustd_addr.output, "Requested address (%s) was offered", inet_ntoa(requested_address));
1116 } else {
1117 sc_rqustd_addr = mp_set_subcheck_state(sc_rqustd_addr, STATE_WARNING);
1118 xasprintf(&sc_rqustd_addr.output, "Requested address (%s) was NOT offered", inet_ntoa(requested_address));
1119 }
1064 1120
1065/* process command-line arguments */ 1121 mp_add_subcheck_to_subcheck(&sc_dhcp_results, sc_rqustd_addr);
1066int process_arguments(int argc, char **argv){ 1122 }
1067 if(argc<1)
1068 return ERROR;
1069 1123
1070 call_getopt(argc,argv); 1124 return sc_dhcp_results;
1071 return validate_arguments(argc);
1072} 1125}
1073 1126
1127/* process command-line arguments */
1128process_arguments_wrapper process_arguments(int argc, char **argv) {
1129 if (argc < 1) {
1130 process_arguments_wrapper tmp = {
1131 .error = ERROR,
1132 };
1133 return tmp;
1134 }
1074 1135
1075 1136 enum {
1076int call_getopt(int argc, char **argv){ 1137 output_format_index = CHAR_MAX + 1,
1077 extern int optind;
1078 int option_index = 0;
1079 static struct option long_options[] =
1080 {
1081 {"serverip", required_argument,0,'s'},
1082 {"requestedip", required_argument,0,'r'},
1083 {"timeout", required_argument,0,'t'},
1084 {"interface", required_argument,0,'i'},
1085 {"mac", required_argument,0,'m'},
1086 {"unicast", no_argument, 0,'u'},
1087 {"exclusive", no_argument, 0,'x'},
1088 {"verbose", no_argument, 0,'v'},
1089 {"version", no_argument, 0,'V'},
1090 {"help", no_argument, 0,'h'},
1091 {0,0,0,0}
1092 }; 1138 };
1093 1139
1094 int c=0; 1140 int option_index = 0;
1095 while(true){ 1141 static struct option long_options[] = {{"serverip", required_argument, 0, 's'},
1096 c=getopt_long(argc,argv,"+hVvxt:s:r:t:i:m:u",long_options,&option_index); 1142 {"requestedip", required_argument, 0, 'r'},
1097 1143 {"timeout", required_argument, 0, 't'},
1098 if(c==-1||c==EOF||c==1) 1144 {"interface", required_argument, 0, 'i'},
1145 {"mac", required_argument, 0, 'm'},
1146 {"unicast", no_argument, 0, 'u'},
1147 {"exclusive", no_argument, 0, 'x'},
1148 {"verbose", no_argument, 0, 'v'},
1149 {"version", no_argument, 0, 'V'},
1150 {"help", no_argument, 0, 'h'},
1151 {"output-format", required_argument, 0, output_format_index},
1152 {0, 0, 0, 0}};
1153
1154 check_dhcp_config config = check_dhcp_config_init();
1155 int option_char = 0;
1156 while (true) {
1157 option_char = getopt_long(argc, argv, "+hVvxt:s:r:t:i:m:u", long_options, &option_index);
1158
1159 if (option_char == -1 || option_char == EOF || option_char == 1) {
1099 break; 1160 break;
1161 }
1100 1162
1101 switch(c){ 1163 switch (option_char) {
1102 1164 case 's': /* DHCP server address */
1103 case 's': /* DHCP server address */ 1165 resolve_host(optarg, &config.dhcp_ip);
1104 resolve_host(optarg,&dhcp_ip); 1166 add_requested_server(config.dhcp_ip, &config.num_of_requested_servers, &config.requested_server_list);
1105 add_requested_server(dhcp_ip); 1167 break;
1106 break;
1107
1108 case 'r': /* address we are requested from DHCP servers */
1109 resolve_host(optarg,&requested_address);
1110 request_specific_address=true;
1111 break;
1112
1113 case 't': /* timeout */
1114
1115 /*
1116 if(is_intnonneg(optarg))
1117 */
1118 if(atoi(optarg)>0)
1119 dhcpoffer_timeout=atoi(optarg);
1120 /*
1121 else
1122 usage("Time interval must be a nonnegative integer\n");
1123 */
1124 break;
1125 1168
1126 case 'm': /* MAC address */ 1169 case 'r': /* address we are requested from DHCP servers */
1170 resolve_host(optarg, &config.requested_address);
1171 config.request_specific_address = true;
1172 break;
1127 1173
1128 if((user_specified_mac=mac_aton(optarg)) == NULL) 1174 case 't': /* timeout */
1129 usage("Cannot parse MAC address.\n"); 1175 if (atoi(optarg) > 0) {
1130 if(verbose) 1176 config.dhcpoffer_timeout = atoi(optarg);
1131 print_hardware_address(user_specified_mac); 1177 }
1178 break;
1132 1179
1133 break; 1180 case 'm': /* MAC address */
1181 if ((config.user_specified_mac = mac_aton(optarg)) == NULL) {
1182 usage("Cannot parse MAC address.\n");
1183 }
1184 if (verbose) {
1185 print_hardware_address(config.user_specified_mac);
1186 }
1187 break;
1134 1188
1135 case 'i': /* interface name */ 1189 case 'i': /* interface name */
1190 strncpy(config.network_interface_name, optarg, sizeof(config.network_interface_name) - 1);
1191 config.network_interface_name[sizeof(config.network_interface_name) - 1] = '\x0';
1192 break;
1136 1193
1137 strncpy(network_interface_name,optarg,sizeof(network_interface_name)-1); 1194 case 'u': /* unicast testing */
1138 network_interface_name[sizeof(network_interface_name)-1]='\x0'; 1195 config.unicast_mode = true;
1196 break;
1139 1197
1140 break; 1198 case 'x': /* exclusive testing aka "rogue DHCP server detection" */
1199 config.exclusive_mode = true;
1200 break;
1141 1201
1142 case 'u': /* unicast testing */ 1202 case 'V': /* version */
1143 unicast=true; 1203 print_revision(progname, NP_VERSION);
1144 break; 1204 exit(STATE_UNKNOWN);
1145 case 'x': /* exclusive testing aka "rogue DHCP server detection" */
1146 exclusive=true;
1147 break;
1148 1205
1149 case 'V': /* version */ 1206 case 'h': /* help */
1150 print_revision(progname, NP_VERSION); 1207 print_help();
1151 exit(STATE_UNKNOWN); 1208 exit(STATE_UNKNOWN);
1152 1209
1153 case 'h': /* help */ 1210 case 'v': /* verbose */
1154 print_help(); 1211 verbose = 1;
1212 break;
1213 case output_format_index: {
1214 parsed_output_format parser = mp_parse_output_format(optarg);
1215 if (!parser.parsing_success) {
1216 // TODO List all available formats here, maybe add anothoer usage function
1217 printf("Invalid output format: %s\n", optarg);
1155 exit(STATE_UNKNOWN); 1218 exit(STATE_UNKNOWN);
1219 }
1156 1220
1157 case 'v': /* verbose */ 1221 config.output_format_is_set = true;
1158 verbose=1; 1222 config.output_format = parser.output_format;
1159 break; 1223 break;
1160 case '?': /* help */ 1224 }
1161 usage5 (); 1225 case '?': /* help */
1162 break; 1226 usage5();
1227 break;
1163 1228
1164 default: 1229 default:
1165 break; 1230 break;
1166 } 1231 }
1167 } 1232 }
1168 return optind;
1169}
1170 1233
1171 1234 if (argc - optind > 0) {
1172int validate_arguments(int argc){
1173
1174 if(argc - optind > 0)
1175 usage(_("Got unexpected non-option argument")); 1235 usage(_("Got unexpected non-option argument"));
1236 }
1176 1237
1177 return OK; 1238 process_arguments_wrapper result = {
1239 .config = config,
1240 .error = OK,
1241 };
1242 return result;
1178} 1243}
1179 1244
1180
1181#if defined(__sun__) || defined(__solaris__) || defined(__hpux__) 1245#if defined(__sun__) || defined(__solaris__) || defined(__hpux__)
1182/* Kompf 2000-2003 see ACKNOWLEDGEMENTS */ 1246/* Kompf 2000-2003 see ACKNOWLEDGEMENTS */
1183 1247
1184/* get a message from a stream; return type of message */ 1248/* get a message from a stream; return type of message */
1185static int get_msg(int fd){ 1249static int get_msg(int fd) {
1186 int flags = 0; 1250 int flags = 0;
1187 int res, ret; 1251 int res, ret;
1188 ctl_area[0] = 0; 1252 ctl_area[0] = 0;
@@ -1190,30 +1254,29 @@ static int get_msg(int fd){
1190 ret = 0; 1254 ret = 0;
1191 res = getmsg(fd, &ctl, &dat, &flags); 1255 res = getmsg(fd, &ctl, &dat, &flags);
1192 1256
1193 if(res < 0){ 1257 if (res < 0) {
1194 if(errno == EINTR){ 1258 if (errno == EINTR) {
1195 return(GOT_INTR); 1259 return (GOT_INTR);
1196 } 1260 } else {
1197 else{
1198 printf("%s\n", "get_msg FAILED."); 1261 printf("%s\n", "get_msg FAILED.");
1199 return(GOT_ERR); 1262 return (GOT_ERR);
1200 } 1263 }
1201 } 1264 }
1202 if(ctl.len > 0){ 1265 if (ctl.len > 0) {
1203 ret |= GOT_CTRL; 1266 ret |= GOT_CTRL;
1204 } 1267 }
1205 if(dat.len > 0){ 1268 if (dat.len > 0) {
1206 ret |= GOT_DATA; 1269 ret |= GOT_DATA;
1207 } 1270 }
1208 1271
1209 return(ret); 1272 return (ret);
1210} 1273}
1211 1274
1212/* verify that dl_primitive in ctl_area = prim */ 1275/* verify that dl_primitive in ctl_area = prim */
1213static int check_ctrl(int prim){ 1276static int check_ctrl(int prim) {
1214 dl_error_ack_t *err_ack = (dl_error_ack_t *)ctl_area; 1277 dl_error_ack_t *err_ack = (dl_error_ack_t *)ctl_area;
1215 1278
1216 if(err_ack->dl_primitive != prim){ 1279 if (err_ack->dl_primitive != prim) {
1217 printf(_("Error: DLPI stream API failed to get MAC in check_ctrl: %s.\n"), strerror(errno)); 1280 printf(_("Error: DLPI stream API failed to get MAC in check_ctrl: %s.\n"), strerror(errno));
1218 exit(STATE_UNKNOWN); 1281 exit(STATE_UNKNOWN);
1219 } 1282 }
@@ -1222,35 +1285,35 @@ static int check_ctrl(int prim){
1222} 1285}
1223 1286
1224/* put a control message on a stream */ 1287/* put a control message on a stream */
1225static int put_ctrl(int fd, int len, int pri){ 1288static int put_ctrl(int fd, int len, int pri) {
1226 1289
1227 ctl.len = len; 1290 ctl.len = len;
1228 if(putmsg(fd, &ctl, 0, pri) < 0){ 1291 if (putmsg(fd, &ctl, 0, pri) < 0) {
1229 printf(_("Error: DLPI stream API failed to get MAC in put_ctrl/putmsg(): %s.\n"), strerror(errno)); 1292 printf(_("Error: DLPI stream API failed to get MAC in put_ctrl/putmsg(): %s.\n"), strerror(errno));
1230 exit(STATE_UNKNOWN); 1293 exit(STATE_UNKNOWN);
1231 } 1294 }
1232 1295
1233 return 0; 1296 return 0;
1234} 1297}
1235 1298
1236/* put a control + data message on a stream */ 1299/* put a control + data message on a stream */
1237static int put_both(int fd, int clen, int dlen, int pri){ 1300static int put_both(int fd, int clen, int dlen, int pri) {
1238 1301
1239 ctl.len = clen; 1302 ctl.len = clen;
1240 dat.len = dlen; 1303 dat.len = dlen;
1241 if(putmsg(fd, &ctl, &dat, pri) < 0){ 1304 if (putmsg(fd, &ctl, &dat, pri) < 0) {
1242 printf(_("Error: DLPI stream API failed to get MAC in put_both/putmsg().\n"), strerror(errno)); 1305 printf(_("Error: DLPI stream API failed to get MAC in put_both/putmsg().\n"), strerror(errno));
1243 exit(STATE_UNKNOWN); 1306 exit(STATE_UNKNOWN);
1244 } 1307 }
1245 1308
1246 return 0; 1309 return 0;
1247} 1310}
1248 1311
1249/* open file descriptor and attach */ 1312/* open file descriptor and attach */
1250static int dl_open(const char *dev, int unit, int *fd){ 1313static int dl_open(const char *dev, int unit, int *fd) {
1251 dl_attach_req_t *attach_req = (dl_attach_req_t *)ctl_area; 1314 dl_attach_req_t *attach_req = (dl_attach_req_t *)ctl_area;
1252 1315
1253 if((*fd = open(dev, O_RDWR)) == -1){ 1316 if ((*fd = open(dev, O_RDWR)) == -1) {
1254 printf(_("Error: DLPI stream API failed to get MAC in dl_attach_req/open(%s..): %s.\n"), dev, strerror(errno)); 1317 printf(_("Error: DLPI stream API failed to get MAC in dl_attach_req/open(%s..): %s.\n"), dev, strerror(errno));
1255 exit(STATE_UNKNOWN); 1318 exit(STATE_UNKNOWN);
1256 } 1319 }
@@ -1262,7 +1325,7 @@ static int dl_open(const char *dev, int unit, int *fd){
1262} 1325}
1263 1326
1264/* send DL_BIND_REQ */ 1327/* send DL_BIND_REQ */
1265static int dl_bind(int fd, int sap, u_char *addr){ 1328static int dl_bind(int fd, int sap, u_char *addr) {
1266 dl_bind_req_t *bind_req = (dl_bind_req_t *)ctl_area; 1329 dl_bind_req_t *bind_req = (dl_bind_req_t *)ctl_area;
1267 dl_bind_ack_t *bind_ack = (dl_bind_ack_t *)ctl_area; 1330 dl_bind_ack_t *bind_ack = (dl_bind_ack_t *)ctl_area;
1268 1331
@@ -1274,12 +1337,11 @@ static int dl_bind(int fd, int sap, u_char *addr){
1274 bind_req->dl_xidtest_flg = 0; 1337 bind_req->dl_xidtest_flg = 0;
1275 put_ctrl(fd, sizeof(dl_bind_req_t), 0); 1338 put_ctrl(fd, sizeof(dl_bind_req_t), 0);
1276 get_msg(fd); 1339 get_msg(fd);
1277 if (GOT_ERR == check_ctrl(DL_BIND_ACK)){ 1340 if (GOT_ERR == check_ctrl(DL_BIND_ACK)) {
1278 printf(_("Error: DLPI stream API failed to get MAC in dl_bind/check_ctrl(): %s.\n"), strerror(errno)); 1341 printf(_("Error: DLPI stream API failed to get MAC in dl_bind/check_ctrl(): %s.\n"), strerror(errno));
1279 exit(STATE_UNKNOWN); 1342 exit(STATE_UNKNOWN);
1280 } 1343 }
1281 bcopy((u_char *)bind_ack + bind_ack->dl_addr_offset, addr, 1344 bcopy((u_char *)bind_ack + bind_ack->dl_addr_offset, addr, bind_ack->dl_addr_length);
1282 bind_ack->dl_addr_length);
1283 1345
1284 return 0; 1346 return 0;
1285} 1347}
@@ -1296,13 +1358,13 @@ static int dl_bind(int fd, int sap, u_char *addr){
1296 * 1358 *
1297 ***********************************************************************/ 1359 ***********************************************************************/
1298 1360
1299long mac_addr_dlpi( const char *dev, int unit, u_char *addr){ 1361long mac_addr_dlpi(const char *dev, int unit, u_char *addr) {
1300 int fd; 1362 int fd;
1301 u_char mac_addr[25]; 1363 u_char mac_addr[25];
1302 1364
1303 if(GOT_ERR != dl_open(dev, unit, &fd)){ 1365 if (GOT_ERR != dl_open(dev, unit, &fd)) {
1304 if(GOT_ERR != dl_bind(fd, INSAP, mac_addr)){ 1366 if (GOT_ERR != dl_bind(fd, INSAP, mac_addr)) {
1305 bcopy( mac_addr, addr, 6); 1367 bcopy(mac_addr, addr, 6);
1306 return 0; 1368 return 0;
1307 } 1369 }
1308 } 1370 }
@@ -1314,99 +1376,93 @@ long mac_addr_dlpi( const char *dev, int unit, u_char *addr){
1314/* Kompf 2000-2003 */ 1376/* Kompf 2000-2003 */
1315#endif 1377#endif
1316 1378
1317
1318/* resolve host name or die (TODO: move this to netutils.c!) */ 1379/* resolve host name or die (TODO: move this to netutils.c!) */
1319void resolve_host(const char *in,struct in_addr *out){ 1380void resolve_host(const char *name, struct in_addr *out) {
1320 struct addrinfo hints, *ai; 1381 struct addrinfo hints = {
1382 .ai_family = PF_INET,
1383 };
1384 struct addrinfo *addr_info;
1321 1385
1322 memset(&hints,0,sizeof(hints)); 1386 if (getaddrinfo(name, NULL, &hints, &addr_info) != 0) {
1323 hints.ai_family=PF_INET; 1387 usage_va(_("Invalid hostname/address - %s"), optarg);
1324 if (getaddrinfo(in,NULL,&hints,&ai) != 0) 1388 }
1325 usage_va(_("Invalid hostname/address - %s"),optarg);
1326 1389
1327 memcpy(out,&((struct sockaddr_in *)ai->ai_addr)->sin_addr,sizeof(*out)); 1390 memcpy(out, &((struct sockaddr_in *)addr_info->ai_addr)->sin_addr, sizeof(*out));
1328 freeaddrinfo(ai); 1391 freeaddrinfo(addr_info);
1329} 1392}
1330 1393
1331
1332/* parse MAC address string, return 6 bytes (unterminated) or NULL */ 1394/* parse MAC address string, return 6 bytes (unterminated) or NULL */
1333unsigned char *mac_aton(const char *string){ 1395unsigned char *mac_aton(const char *string) {
1334 static unsigned char result[6]; 1396 static unsigned char result[MAC_ADDR_LEN];
1335 char tmp[3]; 1397 char tmp[3];
1336 unsigned i, j; 1398 unsigned byte_counter = 0;
1337 1399
1338 for(i=0, j=0; string[i] != '\0' && j < sizeof(result); i++){ 1400 for (int i = 0; string[i] != '\0' && byte_counter < sizeof(result); i++) {
1339 /* ignore ':' and any other non-hex character */ 1401 /* ignore ':' and any other non-hex character */
1340 if(!isxdigit(string[i]) || !isxdigit(string[i+1])) 1402 if (!isxdigit(string[i]) || !isxdigit(string[i + 1])) {
1341 continue; 1403 continue;
1342 tmp[0]=string[i]; 1404 }
1343 tmp[1]=string[i+1]; 1405 tmp[0] = string[i];
1344 tmp[2]='\0'; 1406 tmp[1] = string[i + 1];
1345 result[j]=strtol(tmp,(char **)NULL,16); 1407 tmp[2] = '\0';
1408 result[byte_counter] = strtol(tmp, (char **)NULL, 16);
1346 i++; 1409 i++;
1347 j++; 1410 byte_counter++;
1348 } 1411 }
1349 1412
1350 return (j==6) ? result : NULL; 1413 return (byte_counter == MAC_ADDR_LEN) ? result : NULL;
1351} 1414}
1352 1415
1353 1416void print_hardware_address(const unsigned char *address) {
1354void print_hardware_address(const unsigned char *address){
1355 int i;
1356 1417
1357 printf(_("Hardware address: ")); 1418 printf(_("Hardware address: "));
1358 for (i=0; i<5; i++) 1419 for (int addr_idx = 0; addr_idx < MAC_ADDR_LEN; addr_idx++) {
1359 printf("%2.2x:", address[i]); 1420 printf("%2.2x:", address[addr_idx]);
1360 printf("%2.2x", address[i]); 1421 }
1361 putchar('\n'); 1422 putchar('\n');
1362} 1423}
1363 1424
1364
1365/* print usage help */ 1425/* print usage help */
1366void print_help(void){ 1426void print_help(void) {
1367 1427
1368 print_revision(progname, NP_VERSION); 1428 print_revision(progname, NP_VERSION);
1369 1429
1370 printf("Copyright (c) 2001-2004 Ethan Galstad (nagios@nagios.org)\n"); 1430 printf("Copyright (c) 2001-2004 Ethan Galstad (nagios@nagios.org)\n");
1371 printf (COPYRIGHT, copyright, email); 1431 printf(COPYRIGHT, copyright, email);
1372 1432
1373 printf("%s\n", _("This plugin tests the availability of DHCP servers on a network.")); 1433 printf("%s\n", _("This plugin tests the availability of DHCP servers on a network."));
1374 1434
1375 printf ("\n\n"); 1435 printf("\n\n");
1376 1436
1377 print_usage(); 1437 print_usage();
1378 1438
1379 printf (UT_HELP_VRSN); 1439 printf(UT_HELP_VRSN);
1380 printf (UT_EXTRA_OPTS); 1440 printf(UT_EXTRA_OPTS);
1381 1441
1382 printf (UT_VERBOSE); 1442 printf(UT_OUTPUT_FORMAT);
1383 1443 printf(UT_VERBOSE);
1384 printf (" %s\n", "-s, --serverip=IPADDRESS"); 1444
1385 printf (" %s\n", _("IP address of DHCP server that we must hear from")); 1445 printf(" %s\n", "-s, --serverip=IPADDRESS");
1386 printf (" %s\n", "-r, --requestedip=IPADDRESS"); 1446 printf(" %s\n", _("IP address of DHCP server that we must hear from"));
1387 printf (" %s\n", _("IP address that should be offered by at least one DHCP server")); 1447 printf(" %s\n", "-r, --requestedip=IPADDRESS");
1388 printf (" %s\n", "-t, --timeout=INTEGER"); 1448 printf(" %s\n", _("IP address that should be offered by at least one DHCP server"));
1389 printf (" %s\n", _("Seconds to wait for DHCPOFFER before timeout occurs")); 1449 printf(" %s\n", "-t, --timeout=INTEGER");
1390 printf (" %s\n", "-i, --interface=STRING"); 1450 printf(" %s\n", _("Seconds to wait for DHCPOFFER before timeout occurs"));
1391 printf (" %s\n", _("Interface to to use for listening (i.e. eth0)")); 1451 printf(" %s\n", "-i, --interface=STRING");
1392 printf (" %s\n", "-m, --mac=STRING"); 1452 printf(" %s\n", _("Interface to to use for listening (i.e. eth0)"));
1393 printf (" %s\n", _("MAC address to use in the DHCP request")); 1453 printf(" %s\n", "-m, --mac=STRING");
1394 printf (" %s\n", "-u, --unicast"); 1454 printf(" %s\n", _("MAC address to use in the DHCP request"));
1395 printf (" %s\n", _("Unicast testing: mimic a DHCP relay, requires -s")); 1455 printf(" %s\n", "-u, --unicast");
1396 printf (" %s\n", "-x, --exclusive"); 1456 printf(" %s\n", _("Unicast testing: mimic a DHCP relay, requires -s"));
1397 printf (" %s\n", _("Only requested DHCP server may response (rogue DHCP server detection), requires -s")); 1457 printf(" %s\n", "-x, --exclusive");
1398 1458 printf(" %s\n", _("Only requested DHCP server may response (rogue DHCP server detection), requires -s"));
1399 printf (UT_SUPPORT); 1459
1400 return; 1460 printf(UT_SUPPORT);
1401} 1461}
1402 1462
1463void print_usage(void) {
1403 1464
1404void 1465 printf("%s\n", _("Usage:"));
1405print_usage(void){ 1466 printf(" %s [-v] [-u] [-x] [-s serverip] [-r requestedip] [-t timeout]\n", progname);
1406 1467 printf(" [-i interface] [-m mac]\n");
1407 printf ("%s\n", _("Usage:"));
1408 printf (" %s [-v] [-u] [-x] [-s serverip] [-r requestedip] [-t timeout]\n",progname);
1409 printf (" [-i interface] [-m mac]\n");
1410
1411 return;
1412} 1468}
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 f788d428..d46d2ccc 100644
--- a/plugins-root/check_icmp.c
+++ b/plugins-root/check_icmp.c
@@ -1,54 +1,56 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_icmp plugin 3 * Monitoring check_icmp plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2005-2008 Monitoring Plugins Development Team 6 * Copyright (c) 2005-2024 Monitoring Plugins Development Team
7* Original Author : Andreas Ericsson <ae@op5.se> 7 * Original Author : Andreas Ericsson <ae@op5.se>
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains the check_icmp plugin 11 * This file contains the check_icmp plugin
12* 12 *
13* Relevant RFC's: 792 (ICMP), 791 (IP) 13 * Relevant RFC's: 792 (ICMP), 791 (IP)
14* 14 *
15* This program was modeled somewhat after the check_icmp program, 15 * This program was modeled somewhat after the check_icmp program,
16* which was in turn a hack of fping (www.fping.org) but has been 16 * which was in turn a hack of fping (www.fping.org) but has been
17* completely rewritten since to generate higher precision rta values, 17 * completely rewritten since to generate higher precision rta values,
18* and support several different modes as well as setting ttl to control. 18 * and support several different modes as well as setting ttl to control.
19* redundant routes. The only remainders of fping is currently a few 19 * redundant routes. The only remainders of fping is currently a few
20* function names. 20 * function names.
21* 21 *
22* 22 *
23* This program is free software: you can redistribute it and/or modify 23 * This program is free software: you can redistribute it and/or modify
24* it under the terms of the GNU General Public License as published by 24 * it under the terms of the GNU General Public License as published by
25* the Free Software Foundation, either version 3 of the License, or 25 * the Free Software Foundation, either version 3 of the License, or
26* (at your option) any later version. 26 * (at your option) any later version.
27* 27 *
28* This program is distributed in the hope that it will be useful, 28 * This program is distributed in the hope that it will be useful,
29* but WITHOUT ANY WARRANTY; without even the implied warranty of 29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31* GNU General Public License for more details. 31 * GNU General Public License for more details.
32* 32 *
33* You should have received a copy of the GNU General Public License 33 * You should have received a copy of the GNU General Public License
34* along with this program. If not, see <http://www.gnu.org/licenses/>. 34 * along with this program. If not, see <http://www.gnu.org/licenses/>.
35* 35 *
36* 36 *
37*****************************************************************************/ 37 *****************************************************************************/
38 38
39/* progname may change */ 39/* progname may change */
40/* char *progname = "check_icmp"; */ 40/* char *progname = "check_icmp"; */
41char *progname; 41char *progname;
42const char *copyright = "2005-2008"; 42const char *copyright = "2005-2024";
43const char *email = "devel@monitoring-plugins.org"; 43const char *email = "devel@monitoring-plugins.org";
44 44
45/** Monitoring Plugins basic includes */ 45/** Monitoring Plugins basic includes */
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>
@@ -64,87 +66,50 @@ const char *email = "devel@monitoring-plugins.org";
64#include <netinet/ip_icmp.h> 66#include <netinet/ip_icmp.h>
65#include <netinet/icmp6.h> 67#include <netinet/icmp6.h>
66#include <arpa/inet.h> 68#include <arpa/inet.h>
67 69#include <math.h>
70#include <netdb.h>
71#include <sys/types.h>
72#include <unistd.h>
73#include <stdint.h>
74#include <sys/socket.h>
75#include <assert.h>
76#include <sys/select.h>
77
78#include "../lib/states.h"
79#include "./check_icmp.d/config.h"
80#include "./check_icmp.d/check_icmp_helpers.h"
68 81
69/** sometimes undefined system macros (quite a few, actually) **/ 82/** sometimes undefined system macros (quite a few, actually) **/
70#ifndef MAXTTL 83#ifndef MAXTTL
71# define MAXTTL 255 84# define MAXTTL 255
72#endif 85#endif
73#ifndef INADDR_NONE 86#ifndef INADDR_NONE
74# define INADDR_NONE (in_addr_t)(-1) 87# define INADDR_NONE (in_addr_t)(-1)
75#endif 88#endif
76 89
77#ifndef SOL_IP 90#ifndef SOL_IP
78#define SOL_IP 0 91# define SOL_IP 0
79#endif 92#endif
80 93
81/* we bundle these in one #ifndef, since they're all from BSD 94/* we bundle these in one #ifndef, since they're all from BSD
82 * Put individual #ifndef's around those that bother you */ 95 * Put individual #ifndef's around those that bother you */
83#ifndef ICMP_UNREACH_NET_UNKNOWN 96#ifndef ICMP_UNREACH_NET_UNKNOWN
84# define ICMP_UNREACH_NET_UNKNOWN 6 97# define ICMP_UNREACH_NET_UNKNOWN 6
85# define ICMP_UNREACH_HOST_UNKNOWN 7 98# define ICMP_UNREACH_HOST_UNKNOWN 7
86# define ICMP_UNREACH_ISOLATED 8 99# define ICMP_UNREACH_ISOLATED 8
87# define ICMP_UNREACH_NET_PROHIB 9 100# define ICMP_UNREACH_NET_PROHIB 9
88# define ICMP_UNREACH_HOST_PROHIB 10 101# define ICMP_UNREACH_HOST_PROHIB 10
89# define ICMP_UNREACH_TOSNET 11 102# define ICMP_UNREACH_TOSNET 11
90# define ICMP_UNREACH_TOSHOST 12 103# define ICMP_UNREACH_TOSHOST 12
91#endif 104#endif
92/* tru64 has the ones above, but not these */ 105/* tru64 has the ones above, but not these */
93#ifndef ICMP_UNREACH_FILTER_PROHIB 106#ifndef ICMP_UNREACH_FILTER_PROHIB
94# define ICMP_UNREACH_FILTER_PROHIB 13 107# define ICMP_UNREACH_FILTER_PROHIB 13
95# define ICMP_UNREACH_HOST_PRECEDENCE 14 108# define ICMP_UNREACH_HOST_PRECEDENCE 14
96# define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 109# define ICMP_UNREACH_PRECEDENCE_CUTOFF 15
97#endif 110#endif
98 111
99typedef unsigned short range_t; /* type for get_range() -- unimplemented */ 112#define FLAG_LOST_CAUSE 0x01 /* decidedly dead target. */
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. */
133
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 113
149typedef union ip_hdr { 114typedef union ip_hdr {
150 struct ip ip; 115 struct ip ip;
@@ -158,24 +123,6 @@ typedef union icmp_packet {
158 u_short *cksum_in; 123 u_short *cksum_in;
159} icmp_packet; 124} icmp_packet;
160 125
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 { 126enum enum_threshold_mode {
180 const_rta_mode, 127 const_rta_mode,
181 const_packet_loss_mode, 128 const_packet_loss_mode,
@@ -186,156 +133,587 @@ enum enum_threshold_mode {
186 133
187typedef enum enum_threshold_mode threshold_mode; 134typedef enum enum_threshold_mode threshold_mode;
188 135
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 **/ 136/** prototypes **/
209void print_help (void); 137void print_help();
210void print_usage (void); 138void print_usage(void);
211static u_int get_timevar(const char *); 139
212static u_int get_timevaldiff(struct timeval *, struct timeval *); 140/* Time related */
213static in_addr_t get_ip_address(const char *); 141typedef struct {
214static int wait_for_reply(int, u_int); 142 int error_code;
215static int recvfrom_wto(int, void *, unsigned int, struct sockaddr *, u_int *, struct timeval*); 143 time_t time_range;
216static int send_icmp_ping(int, struct rta_host *); 144} get_timevar_wrapper;
217static int get_threshold(char *str, threshold *th); 145static get_timevar_wrapper get_timevar(const char *str);
218static bool get_threshold2(char *str, size_t length, threshold *, threshold *, threshold_mode mode); 146static 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); 147static time_t get_timevaldiff_to_now(struct timeval earlier);
220static void run_checks(void); 148
221static void set_source_ip(char *); 149static in_addr_t get_ip_address(const char *ifname);
222static int add_target(char *); 150static void set_source_ip(char *arg, int icmp_sock, sa_family_t addr_family);
223static int add_target_ip(char *, struct sockaddr_storage *); 151
224static int handle_random_icmp(unsigned char *, struct sockaddr_storage *); 152/* Receiving data */
225static void parse_address(struct sockaddr_storage *, char *, int); 153static int wait_for_reply(check_icmp_socket_set sockset, time_t time_interval,
226static unsigned short icmp_checksum(uint16_t *, size_t); 154 unsigned short icmp_pkt_size, time_t *target_interval, uint16_t sender_id,
227static void finish(int); 155 ping_target **table, unsigned short packets,
228static void crash(const char *, ...); 156 unsigned short number_of_targets, check_icmp_state *program_state);
229 157
230/** external **/ 158typedef struct {
231extern int optind; 159 sa_family_t recv_proto;
232extern char *optarg; 160 ssize_t received;
233extern char **environ; 161} recvfrom_wto_wrapper;
162static recvfrom_wto_wrapper recvfrom_wto(check_icmp_socket_set sockset, void *buf, unsigned int len,
163 struct sockaddr *saddr, time_t *timeout,
164 struct timeval *received_timestamp);
165static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr,
166 time_t *target_interval, uint16_t sender_id, ping_target **table,
167 unsigned short packets, unsigned short number_of_targets,
168 check_icmp_state *program_state);
169
170/* Sending data */
171static int send_icmp_ping(check_icmp_socket_set sockset, ping_target *host,
172 unsigned short icmp_pkt_size, uint16_t sender_id,
173 check_icmp_state *program_state);
174
175/* Threshold related */
176typedef struct {
177 int errorcode;
178 check_icmp_threshold threshold;
179} get_threshold_wrapper;
180static get_threshold_wrapper get_threshold(char *str, check_icmp_threshold threshold);
181
182typedef struct {
183 int errorcode;
184 check_icmp_threshold warn;
185 check_icmp_threshold crit;
186} get_threshold2_wrapper;
187static get_threshold2_wrapper get_threshold2(char *str, size_t length, check_icmp_threshold warn,
188 check_icmp_threshold crit, threshold_mode mode);
189
190typedef struct {
191 int errorcode;
192 check_icmp_threshold result;
193} parse_threshold2_helper_wrapper;
194static parse_threshold2_helper_wrapper parse_threshold2_helper(char *threshold_string,
195 size_t length,
196 check_icmp_threshold thr,
197 threshold_mode mode);
198
199/* main test function */
200static void run_checks(unsigned short icmp_pkt_size, time_t *target_interval, uint16_t sender_id,
201 check_icmp_execution_mode mode, time_t max_completion_time,
202 struct timeval prog_start, ping_target **table, unsigned short packets,
203 check_icmp_socket_set sockset, unsigned short number_of_targets,
204 check_icmp_state *program_state);
205mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes,
206 check_icmp_threshold warn, check_icmp_threshold crit);
207
208typedef struct {
209 int targets_ok;
210 int targets_warn;
211 mp_subcheck sc_host;
212} evaluate_host_wrapper;
213evaluate_host_wrapper evaluate_host(check_icmp_target_container host,
214 check_icmp_mode_switches modes, check_icmp_threshold warn,
215 check_icmp_threshold crit);
216
217/* Target acquisition */
218typedef struct {
219 int error_code;
220 check_icmp_target_container host;
221 bool has_v4;
222 bool has_v6;
223} add_host_wrapper;
224static add_host_wrapper add_host(char *arg, check_icmp_execution_mode mode,
225 sa_family_t enforced_proto);
226
227typedef struct {
228 int error_code;
229 ping_target *targets;
230 unsigned int number_of_targets;
231 bool has_v4;
232 bool has_v6;
233} add_target_wrapper;
234static add_target_wrapper add_target(char *arg, check_icmp_execution_mode mode,
235 sa_family_t enforced_proto);
236
237typedef struct {
238 int error_code;
239 ping_target *target;
240} add_target_ip_wrapper;
241static add_target_ip_wrapper add_target_ip(struct sockaddr_storage address);
242
243static void parse_address(const struct sockaddr_storage *addr, char *dst, socklen_t size);
244
245static unsigned short icmp_checksum(uint16_t *packet, size_t packet_size);
246
247/* End of run function */
248static void finish(int sign, check_icmp_mode_switches modes, int min_hosts_alive,
249 check_icmp_threshold warn, check_icmp_threshold crit,
250 unsigned short number_of_targets, check_icmp_state *program_state,
251 check_icmp_target_container host_list[], unsigned short number_of_hosts,
252 mp_check overall[static 1]);
253
254/* Error exit */
255static void crash(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
234 256
235/** global variables **/ 257/** global variables **/
236static struct rta_host **table, *cursor, *list; 258static int debug = 0;
237 259
238static threshold crit = { 260extern unsigned int timeout;
239 .pl = 80, 261
240 .rta = 500000, 262/** the working code **/
241 .jitter = 0.0, 263static inline unsigned short targets_alive(unsigned short targets, unsigned short targets_down) {
242 .mos = 0.0, 264 return targets - targets_down;
243 .score = 0.0 265}
244}; 266static inline unsigned int icmp_pkts_en_route(unsigned int icmp_sent, unsigned int icmp_recv,
245static threshold warn = { 267 unsigned int icmp_lost) {
246 .pl = 40, 268 return icmp_sent - (icmp_recv + icmp_lost);
247 .rta = 200000, 269}
248 .jitter = 0.0, 270
249 .mos = 0.0, 271// Create configuration from cli parameters
250 .score = 0.0 272typedef struct {
251}; 273 int errorcode;
274 check_icmp_config config;
275} check_icmp_config_wrapper;
276check_icmp_config_wrapper process_arguments(int argc, char **argv) {
277 /* get calling name the old-fashioned way for portability instead
278 * of relying on the glibc-ism __progname */
279 char *ptr = strrchr(argv[0], '/');
280 if (ptr) {
281 progname = &ptr[1];
282 } else {
283 progname = argv[0];
284 }
285
286 check_icmp_config_wrapper result = {
287 .errorcode = OK,
288 .config = check_icmp_config_init(),
289 };
290
291 /* use the pid to mark packets as ours */
292 /* Some systems have 32-bit pid_t so mask off only 16 bits */
293 result.config.sender_id = getpid() & 0xffff;
294
295 if (!strcmp(progname, "check_icmp") || !strcmp(progname, "check_ping")) {
296 result.config.mode = MODE_ICMP;
297 } else if (!strcmp(progname, "check_host")) {
298 result.config.mode = MODE_HOSTCHECK;
299 result.config.number_of_packets = 5;
300 result.config.crit.rta = result.config.warn.rta = 1000000;
301 result.config.crit.pl = result.config.warn.pl = 100;
302 } else if (!strcmp(progname, "check_rta_multi")) {
303 result.config.mode = MODE_ALL;
304 result.config.target_interval = 0;
305 result.config.number_of_packets = 5;
306 }
307 /* support "--help" and "--version" */
308 if (argc == 2) {
309 if (!strcmp(argv[1], "--help")) {
310 strcpy(argv[1], "-h");
311 }
312 if (!strcmp(argv[1], "--version")) {
313 strcpy(argv[1], "-V");
314 }
315 }
252 316
253static int mode, protocols, sockets, debug = 0, timeout = 10; 317 sa_family_t enforced_ai_family = AF_UNSPEC;
254static unsigned short icmp_data_size = DEFAULT_PING_DATA_SIZE; 318
255static unsigned short icmp_pkt_size = DEFAULT_PING_DATA_SIZE + ICMP_MINLEN; 319 enum {
256 320 output_format_index = CHAR_MAX + 1,
257static unsigned int icmp_sent = 0, icmp_recv = 0, icmp_lost = 0, ttl = 0; 321 };
258#define icmp_pkts_en_route (icmp_sent - (icmp_recv + icmp_lost)) 322
259static unsigned short targets_down = 0, targets = 0, packets = 0; 323 struct option longopts[] = {
260#define targets_alive (targets - targets_down) 324 {"version", no_argument, 0, 'V'},
261static unsigned int retry_interval, pkt_interval, target_interval; 325 {"help", no_argument, 0, 'h'},
262static int icmp_sock, tcp_sock, udp_sock, status = STATE_OK; 326 {"verbose", no_argument, 0, 'v'},
263static pid_t pid; 327 {"Host", required_argument, 0, 'H'},
264static struct timezone tz; 328 {"ipv4-only", no_argument, 0, '4'},
265static struct timeval prog_start; 329 {"ipv6-only", no_argument, 0, '6'},
266static unsigned long long max_completion_time = 0; 330 {"warning", required_argument, 0, 'w'},
267static unsigned int warn_down = 1, crit_down = 1; /* host down threshold values */ 331 {"critical", required_argument, 0, 'c'},
268static int min_hosts_alive = -1; 332 {"rta-mode-thresholds", required_argument, 0, 'R'},
269float pkt_backoff_factor = 1.5; 333 {"packet-loss-mode-thresholds", required_argument, 0, 'P'},
270float target_backoff_factor = 1.5; 334 {"jitter-mode-thresholds", required_argument, 0, 'J'},
271bool rta_mode=false; 335 {"mos-mode-thresholds", required_argument, 0, 'M'},
272bool pl_mode=false; 336 {"score-mode-thresholds", required_argument, 0, 'S'},
273bool jitter_mode=false; 337 {"out-of-order-packets", no_argument, 0, 'O'},
274bool score_mode=false; 338 {"number-of-packets", required_argument, 0, 'n'},
275bool mos_mode=false; 339 {"number-of-packets", required_argument, 0, 'p'},
276bool order_mode=false; 340 {"packet-interval", required_argument, 0, 'i'},
341 {"target-interval", required_argument, 0, 'I'},
342 {"minimal-host-alive", required_argument, 0, 'm'},
343 {"outgoing-ttl", required_argument, 0, 'l'},
344 {"size", required_argument, 0, 'b'},
345 {"output-format", required_argument, 0, output_format_index},
346 {},
347 };
348
349 // Parse protocol arguments first
350 // and count hosts here
351 char *opts_str = "vhVw:c:n:p:t:H:s:i:b:I:l:m:P:R:J:S:M:O64";
352 for (int i = 1; i < argc; i++) {
353 long int arg;
354 while ((arg = getopt_long(argc, argv, opts_str, longopts, NULL)) != EOF) {
355 switch (arg) {
356
357 case '4':
358 if (enforced_ai_family != AF_UNSPEC) {
359 crash("Multiple protocol versions not supported");
360 }
361 enforced_ai_family = AF_INET;
362 break;
363 case '6':
364 if (enforced_ai_family != AF_UNSPEC) {
365 crash("Multiple protocol versions not supported");
366 }
367 enforced_ai_family = AF_INET6;
368 break;
369 case 'H': {
370 result.config.number_of_hosts++;
371 break;
372 }
373 case 'h': /* help */
374 // Trigger help here to avoid adding hosts before that (and doing DNS queries)
375 print_help();
376 exit(STATE_UNKNOWN);
377 break;
378 case 'v':
379 debug++;
380 break;
381 }
382 }
383 }
384
385 char **tmp = &argv[optind];
386 while (*tmp) {
387 result.config.number_of_hosts++;
388 tmp++;
389 }
390
391 // Sanity check: if hostmode is selected,only a single host is allowed
392 if (result.config.mode == MODE_HOSTCHECK && result.config.number_of_hosts > 1) {
393 usage("check_host only allows a single host");
394 }
395
396 // Allocate hosts
397 result.config.hosts =
398 calloc(result.config.number_of_hosts, sizeof(check_icmp_target_container));
399 if (result.config.hosts == NULL) {
400 crash("failed to allocate memory");
401 }
402
403 /* Reset argument scanning */
404 optind = 1;
405
406 int host_counter = 0;
407 /* parse the arguments */
408 for (int i = 1; i < argc; i++) {
409 long int arg;
410 while ((arg = getopt_long(argc, argv, opts_str, longopts, NULL)) != EOF) {
411 switch (arg) {
412 case 'b': {
413 long size = strtol(optarg, NULL, 0);
414 if ((unsigned long)size >= (sizeof(struct icmp) + sizeof(struct icmp_ping_data)) &&
415 size < MAX_PING_DATA) {
416 result.config.icmp_data_size = (unsigned short)size;
417 } else {
418 usage_va("ICMP data length must be between: %lu and %lu",
419 sizeof(struct icmp) + sizeof(struct icmp_ping_data),
420 MAX_PING_DATA - 1);
421 }
422 } break;
423 case 'i': {
424 // packet_interval was unused and is now removed
425 } break;
426 case 'I': {
427 get_timevar_wrapper parsed_time = get_timevar(optarg);
428
429 if (parsed_time.error_code == OK) {
430 result.config.target_interval = parsed_time.time_range;
431 } else {
432 crash("failed to parse target interval");
433 }
434 } break;
435 case 'w': {
436 get_threshold_wrapper warn = get_threshold(optarg, result.config.warn);
437 if (warn.errorcode == OK) {
438 result.config.warn = warn.threshold;
439 } else {
440 crash("failed to parse warning threshold");
441 }
442 } break;
443 case 'c': {
444 get_threshold_wrapper crit = get_threshold(optarg, result.config.crit);
445 if (crit.errorcode == OK) {
446 result.config.crit = crit.threshold;
447 } else {
448 crash("failed to parse critical threshold");
449 }
450 } break;
451 case 'n':
452 case 'p':
453 result.config.number_of_packets = (unsigned short)strtoul(optarg, NULL, 0);
454 if (result.config.number_of_packets > 20) {
455 errno = 0;
456 crash("packets is > 20 (%d)", result.config.number_of_packets);
457 }
458 break;
459 case 't':
460 // WARNING Deprecated since execution time is determined by the other factors
461 break;
462 case 'H': {
463 add_host_wrapper host_add_result =
464 add_host(optarg, result.config.mode, enforced_ai_family);
465 if (host_add_result.error_code == OK) {
466 result.config.hosts[host_counter] = host_add_result.host;
467 host_counter++;
468
469 if (result.config.targets != NULL) {
470 result.config.number_of_targets += ping_target_list_append(
471 result.config.targets, host_add_result.host.target_list);
472 } else {
473 result.config.targets = host_add_result.host.target_list;
474 result.config.number_of_targets += host_add_result.host.number_of_targets;
475 }
476
477 if (host_add_result.has_v4) {
478 result.config.need_v4 = true;
479 }
480 if (host_add_result.has_v6) {
481 result.config.need_v6 = true;
482 }
483 } else {
484 crash("Failed to add host, unable to parse it correctly");
485 }
486 } break;
487 case 'l':
488 result.config.ttl = strtoul(optarg, NULL, 0);
489 break;
490 case 'm':
491 result.config.min_hosts_alive = (int)strtoul(optarg, NULL, 0);
492 break;
493 case 's': /* specify source IP address */
494 result.config.source_ip = optarg;
495 break;
496 case 'V': /* version */
497 print_revision(progname, NP_VERSION);
498 exit(STATE_UNKNOWN);
499 case 'R': /* RTA mode */ {
500 get_threshold2_wrapper rta_th = get_threshold2(
501 optarg, strlen(optarg), result.config.warn, result.config.crit, const_rta_mode);
502
503 if (rta_th.errorcode != OK) {
504 crash("Failed to parse RTA threshold");
505 }
506
507 result.config.warn = rta_th.warn;
508 result.config.crit = rta_th.crit;
509 result.config.modes.rta_mode = true;
510 } break;
511 case 'P': /* packet loss mode */ {
512 get_threshold2_wrapper pl_th =
513 get_threshold2(optarg, strlen(optarg), result.config.warn, result.config.crit,
514 const_packet_loss_mode);
515 if (pl_th.errorcode != OK) {
516 crash("Failed to parse packet loss threshold");
517 }
518
519 result.config.warn = pl_th.warn;
520 result.config.crit = pl_th.crit;
521 result.config.modes.pl_mode = true;
522 } break;
523 case 'J': /* jitter mode */ {
524 get_threshold2_wrapper jitter_th =
525 get_threshold2(optarg, strlen(optarg), result.config.warn, result.config.crit,
526 const_jitter_mode);
527 if (jitter_th.errorcode != OK) {
528 crash("Failed to parse jitter threshold");
529 }
530
531 result.config.warn = jitter_th.warn;
532 result.config.crit = jitter_th.crit;
533 result.config.modes.jitter_mode = true;
534 } break;
535 case 'M': /* MOS mode */ {
536 get_threshold2_wrapper mos_th = get_threshold2(
537 optarg, strlen(optarg), result.config.warn, result.config.crit, const_mos_mode);
538 if (mos_th.errorcode != OK) {
539 crash("Failed to parse MOS threshold");
540 }
541
542 result.config.warn = mos_th.warn;
543 result.config.crit = mos_th.crit;
544 result.config.modes.mos_mode = true;
545 } break;
546 case 'S': /* score mode */ {
547 get_threshold2_wrapper score_th =
548 get_threshold2(optarg, strlen(optarg), result.config.warn, result.config.crit,
549 const_score_mode);
550 if (score_th.errorcode != OK) {
551 crash("Failed to parse score threshold");
552 }
553
554 result.config.warn = score_th.warn;
555 result.config.crit = score_th.crit;
556 result.config.modes.score_mode = true;
557 } break;
558 case 'O': /* out of order mode */
559 result.config.modes.order_mode = true;
560 break;
561 case output_format_index: {
562 parsed_output_format parser = mp_parse_output_format(optarg);
563 if (!parser.parsing_success) {
564 // TODO List all available formats here, maybe add anothoer usage function
565 printf("Invalid output format: %s\n", optarg);
566 exit(STATE_UNKNOWN);
567 }
568
569 result.config.output_format_is_set = true;
570 result.config.output_format = parser.output_format;
571 break;
572 }
573 }
574 }
575 }
576
577 argv = &argv[optind];
578 while (*argv) {
579 add_target(*argv, result.config.mode, enforced_ai_family);
580 argv++;
581 }
582
583 if (!result.config.number_of_targets) {
584 errno = 0;
585 crash("No hosts to check");
586 }
587
588 /* stupid users should be able to give whatever thresholds they want
589 * (nothing will break if they do), but some anal plugin maintainer
590 * will probably add some printf() thing here later, so it might be
591 * best to at least show them where to do it. ;) */
592 if (result.config.warn.pl > result.config.crit.pl) {
593 result.config.warn.pl = result.config.crit.pl;
594 }
595 if (result.config.warn.rta > result.config.crit.rta) {
596 result.config.warn.rta = result.config.crit.rta;
597 }
598 if (result.config.warn.jitter > result.config.crit.jitter) {
599 result.config.crit.jitter = result.config.warn.jitter;
600 }
601 if (result.config.warn.mos < result.config.crit.mos) {
602 result.config.warn.mos = result.config.crit.mos;
603 }
604 if (result.config.warn.score < result.config.crit.score) {
605 result.config.warn.score = result.config.crit.score;
606 }
607
608 return result;
609}
277 610
278/** code start **/ 611/** code start **/
279static void 612static void crash(const char *fmt, ...) {
280crash(const char *fmt, ...)
281{
282 va_list ap;
283 613
284 printf("%s: ", progname); 614 printf("%s: ", progname);
285 615
616 va_list ap;
286 va_start(ap, fmt); 617 va_start(ap, fmt);
287 vprintf(fmt, ap); 618 vprintf(fmt, ap);
288 va_end(ap); 619 va_end(ap);
289 620
290 if(errno) printf(": %s", strerror(errno)); 621 if (errno) {
622 printf(": %s", strerror(errno));
623 }
291 puts(""); 624 puts("");
292 625
293 exit(3); 626 exit(3);
294} 627}
295 628
296 629static const char *get_icmp_error_msg(unsigned char icmp_type, unsigned char icmp_code) {
297static const char *
298get_icmp_error_msg(unsigned char icmp_type, unsigned char icmp_code)
299{
300 const char *msg = "unreachable"; 630 const char *msg = "unreachable";
301 631
302 if(debug > 1) printf("get_icmp_error_msg(%u, %u)\n", icmp_type, icmp_code); 632 if (debug > 1) {
303 switch(icmp_type) { 633 printf("get_icmp_error_msg(%u, %u)\n", icmp_type, icmp_code);
634 }
635 switch (icmp_type) {
304 case ICMP_UNREACH: 636 case ICMP_UNREACH:
305 switch(icmp_code) { 637 switch (icmp_code) {
306 case ICMP_UNREACH_NET: msg = "Net unreachable"; break; 638 case ICMP_UNREACH_NET:
307 case ICMP_UNREACH_HOST: msg = "Host unreachable"; break; 639 msg = "Net unreachable";
308 case ICMP_UNREACH_PROTOCOL: msg = "Protocol unreachable (firewall?)"; break; 640 break;
309 case ICMP_UNREACH_PORT: msg = "Port unreachable (firewall?)"; break; 641 case ICMP_UNREACH_HOST:
310 case ICMP_UNREACH_NEEDFRAG: msg = "Fragmentation needed"; break; 642 msg = "Host unreachable";
311 case ICMP_UNREACH_SRCFAIL: msg = "Source route failed"; break; 643 break;
312 case ICMP_UNREACH_ISOLATED: msg = "Source host isolated"; break; 644 case ICMP_UNREACH_PROTOCOL:
313 case ICMP_UNREACH_NET_UNKNOWN: msg = "Unknown network"; break; 645 msg = "Protocol unreachable (firewall?)";
314 case ICMP_UNREACH_HOST_UNKNOWN: msg = "Unknown host"; break; 646 break;
315 case ICMP_UNREACH_NET_PROHIB: msg = "Network denied (firewall?)"; break; 647 case ICMP_UNREACH_PORT:
316 case ICMP_UNREACH_HOST_PROHIB: msg = "Host denied (firewall?)"; break; 648 msg = "Port unreachable (firewall?)";
317 case ICMP_UNREACH_TOSNET: msg = "Bad TOS for network (firewall?)"; break; 649 break;
318 case ICMP_UNREACH_TOSHOST: msg = "Bad TOS for host (firewall?)"; break; 650 case ICMP_UNREACH_NEEDFRAG:
319 case ICMP_UNREACH_FILTER_PROHIB: msg = "Prohibited by filter (firewall)"; break; 651 msg = "Fragmentation needed";
320 case ICMP_UNREACH_HOST_PRECEDENCE: msg = "Host precedence violation"; break; 652 break;
321 case ICMP_UNREACH_PRECEDENCE_CUTOFF: msg = "Precedence cutoff"; break; 653 case ICMP_UNREACH_SRCFAIL:
322 default: msg = "Invalid code"; break; 654 msg = "Source route failed";
655 break;
656 case ICMP_UNREACH_ISOLATED:
657 msg = "Source host isolated";
658 break;
659 case ICMP_UNREACH_NET_UNKNOWN:
660 msg = "Unknown network";
661 break;
662 case ICMP_UNREACH_HOST_UNKNOWN:
663 msg = "Unknown host";
664 break;
665 case ICMP_UNREACH_NET_PROHIB:
666 msg = "Network denied (firewall?)";
667 break;
668 case ICMP_UNREACH_HOST_PROHIB:
669 msg = "Host denied (firewall?)";
670 break;
671 case ICMP_UNREACH_TOSNET:
672 msg = "Bad TOS for network (firewall?)";
673 break;
674 case ICMP_UNREACH_TOSHOST:
675 msg = "Bad TOS for host (firewall?)";
676 break;
677 case ICMP_UNREACH_FILTER_PROHIB:
678 msg = "Prohibited by filter (firewall)";
679 break;
680 case ICMP_UNREACH_HOST_PRECEDENCE:
681 msg = "Host precedence violation";
682 break;
683 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
684 msg = "Precedence cutoff";
685 break;
686 default:
687 msg = "Invalid code";
688 break;
323 } 689 }
324 break; 690 break;
325 691
326 case ICMP_TIMXCEED: 692 case ICMP_TIMXCEED:
327 /* really 'out of reach', or non-existent host behind a router serving 693 /* really 'out of reach', or non-existent host behind a router serving
328 * two different subnets */ 694 * two different subnets */
329 switch(icmp_code) { 695 switch (icmp_code) {
330 case ICMP_TIMXCEED_INTRANS: msg = "Time to live exceeded in transit"; break; 696 case ICMP_TIMXCEED_INTRANS:
331 case ICMP_TIMXCEED_REASS: msg = "Fragment reassembly time exceeded"; break; 697 msg = "Time to live exceeded in transit";
332 default: msg = "Invalid code"; break; 698 break;
699 case ICMP_TIMXCEED_REASS:
700 msg = "Fragment reassembly time exceeded";
701 break;
702 default:
703 msg = "Invalid code";
704 break;
333 } 705 }
334 break; 706 break;
335 707
336 case ICMP_SOURCEQUENCH: msg = "Transmitting too fast"; break; 708 case ICMP_SOURCEQUENCH:
337 case ICMP_REDIRECT: msg = "Redirect (change route)"; break; 709 msg = "Transmitting too fast";
338 case ICMP_PARAMPROB: msg = "Bad IP header (required option absent)"; break; 710 break;
711 case ICMP_REDIRECT:
712 msg = "Redirect (change route)";
713 break;
714 case ICMP_PARAMPROB:
715 msg = "Bad IP header (required option absent)";
716 break;
339 717
340 /* the following aren't error messages, so ignore */ 718 /* the following aren't error messages, so ignore */
341 case ICMP_TSTAMP: 719 case ICMP_TSTAMP:
@@ -344,25 +722,29 @@ get_icmp_error_msg(unsigned char icmp_type, unsigned char icmp_code)
344 case ICMP_IREQREPLY: 722 case ICMP_IREQREPLY:
345 case ICMP_MASKREQ: 723 case ICMP_MASKREQ:
346 case ICMP_MASKREPLY: 724 case ICMP_MASKREPLY:
347 default: msg = ""; break; 725 default:
726 msg = "";
727 break;
348 } 728 }
349 729
350 return msg; 730 return msg;
351} 731}
352 732
353static int 733static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr,
354handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr) 734 time_t *target_interval, const uint16_t sender_id,
355{ 735 ping_target **table, unsigned short packets,
356 struct icmp p, sent_icmp; 736 const unsigned short number_of_targets,
357 struct rta_host *host = NULL; 737 check_icmp_state *program_state) {
358 738 struct icmp icmp_packet;
359 memcpy(&p, packet, sizeof(p)); 739 memcpy(&icmp_packet, packet, sizeof(icmp_packet));
360 if(p.icmp_type == ICMP_ECHO && ntohs(p.icmp_id) == pid) { 740 if (icmp_packet.icmp_type == ICMP_ECHO && ntohs(icmp_packet.icmp_id) == sender_id) {
361 /* echo request from us to us (pinging localhost) */ 741 /* echo request from us to us (pinging localhost) */
362 return 0; 742 return 0;
363 } 743 }
364 744
365 if(debug) printf("handle_random_icmp(%p, %p)\n", (void *)&p, (void *)addr); 745 if (debug) {
746 printf("handle_random_icmp(%p, %p)\n", (void *)&icmp_packet, (void *)addr);
747 }
366 748
367 /* only handle a few types, since others can't possibly be replies to 749 /* only handle a few types, since others can't possibly be replies to
368 * us in a sane network (if it is anyway, it will be counted as lost 750 * us in a sane network (if it is anyway, it will be counted as lost
@@ -374,327 +756,139 @@ handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr)
374 * TIMXCEED actually sends a proper icmp response we will have passed 756 * TIMXCEED actually sends a proper icmp response we will have passed
375 * too many hops to have a hope of reaching it later, in which case it 757 * too many hops to have a hope of reaching it later, in which case it
376 * indicates overconfidence in the network, poor routing or both. */ 758 * indicates overconfidence in the network, poor routing or both. */
377 if(p.icmp_type != ICMP_UNREACH && p.icmp_type != ICMP_TIMXCEED && 759 if (icmp_packet.icmp_type != ICMP_UNREACH && icmp_packet.icmp_type != ICMP_TIMXCEED &&
378 p.icmp_type != ICMP_SOURCEQUENCH && p.icmp_type != ICMP_PARAMPROB) 760 icmp_packet.icmp_type != ICMP_SOURCEQUENCH && icmp_packet.icmp_type != ICMP_PARAMPROB) {
379 {
380 return 0; 761 return 0;
381 } 762 }
382 763
383 /* might be for us. At least it holds the original package (according 764 /* might be for us. At least it holds the original package (according
384 * to RFC 792). If it isn't, just ignore it */ 765 * to RFC 792). If it isn't, just ignore it */
766 struct icmp sent_icmp;
385 memcpy(&sent_icmp, packet + 28, sizeof(sent_icmp)); 767 memcpy(&sent_icmp, packet + 28, sizeof(sent_icmp));
386 if(sent_icmp.icmp_type != ICMP_ECHO || ntohs(sent_icmp.icmp_id) != pid || 768 if (sent_icmp.icmp_type != ICMP_ECHO || ntohs(sent_icmp.icmp_id) != sender_id ||
387 ntohs(sent_icmp.icmp_seq) >= targets*packets) 769 ntohs(sent_icmp.icmp_seq) >= number_of_targets * packets) {
388 { 770 if (debug) {
389 if(debug) printf("Packet is no response to a packet we sent\n"); 771 printf("Packet is no response to a packet we sent\n");
772 }
390 return 0; 773 return 0;
391 } 774 }
392 775
393 /* it is indeed a response for us */ 776 /* it is indeed a response for us */
394 host = table[ntohs(sent_icmp.icmp_seq)/packets]; 777 ping_target *host = table[ntohs(sent_icmp.icmp_seq) / packets];
395 if(debug) { 778 if (debug) {
396 char address[INET6_ADDRSTRLEN]; 779 char address[INET6_ADDRSTRLEN];
397 parse_address(addr, address, sizeof(address)); 780 parse_address(addr, address, sizeof(address));
398 printf("Received \"%s\" from %s for ICMP ECHO sent to %s.\n", 781 printf("Received \"%s\" from %s for ICMP ECHO sent.\n",
399 get_icmp_error_msg(p.icmp_type, p.icmp_code), 782 get_icmp_error_msg(icmp_packet.icmp_type, icmp_packet.icmp_code), address);
400 address, host->name);
401 } 783 }
402 784
403 icmp_lost++; 785 program_state->icmp_lost++;
404 host->icmp_lost++; 786 host->icmp_lost++;
405 /* don't spend time on lost hosts any more */ 787 /* don't spend time on lost hosts any more */
406 if(host->flags & FLAG_LOST_CAUSE) return 0; 788 if (host->flags & FLAG_LOST_CAUSE) {
789 return 0;
790 }
407 791
408 /* source quench means we're sending too fast, so increase the 792 /* source quench means we're sending too fast, so increase the
409 * interval and mark this packet lost */ 793 * interval and mark this packet lost */
410 if(p.icmp_type == ICMP_SOURCEQUENCH) { 794 if (icmp_packet.icmp_type == ICMP_SOURCEQUENCH) {
411 pkt_interval *= pkt_backoff_factor; 795 *target_interval = (unsigned int)((double)*target_interval * TARGET_BACKOFF_FACTOR);
412 target_interval *= target_backoff_factor; 796 } else {
413 } 797 program_state->targets_down++;
414 else {
415 targets_down++;
416 host->flags |= FLAG_LOST_CAUSE; 798 host->flags |= FLAG_LOST_CAUSE;
417 } 799 }
418 host->icmp_type = p.icmp_type; 800 host->icmp_type = icmp_packet.icmp_type;
419 host->icmp_code = p.icmp_code; 801 host->icmp_code = icmp_packet.icmp_code;
420 host->error_addr = *addr; 802 host->error_addr = *addr;
421 803
422 return 0; 804 return 0;
423} 805}
424 806
425void parse_address(struct sockaddr_storage *addr, char *address, int size) 807void parse_address(const struct sockaddr_storage *addr, char *dst, socklen_t size) {
426{ 808 switch (addr->ss_family) {
427 switch (address_family) {
428 case AF_INET: 809 case AF_INET:
429 inet_ntop(address_family, &((struct sockaddr_in *)addr)->sin_addr, address, size); 810 inet_ntop(AF_INET, &((struct sockaddr_in *)addr)->sin_addr, dst, size);
430 break; 811 break;
431 case AF_INET6: 812 case AF_INET6:
432 inet_ntop(address_family, &((struct sockaddr_in6 *)addr)->sin6_addr, address, size); 813 inet_ntop(AF_INET6, &((struct sockaddr_in6 *)addr)->sin6_addr, dst, size);
433 break; 814 break;
815 default:
816 assert(false);
434 } 817 }
435} 818}
436 819
437int 820int main(int argc, char **argv) {
438main(int argc, char **argv) 821 setlocale(LC_ALL, "");
439{ 822 bindtextdomain(PACKAGE, LOCALEDIR);
440 int i; 823 textdomain(PACKAGE);
441 char *ptr;
442 long int arg;
443 int icmp_sockerrno, udp_sockerrno, tcp_sockerrno;
444 int result;
445 struct rta_host *host;
446#ifdef HAVE_SIGACTION
447 struct sigaction sig_action;
448#endif
449#ifdef SO_TIMESTAMP
450 int on = 1;
451#endif
452 char *source_ip = NULL;
453 char * opts_str = "vhVw:c:n:p:t:H:s:i:b:I:l:m:P:R:J:S:M:O64";
454 setlocale (LC_ALL, "");
455 bindtextdomain (PACKAGE, LOCALEDIR);
456 textdomain (PACKAGE);
457 824
458 /* we only need to be setsuid when we get the sockets, so do 825 /* POSIXLY_CORRECT might break things, so unset it (the portable way) */
459 * that before pointer magic (esp. on network data) */ 826 environ = NULL;
460 icmp_sockerrno = udp_sockerrno = tcp_sockerrno = sockets = 0;
461 827
462 address_family = -1; 828 /* Parse extra opts if any */
463 int icmp_proto = IPPROTO_ICMP; 829 argv = np_extra_opts(&argc, argv, progname);
464 830
465 /* get calling name the old-fashioned way for portability instead 831 check_icmp_config_wrapper tmp_config = process_arguments(argc, argv);
466 * of relying on the glibc-ism __progname */
467 ptr = strrchr(argv[0], '/');
468 if(ptr) progname = &ptr[1];
469 else progname = argv[0];
470
471 /* now set defaults. Use progname to set them initially (allows for
472 * superfast check_host program when target host is up */
473 cursor = list = NULL;
474 table = NULL;
475
476 mode = MODE_RTA;
477 /* Default critical thresholds */
478 crit.rta = 500000;
479 crit.pl = 80;
480 crit.jitter = 50;
481 crit.mos= 3;
482 crit.score=70;
483 /* Default warning thresholds */
484 warn.rta = 200000;
485 warn.pl = 40;
486 warn.jitter = 40;
487 warn.mos= 3.5;
488 warn.score=80;
489
490 protocols = HAVE_ICMP | HAVE_UDP | HAVE_TCP;
491 pkt_interval = 80000; /* 80 msec packet interval by default */
492 packets = 5;
493
494 if(!strcmp(progname, "check_icmp") || !strcmp(progname, "check_ping")) {
495 mode = MODE_ICMP;
496 protocols = HAVE_ICMP;
497 }
498 else if(!strcmp(progname, "check_host")) {
499 mode = MODE_HOSTCHECK;
500 pkt_interval = 1000000;
501 packets = 5;
502 crit.rta = warn.rta = 1000000;
503 crit.pl = warn.pl = 100;
504 }
505 else if(!strcmp(progname, "check_rta_multi")) {
506 mode = MODE_ALL;
507 target_interval = 0;
508 pkt_interval = 50000;
509 packets = 5;
510 }
511 832
512 /* support "--help" and "--version" */ 833 if (tmp_config.errorcode != OK) {
513 if(argc == 2) { 834 crash("failed to parse config");
514 if(!strcmp(argv[1], "--help"))
515 strcpy(argv[1], "-h");
516 if(!strcmp(argv[1], "--version"))
517 strcpy(argv[1], "-V");
518 } 835 }
519 836
520 /* Parse protocol arguments first */ 837 const check_icmp_config config = tmp_config.config;
521 for(i = 1; i < argc; i++) { 838
522 while((arg = getopt(argc, argv, opts_str)) != EOF) { 839 if (config.output_format_is_set) {
523 switch(arg) { 840 mp_set_format(config.output_format);
524 case '4':
525 if (address_family != -1)
526 crash("Multiple protocol versions not supported");
527 address_family = AF_INET;
528 break;
529 case '6':
530#ifdef USE_IPV6
531 if (address_family != -1)
532 crash("Multiple protocol versions not supported");
533 address_family = AF_INET6;
534#else
535 usage (_("IPv6 support not available\n"));
536#endif
537 break;
538 }
539 }
540 } 841 }
541 842
542 /* Reset argument scanning */ 843 check_icmp_socket_set sockset = {
543 optind = 1; 844 .socket4 = -1,
845 .socket6 = -1,
846 };
544 847
545 unsigned long size; 848 if (config.need_v4) {
546 bool err; 849 sockset.socket4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
547 /* parse the arguments */ 850 if (sockset.socket4 == -1) {
548 for(i = 1; i < argc; i++) { 851 crash("Failed to obtain ICMP v4 socket");
549 while((arg = getopt(argc, argv, opts_str)) != EOF) { 852 }
550 switch(arg) {
551 case 'v':
552 debug++;
553 break;
554 case 'b':
555 size = strtol(optarg,NULL,0);
556 if (size >= (sizeof(struct icmp) + sizeof(struct icmp_ping_data)) &&
557 size < MAX_PING_DATA) {
558 icmp_data_size = size;
559 icmp_pkt_size = size + ICMP_MINLEN;
560 } else
561 usage_va("ICMP data length must be between: %lu and %lu",
562 sizeof(struct icmp) + sizeof(struct icmp_ping_data),
563 MAX_PING_DATA - 1);
564 break;
565 case 'i':
566 pkt_interval = get_timevar(optarg);
567 break;
568 case 'I':
569 target_interval = get_timevar(optarg);
570 break;
571 case 'w':
572 get_threshold(optarg, &warn);
573 break;
574 case 'c':
575 get_threshold(optarg, &crit);
576 break;
577 case 'n':
578 case 'p':
579 packets = strtoul(optarg, NULL, 0);
580 break;
581 case 't':
582 timeout = strtoul(optarg, NULL, 0);
583 if(!timeout) timeout = 10;
584 break;
585 case 'H':
586 add_target(optarg);
587 break;
588 case 'l':
589 ttl = (int)strtoul(optarg, NULL, 0);
590 break;
591 case 'm':
592 min_hosts_alive = (int)strtoul(optarg, NULL, 0);
593 break;
594 case 'd': /* implement later, for cluster checks */
595 warn_down = (unsigned char)strtoul(optarg, &ptr, 0);
596 if(ptr) {
597 crit_down = (unsigned char)strtoul(ptr + 1, NULL, 0);
598 }
599 break;
600 case 's': /* specify source IP address */
601 source_ip = optarg;
602 break;
603 case 'V': /* version */
604 print_revision (progname, NP_VERSION);
605 exit (STATE_UNKNOWN);
606 case 'h': /* help */
607 print_help ();
608 exit (STATE_UNKNOWN);
609 break;
610 case 'R': /* RTA mode */
611 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_rta_mode);
612 if (!err) {
613 crash("Failed to parse RTA threshold");
614 }
615 853
616 rta_mode=true; 854 if (config.source_ip) {
617 break;
618 case 'P': /* packet loss mode */
619 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_packet_loss_mode);
620 if (!err) {
621 crash("Failed to parse packet loss threshold");
622 }
623 855
624 pl_mode=true; 856 struct in_addr tmp = {};
625 break; 857 int error_code = inet_pton(AF_INET, config.source_ip, &tmp);
626 case 'J': /* jitter mode */ 858 if (error_code == 1) {
627 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_jitter_mode); 859 set_source_ip(config.source_ip, sockset.socket4, AF_INET);
628 if (!err) { 860 } else {
629 crash("Failed to parse jitter threshold"); 861 // just try this mindlessly if it's not a v4 address
630 } 862 set_source_ip(config.source_ip, sockset.socket6, AF_INET6);
863 }
864 }
631 865
632 jitter_mode=true; 866#ifdef SO_TIMESTAMP
633 break; 867 if (sockset.socket4 != -1) {
634 case 'M': /* MOS mode */ 868 int on = 1;
635 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_mos_mode); 869 if (setsockopt(sockset.socket4, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on))) {
636 if (!err) { 870 if (debug) {
637 crash("Failed to parse MOS threshold"); 871 printf("Warning: no SO_TIMESTAMP support\n");
638 } 872 }
639 873 }
640 mos_mode=true; 874 }
641 break; 875 if (sockset.socket6 != -1) {
642 case 'S': /* score mode */ 876 int on = 1;
643 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_score_mode); 877 if (setsockopt(sockset.socket6, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on))) {
644 if (!err) { 878 if (debug) {
645 crash("Failed to parse score threshold"); 879 printf("Warning: no SO_TIMESTAMP support\n");
646 } 880 }
647
648 score_mode=true;
649 break;
650 case 'O': /* out of order mode */
651 order_mode=true;
652 break;
653 } 881 }
654 } 882 }
883#endif // SO_TIMESTAMP
655 } 884 }
656 885
657 /* POSIXLY_CORRECT might break things, so unset it (the portable way) */ 886 if (config.need_v6) {
658 environ = NULL; 887 sockset.socket6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
659 888 if (sockset.socket6 == -1) {
660 /* use the pid to mark packets as ours */ 889 crash("Failed to obtain ICMP v6 socket");
661 /* Some systems have 32-bit pid_t so mask off only 16 bits */ 890 }
662 pid = getpid() & 0xffff;
663 /* printf("pid = %u\n", pid); */
664
665 /* Parse extra opts if any */
666 argv=np_extra_opts(&argc, argv, progname);
667
668 argv = &argv[optind];
669 while(*argv) {
670 add_target(*argv);
671 argv++;
672 }
673
674 if(!targets) {
675 errno = 0;
676 crash("No hosts to check");
677 }
678
679 // add_target might change address_family
680 switch ( address_family ){
681 case AF_INET: icmp_proto = IPPROTO_ICMP;
682 break;
683 case AF_INET6: icmp_proto = IPPROTO_ICMPV6;
684 break;
685 default: crash("Address family not supported");
686 } 891 }
687 if((icmp_sock = socket(address_family, SOCK_RAW, icmp_proto)) != -1)
688 sockets |= HAVE_ICMP;
689 else icmp_sockerrno = errno;
690
691 if( source_ip )
692 set_source_ip(source_ip);
693
694#ifdef SO_TIMESTAMP
695 if(setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)))
696 if(debug) printf("Warning: no SO_TIMESTAMP support\n");
697#endif // SO_TIMESTAMP
698 892
699 /* now drop privileges (no effect if not setsuid or geteuid() == 0) */ 893 /* now drop privileges (no effect if not setsuid or geteuid() == 0) */
700 if (setuid(getuid()) == -1) { 894 if (setuid(getuid()) == -1) {
@@ -702,177 +896,182 @@ main(int argc, char **argv)
702 return 1; 896 return 1;
703 } 897 }
704 898
705 if(!sockets) { 899 if (sockset.socket4) {
706 if(icmp_sock == -1) { 900 int result = setsockopt(sockset.socket4, SOL_IP, IP_TTL, &config.ttl, sizeof(config.ttl));
707 errno = icmp_sockerrno; 901 if (debug) {
708 crash("Failed to obtain ICMP socket"); 902 if (result == -1) {
709 return -1; 903 printf("setsockopt failed\n");
710 } 904 } else {
711 /* if(udp_sock == -1) { */ 905 printf("ttl set to %lu\n", config.ttl);
712 /* errno = icmp_sockerrno; */ 906 }
713 /* crash("Failed to obtain UDP socket"); */
714 /* return -1; */
715 /* } */
716 /* if(tcp_sock == -1) { */
717 /* errno = icmp_sockerrno; */
718 /* crash("Failed to obtain TCP socker"); */
719 /* return -1; */
720 /* } */
721 }
722 if(!ttl) ttl = 64;
723
724 if(icmp_sock) {
725 result = setsockopt(icmp_sock, SOL_IP, IP_TTL, &ttl, sizeof(ttl));
726 if(debug) {
727 if(result == -1) printf("setsockopt failed\n");
728 else printf("ttl set to %u\n", ttl);
729 } 907 }
730 } 908 }
731 909
732 /* stupid users should be able to give whatever thresholds they want 910 if (sockset.socket6) {
733 * (nothing will break if they do), but some anal plugin maintainer 911 int result = setsockopt(sockset.socket6, SOL_IP, IP_TTL, &config.ttl, sizeof(config.ttl));
734 * will probably add some printf() thing here later, so it might be 912 if (debug) {
735 * best to at least show them where to do it. ;) */ 913 if (result == -1) {
736 if(warn.pl > crit.pl) warn.pl = crit.pl; 914 printf("setsockopt failed\n");
737 if(warn.rta > crit.rta) warn.rta = crit.rta; 915 } else {
738 if(warn_down > crit_down) crit_down = warn_down; 916 printf("ttl set to %lu\n", config.ttl);
739 if(warn.jitter > crit.jitter) crit.jitter = warn.jitter; 917 }
740 if(warn.mos < crit.mos) warn.mos = crit.mos; 918 }
741 if(warn.score < crit.score) warn.score = crit.score; 919 }
742
743#ifdef HAVE_SIGACTION
744 sig_action.sa_sigaction = NULL;
745 sig_action.sa_handler = finish;
746 sigfillset(&sig_action.sa_mask);
747 sig_action.sa_flags = SA_NODEFER|SA_RESTART;
748 sigaction(SIGINT, &sig_action, NULL);
749 sigaction(SIGHUP, &sig_action, NULL);
750 sigaction(SIGTERM, &sig_action, NULL);
751 sigaction(SIGALRM, &sig_action, NULL);
752#else /* HAVE_SIGACTION */
753 signal(SIGINT, finish);
754 signal(SIGHUP, finish);
755 signal(SIGTERM, finish);
756 signal(SIGALRM, finish);
757#endif /* HAVE_SIGACTION */
758 if(debug) printf("Setting alarm timeout to %u seconds\n", timeout);
759 alarm(timeout);
760 920
761 /* make sure we don't wait any longer than necessary */ 921 /* make sure we don't wait any longer than necessary */
762 gettimeofday(&prog_start, &tz); 922 struct timeval prog_start;
763 max_completion_time = 923 gettimeofday(&prog_start, NULL);
764 ((targets * packets * pkt_interval) + (targets * target_interval)) +
765 (targets * packets * crit.rta) + crit.rta;
766 924
767 if(debug) { 925 time_t max_completion_time =
926 (config.target_interval * config.number_of_targets) +
927 (config.crit.rta * config.number_of_targets * config.number_of_packets) + config.crit.rta;
928
929 if (debug) {
768 printf("packets: %u, targets: %u\n" 930 printf("packets: %u, targets: %u\n"
769 "target_interval: %0.3f, pkt_interval %0.3f\n" 931 "target_interval: %0.3f\n"
770 "crit.rta: %0.3f\n" 932 "crit.rta: %0.3f\n"
771 "max_completion_time: %0.3f\n", 933 "max_completion_time: %0.3f\n",
772 packets, targets, 934 config.number_of_packets, config.number_of_targets,
773 (float)target_interval / 1000, (float)pkt_interval / 1000, 935 (float)config.target_interval / 1000, (float)config.crit.rta / 1000,
774 (float)crit.rta / 1000,
775 (float)max_completion_time / 1000); 936 (float)max_completion_time / 1000);
776 } 937 }
777 938
778 if(debug) { 939 if (debug) {
779 if(max_completion_time > (u_int)timeout * 1000000) { 940 if (max_completion_time > (timeout * 1000000)) {
780 printf("max_completion_time: %llu timeout: %u\n", 941 printf("max_completion_time: %ld timeout: %u\n", max_completion_time, timeout);
781 max_completion_time, timeout); 942 printf("Timeout must be at least %ld\n", (max_completion_time / 1000000) + 1);
782 printf("Timeout must be at least %llu\n",
783 max_completion_time / 1000000 + 1);
784 } 943 }
785 } 944 }
786 945
787 if(debug) { 946 if (debug) {
788 printf("crit = {%u, %u%%}, warn = {%u, %u%%}\n", 947 printf("crit = {%ld, %u%%}, warn = {%ld, %u%%}\n", config.crit.rta, config.crit.pl,
789 crit.rta, crit.pl, warn.rta, warn.pl); 948 config.warn.rta, config.warn.pl);
790 printf("pkt_interval: %u target_interval: %u retry_interval: %u\n", 949 printf("target_interval: %ld\n", config.target_interval);
791 pkt_interval, target_interval, retry_interval); 950 printf("icmp_pkt_size: %u timeout: %u\n", config.icmp_data_size + ICMP_MINLEN, timeout);
792 printf("icmp_pkt_size: %u timeout: %u\n",
793 icmp_pkt_size, timeout);
794 }
795
796 if(packets > 20) {
797 errno = 0;
798 crash("packets is > 20 (%d)", packets);
799 } 951 }
800 952
801 if(min_hosts_alive < -1) { 953 if (config.min_hosts_alive < -1) {
802 errno = 0; 954 errno = 0;
803 crash("minimum alive hosts is negative (%i)", min_hosts_alive); 955 crash("minimum alive hosts is negative (%i)", config.min_hosts_alive);
804 } 956 }
805 957
806 host = list; 958 // Build an index table of all targets
807 table = malloc(sizeof(struct rta_host *) * targets); 959 ping_target *host = config.targets;
808 if(!table) { 960 ping_target **table = malloc(sizeof(ping_target *) * config.number_of_targets);
961 if (!table) {
809 crash("main(): malloc failed for host table"); 962 crash("main(): malloc failed for host table");
810 } 963 }
811 964
812 i = 0; 965 unsigned short target_index = 0;
813 while(host) { 966 while (host) {
814 host->id = i*packets; 967 host->id = target_index * config.number_of_packets;
815 table[i] = host; 968 table[target_index] = host;
816 host = host->next; 969 host = host->next;
817 i++; 970 target_index++;
818 } 971 }
819 972
820 run_checks(); 973 time_t target_interval = config.target_interval;
974
975 check_icmp_state program_state = check_icmp_state_init();
976
977 run_checks(config.icmp_data_size, &target_interval, config.sender_id, config.mode,
978 max_completion_time, prog_start, table, config.number_of_packets, sockset,
979 config.number_of_targets, &program_state);
821 980
822 errno = 0; 981 errno = 0;
823 finish(0);
824 982
825 return(0); 983 mp_check overall = mp_check_init();
826} 984 finish(0, config.modes, config.min_hosts_alive, config.warn, config.crit,
985 config.number_of_targets, &program_state, config.hosts, config.number_of_hosts,
986 &overall);
827 987
828static void 988 if (sockset.socket4) {
829run_checks() 989 close(sockset.socket4);
830{ 990 }
831 u_int i, t; 991 if (sockset.socket6) {
832 u_int final_wait, time_passed; 992 close(sockset.socket6);
993 }
833 994
995 mp_exit(overall);
996}
997
998static void run_checks(unsigned short icmp_pkt_size, time_t *target_interval,
999 const uint16_t sender_id, const check_icmp_execution_mode mode,
1000 const time_t max_completion_time, const struct timeval prog_start,
1001 ping_target **table, const unsigned short packets,
1002 const check_icmp_socket_set sockset, const unsigned short number_of_targets,
1003 check_icmp_state *program_state) {
834 /* this loop might actually violate the pkt_interval or target_interval 1004 /* this loop might actually violate the pkt_interval or target_interval
835 * settings, but only if there aren't any packets on the wire which 1005 * settings, but only if there aren't any packets on the wire which
836 * indicates that the target can handle an increased packet rate */ 1006 * indicates that the target can handle an increased packet rate */
837 for(i = 0; i < packets; i++) { 1007 for (unsigned int packet_index = 0; packet_index < packets; packet_index++) {
838 for(t = 0; t < targets; t++) { 1008 for (unsigned int target_index = 0; target_index < number_of_targets; target_index++) {
839 /* don't send useless packets */ 1009 /* don't send useless packets */
840 if(!targets_alive) finish(0); 1010 if (!targets_alive(number_of_targets, program_state->targets_down)) {
841 if(table[t]->flags & FLAG_LOST_CAUSE) { 1011 return;
842 if(debug) printf("%s is a lost cause. not sending any more\n", 1012 }
843 table[t]->name); 1013 if (table[target_index]->flags & FLAG_LOST_CAUSE) {
1014 if (debug) {
1015
1016 char address[INET6_ADDRSTRLEN];
1017 parse_address(&table[target_index]->address, address, sizeof(address));
1018 printf("%s is a lost cause. not sending any more\n", address);
1019 }
844 continue; 1020 continue;
845 } 1021 }
846 1022
847 /* we're still in the game, so send next packet */ 1023 /* we're still in the game, so send next packet */
848 (void)send_icmp_ping(icmp_sock, table[t]); 1024 (void)send_icmp_ping(sockset, table[target_index], icmp_pkt_size, sender_id,
849 wait_for_reply(icmp_sock, target_interval); 1025 program_state);
1026
1027 /* wrap up if all targets are declared dead */
1028 if (targets_alive(number_of_targets, program_state->targets_down) ||
1029 get_timevaldiff(prog_start, prog_start) < max_completion_time ||
1030 !(mode == MODE_HOSTCHECK && program_state->targets_down)) {
1031 wait_for_reply(sockset, *target_interval, icmp_pkt_size, target_interval, sender_id,
1032 table, packets, number_of_targets, program_state);
1033 }
1034 }
1035 if (targets_alive(number_of_targets, program_state->targets_down) ||
1036 get_timevaldiff_to_now(prog_start) < max_completion_time ||
1037 !(mode == MODE_HOSTCHECK && program_state->targets_down)) {
1038 wait_for_reply(sockset, number_of_targets, icmp_pkt_size, target_interval, sender_id,
1039 table, packets, number_of_targets, program_state);
850 } 1040 }
851 wait_for_reply(icmp_sock, pkt_interval * targets);
852 } 1041 }
853 1042
854 if(icmp_pkts_en_route && targets_alive) { 1043 if (icmp_pkts_en_route(program_state->icmp_sent, program_state->icmp_recv,
855 time_passed = get_timevaldiff(NULL, NULL); 1044 program_state->icmp_lost) &&
856 final_wait = max_completion_time - time_passed; 1045 targets_alive(number_of_targets, program_state->targets_down)) {
1046 time_t time_passed = get_timevaldiff_to_now(prog_start);
1047 time_t final_wait = max_completion_time - time_passed;
857 1048
858 if(debug) { 1049 if (debug) {
859 printf("time_passed: %u final_wait: %u max_completion_time: %llu\n", 1050 printf("time_passed: %ld final_wait: %ld max_completion_time: %ld\n", time_passed,
860 time_passed, final_wait, max_completion_time); 1051 final_wait, max_completion_time);
861 } 1052 }
862 if(time_passed > max_completion_time) { 1053 if (time_passed > max_completion_time) {
863 if(debug) printf("Time passed. Finishing up\n"); 1054 if (debug) {
864 finish(0); 1055 printf("Time passed. Finishing up\n");
1056 }
1057 return;
865 } 1058 }
866 1059
867 /* catch the packets that might come in within the timeframe, but 1060 /* catch the packets that might come in within the timeframe, but
868 * haven't yet */ 1061 * haven't yet */
869 if(debug) printf("Waiting for %u micro-seconds (%0.3f msecs)\n", 1062 if (debug) {
870 final_wait, (float)final_wait / 1000); 1063 printf("Waiting for %ld micro-seconds (%0.3f msecs)\n", final_wait,
871 wait_for_reply(icmp_sock, final_wait); 1064 (float)final_wait / 1000);
1065 }
1066 if (targets_alive(number_of_targets, program_state->targets_down) ||
1067 get_timevaldiff_to_now(prog_start) < max_completion_time ||
1068 !(mode == MODE_HOSTCHECK && program_state->targets_down)) {
1069 wait_for_reply(sockset, final_wait, icmp_pkt_size, target_interval, sender_id, table,
1070 packets, number_of_targets, program_state);
1071 }
872 } 1072 }
873} 1073}
874 1074
875
876/* response structure: 1075/* response structure:
877 * IPv4: 1076 * IPv4:
878 * ip header : 20 bytes 1077 * ip header : 20 bytes
@@ -883,211 +1082,186 @@ run_checks()
883 * both: 1082 * both:
884 * icmp echo reply : the rest 1083 * icmp echo reply : the rest
885 */ 1084 */
886static int 1085static int wait_for_reply(check_icmp_socket_set sockset, const time_t time_interval,
887wait_for_reply(int sock, u_int t) 1086 unsigned short icmp_pkt_size, time_t *target_interval, uint16_t sender_id,
888{ 1087 ping_target **table, const unsigned short packets,
889 int n, hlen; 1088 const unsigned short number_of_targets, check_icmp_state *program_state) {
890 static unsigned char buf[65536];
891 struct sockaddr_storage resp_addr;
892 union ip_hdr *ip;
893 union icmp_packet packet; 1089 union icmp_packet packet;
894 struct rta_host *host;
895 struct icmp_ping_data data;
896 struct timeval wait_start, now;
897 u_int tdiff, i, per_pkt_wait;
898 double jitter_tmp;
899
900 if (!(packet.buf = malloc(icmp_pkt_size))) { 1090 if (!(packet.buf = malloc(icmp_pkt_size))) {
901 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", 1091 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", icmp_pkt_size);
902 icmp_pkt_size); 1092 return -1; /* might be reached if we're in debug mode */
903 return -1; /* might be reached if we're in debug mode */
904 } 1093 }
905 1094
906 memset(packet.buf, 0, icmp_pkt_size); 1095 memset(packet.buf, 0, icmp_pkt_size);
907 1096
908 /* if we can't listen or don't have anything to listen to, just return */ 1097 /* if we can't listen or don't have anything to listen to, just return */
909 if(!t || !icmp_pkts_en_route) { 1098 if (!time_interval || !icmp_pkts_en_route(program_state->icmp_sent, program_state->icmp_recv,
1099 program_state->icmp_lost)) {
910 free(packet.buf); 1100 free(packet.buf);
911 return 0; 1101 return 0;
912 } 1102 }
913 1103
914 gettimeofday(&wait_start, &tz); 1104 // Get current time stamp
1105 struct timeval wait_start;
1106 gettimeofday(&wait_start, NULL);
915 1107
916 i = t; 1108 struct sockaddr_storage resp_addr;
917 per_pkt_wait = t / icmp_pkts_en_route; 1109 time_t per_pkt_wait =
918 while(icmp_pkts_en_route && get_timevaldiff(&wait_start, NULL) < i) { 1110 time_interval / icmp_pkts_en_route(program_state->icmp_sent, program_state->icmp_recv,
919 t = per_pkt_wait; 1111 program_state->icmp_lost);
920 1112 static unsigned char buf[65536];
921 /* wrap up if all targets are declared dead */ 1113 union ip_hdr *ip_header;
922 if(!targets_alive || 1114 struct timeval packet_received_timestamp;
923 get_timevaldiff(&prog_start, NULL) >= max_completion_time || 1115 while (icmp_pkts_en_route(program_state->icmp_sent, program_state->icmp_recv,
924 (mode == MODE_HOSTCHECK && targets_down)) 1116 program_state->icmp_lost) &&
925 { 1117 get_timevaldiff_to_now(wait_start) < time_interval) {
926 finish(0); 1118 time_t loop_time_interval = per_pkt_wait;
927 }
928 1119
929 /* reap responses until we hit a timeout */ 1120 /* reap responses until we hit a timeout */
930 n = recvfrom_wto(sock, buf, sizeof(buf), 1121 recvfrom_wto_wrapper recv_foo =
931 (struct sockaddr *)&resp_addr, &t, &now); 1122 recvfrom_wto(sockset, buf, sizeof(buf), (struct sockaddr *)&resp_addr,
932 if(!n) { 1123 &loop_time_interval, &packet_received_timestamp);
933 if(debug > 1) { 1124 if (!recv_foo.received) {
934 printf("recvfrom_wto() timed out during a %u usecs wait\n", 1125 if (debug > 1) {
935 per_pkt_wait); 1126 printf("recvfrom_wto() timed out during a %ld usecs wait\n", per_pkt_wait);
936 } 1127 }
937 continue; /* timeout for this one, so keep trying */ 1128 continue; /* timeout for this one, so keep trying */
938 } 1129 }
939 if(n < 0) { 1130
940 if(debug) printf("recvfrom_wto() returned errors\n"); 1131 if (recv_foo.received < 0) {
1132 if (debug) {
1133 printf("recvfrom_wto() returned errors\n");
1134 }
941 free(packet.buf); 1135 free(packet.buf);
942 return n; 1136 return (int)recv_foo.received;
943 } 1137 }
944 1138
945 // FIXME: with ipv6 we don't have an ip header here 1139 if (recv_foo.recv_proto != AF_INET6) {
946 if (address_family != AF_INET6) { 1140 ip_header = (union ip_hdr *)buf;
947 ip = (union ip_hdr *)buf;
948 1141
949 if(debug > 1) { 1142 if (debug > 1) {
950 char address[INET6_ADDRSTRLEN]; 1143 char address[INET6_ADDRSTRLEN];
951 parse_address(&resp_addr, address, sizeof(address)); 1144 parse_address(&resp_addr, address, sizeof(address));
952 printf("received %u bytes from %s\n", 1145 printf("received %u bytes from %s\n",
953 address_family == AF_INET6 ? ntohs(ip->ip6.ip6_plen) 1146 address_family == AF_INET6 ? ntohs(ip_header->ip6.ip6_plen)
954 : ntohs(ip->ip.ip_len), 1147 : ntohs(ip_header->ip.ip_len),
955 address); 1148 address);
956 } 1149 }
957 } 1150 }
958 1151
959/* obsolete. alpha on tru64 provides the necessary defines, but isn't broken */ 1152 int hlen = (recv_foo.recv_proto == AF_INET6) ? 0 : ip_header->ip.ip_hl << 2;
960/* #if defined( __alpha__ ) && __STDC__ && !defined( __GLIBC__ ) */ 1153
961 /* alpha headers are decidedly broken. Using an ansi compiler, 1154 if (recv_foo.received < (hlen + ICMP_MINLEN)) {
962 * they provide ip_vhl instead of ip_hl and ip_v, so we mask
963 * off the bottom 4 bits */
964/* hlen = (ip->ip_vhl & 0x0f) << 2; */
965/* #else */
966 hlen = (address_family == AF_INET6) ? 0 : ip->ip.ip_hl << 2;
967/* #endif */
968
969 if(n < (hlen + ICMP_MINLEN)) {
970 char address[INET6_ADDRSTRLEN]; 1155 char address[INET6_ADDRSTRLEN];
971 parse_address(&resp_addr, address, sizeof(address)); 1156 parse_address(&resp_addr, address, sizeof(address));
972 crash("received packet too short for ICMP (%d bytes, expected %d) from %s\n", 1157 crash("received packet too short for ICMP (%ld bytes, expected %d) from %s\n",
973 n, hlen + icmp_pkt_size, address); 1158 recv_foo.received, hlen + icmp_pkt_size, address);
974 } 1159 }
975 /* else if(debug) { */
976 /* printf("ip header size: %u, packet size: %u (expected %u, %u)\n", */
977 /* hlen, ntohs(ip->ip_len) - hlen, */
978 /* sizeof(struct ip), icmp_pkt_size); */
979 /* } */
980
981 /* check the response */ 1160 /* check the response */
982
983 memcpy(packet.buf, buf + hlen, icmp_pkt_size); 1161 memcpy(packet.buf, buf + hlen, icmp_pkt_size);
984/* address_family == AF_INET6 ? sizeof(struct icmp6_hdr) 1162
985 : sizeof(struct icmp));*/ 1163 if ((recv_foo.recv_proto == AF_INET &&
986 1164 (ntohs(packet.icp->icmp_id) != sender_id || packet.icp->icmp_type != ICMP_ECHOREPLY ||
987 if( (address_family == PF_INET && 1165 ntohs(packet.icp->icmp_seq) >= number_of_targets * packets)) ||
988 (ntohs(packet.icp->icmp_id) != pid || packet.icp->icmp_type != ICMP_ECHOREPLY 1166 (recv_foo.recv_proto == AF_INET6 &&
989 || ntohs(packet.icp->icmp_seq) >= targets * packets)) 1167 (ntohs(packet.icp6->icmp6_id) != sender_id ||
990 || (address_family == PF_INET6 && 1168 packet.icp6->icmp6_type != ICMP6_ECHO_REPLY ||
991 (ntohs(packet.icp6->icmp6_id) != pid || packet.icp6->icmp6_type != ICMP6_ECHO_REPLY 1169 ntohs(packet.icp6->icmp6_seq) >= number_of_targets * packets))) {
992 || ntohs(packet.icp6->icmp6_seq) >= targets * packets))) { 1170 if (debug > 2) {
993 if(debug > 2) printf("not a proper ICMP_ECHOREPLY\n"); 1171 printf("not a proper ICMP_ECHOREPLY\n");
994 handle_random_icmp(buf + hlen, &resp_addr); 1172 }
1173
1174 handle_random_icmp(buf + hlen, &resp_addr, target_interval, sender_id, table, packets,
1175 number_of_targets, program_state);
1176
995 continue; 1177 continue;
996 } 1178 }
997 1179
998 /* this is indeed a valid response */ 1180 /* this is indeed a valid response */
999 if (address_family == PF_INET) { 1181 ping_target *target;
1182 struct icmp_ping_data data;
1183 if (address_family == AF_INET) {
1000 memcpy(&data, packet.icp->icmp_data, sizeof(data)); 1184 memcpy(&data, packet.icp->icmp_data, sizeof(data));
1001 if (debug > 2) 1185 if (debug > 2) {
1002 printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n", 1186 printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n", sizeof(data),
1003 (unsigned long)sizeof(data), ntohs(packet.icp->icmp_id), 1187 ntohs(packet.icp->icmp_id), ntohs(packet.icp->icmp_seq),
1004 ntohs(packet.icp->icmp_seq), packet.icp->icmp_cksum); 1188 packet.icp->icmp_cksum);
1005 host = table[ntohs(packet.icp->icmp_seq)/packets]; 1189 }
1190 target = table[ntohs(packet.icp->icmp_seq) / packets];
1006 } else { 1191 } else {
1007 memcpy(&data, &packet.icp6->icmp6_dataun.icmp6_un_data8[4], sizeof(data)); 1192 memcpy(&data, &packet.icp6->icmp6_dataun.icmp6_un_data8[4], sizeof(data));
1008 if (debug > 2) 1193 if (debug > 2) {
1009 printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n", 1194 printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n", sizeof(data),
1010 (unsigned long)sizeof(data), ntohs(packet.icp6->icmp6_id), 1195 ntohs(packet.icp6->icmp6_id), ntohs(packet.icp6->icmp6_seq),
1011 ntohs(packet.icp6->icmp6_seq), packet.icp6->icmp6_cksum); 1196 packet.icp6->icmp6_cksum);
1012 host = table[ntohs(packet.icp6->icmp6_seq)/packets]; 1197 }
1198 target = table[ntohs(packet.icp6->icmp6_seq) / packets];
1013 } 1199 }
1014 1200
1015 tdiff = get_timevaldiff(&data.stime, &now); 1201 time_t tdiff = get_timevaldiff(data.stime, packet_received_timestamp);
1016 1202
1017 if (host->last_tdiff>0) { 1203 if (target->last_tdiff > 0) {
1018 /* Calculate jitter */ 1204 /* Calculate jitter */
1019 if (host->last_tdiff > tdiff) { 1205 double jitter_tmp;
1020 jitter_tmp = host->last_tdiff - tdiff; 1206 if (target->last_tdiff > tdiff) {
1207 jitter_tmp = (double)(target->last_tdiff - tdiff);
1021 } else { 1208 } else {
1022 jitter_tmp = tdiff - host->last_tdiff; 1209 jitter_tmp = (double)(tdiff - target->last_tdiff);
1023 } 1210 }
1024 1211
1025 if (host->jitter==0) { 1212 if (target->jitter == 0) {
1026 host->jitter=jitter_tmp; 1213 target->jitter = jitter_tmp;
1027 host->jitter_max=jitter_tmp; 1214 target->jitter_max = jitter_tmp;
1028 host->jitter_min=jitter_tmp; 1215 target->jitter_min = jitter_tmp;
1029 } else { 1216 } else {
1030 host->jitter+=jitter_tmp; 1217 target->jitter += jitter_tmp;
1031 1218
1032 if (jitter_tmp < host->jitter_min) { 1219 if (jitter_tmp < target->jitter_min) {
1033 host->jitter_min=jitter_tmp; 1220 target->jitter_min = jitter_tmp;
1034 } 1221 }
1035 1222
1036 if (jitter_tmp > host->jitter_max) { 1223 if (jitter_tmp > target->jitter_max) {
1037 host->jitter_max=jitter_tmp; 1224 target->jitter_max = jitter_tmp;
1038 } 1225 }
1039 } 1226 }
1040 1227
1041 /* Check if packets in order */ 1228 /* Check if packets in order */
1042 if (host->last_icmp_seq >= packet.icp->icmp_seq) 1229 if (target->last_icmp_seq >= packet.icp->icmp_seq) {
1043 host->order_status=STATE_CRITICAL; 1230 target->found_out_of_order_packets = true;
1231 }
1044 } 1232 }
1045 host->last_tdiff=tdiff; 1233 target->last_tdiff = tdiff;
1046 1234
1047 host->last_icmp_seq=packet.icp->icmp_seq; 1235 target->last_icmp_seq = packet.icp->icmp_seq;
1048 1236
1049 host->time_waited += tdiff; 1237 target->time_waited += tdiff;
1050 host->icmp_recv++; 1238 target->icmp_recv++;
1051 icmp_recv++; 1239 program_state->icmp_recv++;
1052 if (tdiff > (unsigned int)host->rtmax)
1053 host->rtmax = tdiff;
1054 if (tdiff < (unsigned int)host->rtmin)
1055 host->rtmin = tdiff;
1056 1240
1057 if(debug) { 1241 if (tdiff > (unsigned int)target->rtmax) {
1058 char address[INET6_ADDRSTRLEN]; 1242 target->rtmax = (double)tdiff;
1059 parse_address(&resp_addr, address, sizeof(address)); 1243 }
1060 1244
1061 switch(address_family) { 1245 if ((target->rtmin == INFINITY) || (tdiff < (unsigned int)target->rtmin)) {
1062 case AF_INET: { 1246 target->rtmin = (double)tdiff;
1063 printf("%0.3f ms rtt from %s, outgoing ttl: %u, incoming ttl: %u, max: %0.3f, min: %0.3f\n",
1064 (float)tdiff / 1000,
1065 address,
1066 ttl,
1067 ip->ip.ip_ttl,
1068 (float)host->rtmax / 1000,
1069 (float)host->rtmin / 1000);
1070 break;
1071 };
1072 case AF_INET6: {
1073 printf("%0.3f ms rtt from %s, outgoing ttl: %u, max: %0.3f, min: %0.3f\n",
1074 (float)tdiff / 1000,
1075 address,
1076 ttl,
1077 (float)host->rtmax / 1000,
1078 (float)host->rtmin / 1000);
1079 };
1080 }
1081 } 1247 }
1082 1248
1083 /* if we're in hostcheck mode, exit with limited printouts */ 1249 if (debug) {
1084 if(mode == MODE_HOSTCHECK) { 1250 char address[INET6_ADDRSTRLEN];
1085 printf("OK - %s responds to ICMP. Packet %u, rta %0.3fms|" 1251 parse_address(&resp_addr, address, sizeof(address));
1086 "pkt=%u;;;0;%u rta=%0.3f;%0.3f;%0.3f;;\n", 1252
1087 host->name, icmp_recv, (float)tdiff / 1000, 1253 switch (recv_foo.recv_proto) {
1088 icmp_recv, packets, (float)tdiff / 1000, 1254 case AF_INET: {
1089 (float)warn.rta / 1000, (float)crit.rta / 1000); 1255 printf("%0.3f ms rtt from %s, incoming ttl: %u, max: %0.3f, min: %0.3f\n",
1090 exit(STATE_OK); 1256 (float)tdiff / 1000, address, ip_header->ip.ip_ttl,
1257 (float)target->rtmax / 1000, (float)target->rtmin / 1000);
1258 break;
1259 };
1260 case AF_INET6: {
1261 printf("%0.3f ms rtt from %s, max: %0.3f, min: %0.3f\n", (float)tdiff / 1000,
1262 address, (float)target->rtmax / 1000, (float)target->rtmin / 1000);
1263 };
1264 }
1091 } 1265 }
1092 } 1266 }
1093 1267
@@ -1096,42 +1270,29 @@ wait_for_reply(int sock, u_int t)
1096} 1270}
1097 1271
1098/* the ping functions */ 1272/* the ping functions */
1099static int 1273static int send_icmp_ping(const check_icmp_socket_set sockset, ping_target *host,
1100send_icmp_ping(int sock, struct rta_host *host) 1274 const unsigned short icmp_pkt_size, const uint16_t sender_id,
1101{ 1275 check_icmp_state *program_state) {
1102 long int len; 1276 void *buf = calloc(1, icmp_pkt_size);
1103 size_t addrlen; 1277 if (!buf) {
1104 struct icmp_ping_data data; 1278 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", icmp_pkt_size);
1105 struct msghdr hdr; 1279 return -1; /* might be reached if we're in debug mode */
1106 struct iovec iov;
1107 struct timeval tv;
1108 void *buf = NULL;
1109
1110 if(sock == -1) {
1111 errno = 0;
1112 crash("Attempt to send on bogus socket");
1113 return -1;
1114 }
1115
1116 if(!buf) {
1117 if (!(buf = malloc(icmp_pkt_size))) {
1118 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer",
1119 icmp_pkt_size);
1120 return -1; /* might be reached if we're in debug mode */
1121 }
1122 } 1280 }
1123 memset(buf, 0, icmp_pkt_size);
1124 1281
1125 if((gettimeofday(&tv, &tz)) == -1) { 1282 struct timeval current_time;
1283 if ((gettimeofday(&current_time, NULL)) == -1) {
1126 free(buf); 1284 free(buf);
1127 return -1; 1285 return -1;
1128 } 1286 }
1129 1287
1288 struct icmp_ping_data data;
1130 data.ping_id = 10; /* host->icmp.icmp_sent; */ 1289 data.ping_id = 10; /* host->icmp.icmp_sent; */
1131 memcpy(&data.stime, &tv, sizeof(tv)); 1290 memcpy(&data.stime, &current_time, sizeof(current_time));
1291
1292 socklen_t addrlen = 0;
1132 1293
1133 if (address_family == AF_INET) { 1294 if (host->address.ss_family == AF_INET) {
1134 struct icmp *icp = (struct icmp*)buf; 1295 struct icmp *icp = (struct icmp *)buf;
1135 addrlen = sizeof(struct sockaddr_in); 1296 addrlen = sizeof(struct sockaddr_in);
1136 1297
1137 memcpy(&icp->icmp_data, &data, sizeof(data)); 1298 memcpy(&icp->icmp_data, &data, sizeof(data));
@@ -1139,16 +1300,20 @@ send_icmp_ping(int sock, struct rta_host *host)
1139 icp->icmp_type = ICMP_ECHO; 1300 icp->icmp_type = ICMP_ECHO;
1140 icp->icmp_code = 0; 1301 icp->icmp_code = 0;
1141 icp->icmp_cksum = 0; 1302 icp->icmp_cksum = 0;
1142 icp->icmp_id = htons(pid); 1303 icp->icmp_id = htons((uint16_t)sender_id);
1143 icp->icmp_seq = htons(host->id++); 1304 icp->icmp_seq = htons(host->id++);
1144 icp->icmp_cksum = icmp_checksum((uint16_t*)buf, (size_t)icmp_pkt_size); 1305 icp->icmp_cksum = icmp_checksum((uint16_t *)buf, (size_t)icmp_pkt_size);
1306
1307 if (debug > 2) {
1308 char address[INET6_ADDRSTRLEN];
1309 parse_address((&host->address), address, sizeof(address));
1145 1310
1146 if (debug > 2)
1147 printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n", 1311 printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n",
1148 (unsigned long)sizeof(data), ntohs(icp->icmp_id), ntohs(icp->icmp_seq), icp->icmp_cksum, host->name); 1312 sizeof(data), ntohs(icp->icmp_id), ntohs(icp->icmp_seq), icp->icmp_cksum,
1149 } 1313 address);
1150 else { 1314 }
1151 struct icmp6_hdr *icp6 = (struct icmp6_hdr*)buf; 1315 } else if (host->address.ss_family == AF_INET6) {
1316 struct icmp6_hdr *icp6 = (struct icmp6_hdr *)buf;
1152 addrlen = sizeof(struct sockaddr_in6); 1317 addrlen = sizeof(struct sockaddr_in6);
1153 1318
1154 memcpy(&icp6->icmp6_dataun.icmp6_un_data8[4], &data, sizeof(data)); 1319 memcpy(&icp6->icmp6_dataun.icmp6_un_data8[4], &data, sizeof(data));
@@ -1156,685 +1321,466 @@ send_icmp_ping(int sock, struct rta_host *host)
1156 icp6->icmp6_type = ICMP6_ECHO_REQUEST; 1321 icp6->icmp6_type = ICMP6_ECHO_REQUEST;
1157 icp6->icmp6_code = 0; 1322 icp6->icmp6_code = 0;
1158 icp6->icmp6_cksum = 0; 1323 icp6->icmp6_cksum = 0;
1159 icp6->icmp6_id = htons(pid); 1324 icp6->icmp6_id = htons((uint16_t)sender_id);
1160 icp6->icmp6_seq = htons(host->id++); 1325 icp6->icmp6_seq = htons(host->id++);
1161 // let checksum be calculated automatically 1326 // let checksum be calculated automatically
1162 1327
1163 if (debug > 2) { 1328 if (debug > 2) {
1164 printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n", 1329 char address[INET6_ADDRSTRLEN];
1165 (unsigned long)sizeof(data), ntohs(icp6->icmp6_id), 1330 parse_address((&host->address), address, sizeof(address));
1166 ntohs(icp6->icmp6_seq), icp6->icmp6_cksum, host->name); 1331
1332 printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to target %s\n",
1333 sizeof(data), ntohs(icp6->icmp6_id), ntohs(icp6->icmp6_seq), icp6->icmp6_cksum,
1334 address);
1167 } 1335 }
1336 } else {
1337 // unknown address family
1338 crash("unknown address family in %s", __func__);
1168 } 1339 }
1169 1340
1341 struct iovec iov;
1170 memset(&iov, 0, sizeof(iov)); 1342 memset(&iov, 0, sizeof(iov));
1171 iov.iov_base = buf; 1343 iov.iov_base = buf;
1172 iov.iov_len = icmp_pkt_size; 1344 iov.iov_len = icmp_pkt_size;
1173 1345
1346 struct msghdr hdr;
1174 memset(&hdr, 0, sizeof(hdr)); 1347 memset(&hdr, 0, sizeof(hdr));
1175 hdr.msg_name = (struct sockaddr *)&host->saddr_in; 1348 hdr.msg_name = (struct sockaddr *)&host->address;
1176 hdr.msg_namelen = addrlen; 1349 hdr.msg_namelen = addrlen;
1177 hdr.msg_iov = &iov; 1350 hdr.msg_iov = &iov;
1178 hdr.msg_iovlen = 1; 1351 hdr.msg_iovlen = 1;
1179 1352
1180 errno = 0; 1353 errno = 0;
1181 1354
1182/* MSG_CONFIRM is a linux thing and only available on linux kernels >= 2.3.15, see send(2) */ 1355 long int len;
1356 /* MSG_CONFIRM is a linux thing and only available on linux kernels >= 2.3.15, see send(2) */
1357 if (host->address.ss_family == AF_INET) {
1183#ifdef MSG_CONFIRM 1358#ifdef MSG_CONFIRM
1184 len = sendmsg(sock, &hdr, MSG_CONFIRM); 1359 len = sendmsg(sockset.socket4, &hdr, MSG_CONFIRM);
1185#else 1360#else
1186 len = sendmsg(sock, &hdr, 0); 1361 len = sendmsg(sockset.socket4, &hdr, 0);
1187#endif 1362#endif
1363 } else if (host->address.ss_family == AF_INET6) {
1364#ifdef MSG_CONFIRM
1365 len = sendmsg(sockset.socket6, &hdr, MSG_CONFIRM);
1366#else
1367 len = sendmsg(sockset.socket6, &hdr, 0);
1368#endif
1369 } else {
1370 assert(false);
1371 }
1188 1372
1189 free(buf); 1373 free(buf);
1190 1374
1191 if(len < 0 || (unsigned int)len != icmp_pkt_size) { 1375 if (len < 0 || (unsigned int)len != icmp_pkt_size) {
1192 if(debug) { 1376 if (debug) {
1193 char address[INET6_ADDRSTRLEN]; 1377 char address[INET6_ADDRSTRLEN];
1194 parse_address((struct sockaddr_storage *)&host->saddr_in, address, sizeof(address)); 1378 parse_address((&host->address), address, sizeof(address));
1195 printf("Failed to send ping to %s: %s\n", address, strerror(errno)); 1379 printf("Failed to send ping to %s: %s\n", address, strerror(errno));
1196 } 1380 }
1197 errno = 0; 1381 errno = 0;
1198 return -1; 1382 return -1;
1199 } 1383 }
1200 1384
1201 icmp_sent++; 1385 program_state->icmp_sent++;
1202 host->icmp_sent++; 1386 host->icmp_sent++;
1203 1387
1204 return 0; 1388 return 0;
1205} 1389}
1206 1390
1207static int 1391static recvfrom_wto_wrapper recvfrom_wto(const check_icmp_socket_set sockset, void *buf,
1208recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr, 1392 const unsigned int len, struct sockaddr *saddr,
1209 u_int *timo, struct timeval* tv) 1393 time_t *timeout, struct timeval *received_timestamp) {
1210{
1211 u_int slen;
1212 int n, ret;
1213 struct timeval to, then, now;
1214 fd_set rd, wr;
1215#ifdef HAVE_MSGHDR_MSG_CONTROL 1394#ifdef HAVE_MSGHDR_MSG_CONTROL
1216 char ans_data[4096]; 1395 char ans_data[4096];
1217#endif // HAVE_MSGHDR_MSG_CONTROL 1396#endif // HAVE_MSGHDR_MSG_CONTROL
1218 struct msghdr hdr;
1219 struct iovec iov;
1220#ifdef SO_TIMESTAMP 1397#ifdef SO_TIMESTAMP
1221 struct cmsghdr* chdr; 1398 struct cmsghdr *chdr;
1222#endif 1399#endif
1223 1400
1224 if(!*timo) { 1401 recvfrom_wto_wrapper result = {
1225 if(debug) printf("*timo is not\n"); 1402 .received = 0,
1226 return 0; 1403 .recv_proto = AF_UNSPEC,
1227 } 1404 };
1228
1229 to.tv_sec = *timo / 1000000;
1230 to.tv_usec = (*timo - (to.tv_sec * 1000000));
1231
1232 FD_ZERO(&rd);
1233 FD_ZERO(&wr);
1234 FD_SET(sock, &rd);
1235 errno = 0;
1236 gettimeofday(&then, &tz);
1237 n = select(sock + 1, &rd, &wr, NULL, &to);
1238 if(n < 0) crash("select() in recvfrom_wto");
1239 gettimeofday(&now, &tz);
1240 *timo = get_timevaldiff(&then, &now);
1241
1242 if(!n) return 0; /* timeout */
1243
1244 slen = sizeof(struct sockaddr_storage);
1245
1246 memset(&iov, 0, sizeof(iov));
1247 iov.iov_base = buf;
1248 iov.iov_len = len;
1249 1405
1250 memset(&hdr, 0, sizeof(hdr)); 1406 if (!*timeout) {
1251 hdr.msg_name = saddr; 1407 if (debug) {
1252 hdr.msg_namelen = slen; 1408 printf("*timeout is not\n");
1253 hdr.msg_iov = &iov;
1254 hdr.msg_iovlen = 1;
1255#ifdef HAVE_MSGHDR_MSG_CONTROL
1256 hdr.msg_control = ans_data;
1257 hdr.msg_controllen = sizeof(ans_data);
1258#endif
1259
1260 ret = recvmsg(sock, &hdr, 0);
1261#ifdef SO_TIMESTAMP
1262 for(chdr = CMSG_FIRSTHDR(&hdr); chdr; chdr = CMSG_NXTHDR(&hdr, chdr)) {
1263 if(chdr->cmsg_level == SOL_SOCKET
1264 && chdr->cmsg_type == SO_TIMESTAMP
1265 && chdr->cmsg_len >= CMSG_LEN(sizeof(struct timeval))) {
1266 memcpy(tv, CMSG_DATA(chdr), sizeof(*tv));
1267 break ;
1268 } 1409 }
1410 return result;
1269 } 1411 }
1270 1412
1271 if (!chdr) 1413 struct timeval real_timeout;
1272#endif // SO_TIMESTAMP 1414 real_timeout.tv_sec = *timeout / 1000000;
1273 gettimeofday(tv, &tz); 1415 real_timeout.tv_usec = (*timeout - (real_timeout.tv_sec * 1000000));
1274 return (ret);
1275}
1276 1416
1277static void 1417 // Dummy fds for select
1278finish(int sig) 1418 fd_set dummy_write_fds;
1279{ 1419 FD_ZERO(&dummy_write_fds);
1280 u_int i = 0;
1281 unsigned char pl;
1282 double rta;
1283 struct rta_host *host;
1284 const char *status_string[] =
1285 {"OK", "WARNING", "CRITICAL", "UNKNOWN", "DEPENDENT"};
1286 int hosts_ok = 0;
1287 int hosts_warn = 0;
1288 int this_status;
1289 double R;
1290 1420
1291 alarm(0); 1421 // Read fds for select with the socket
1292 if(debug > 1) printf("finish(%d) called\n", sig); 1422 fd_set read_fds;
1293 1423 FD_ZERO(&read_fds);
1294 if(icmp_sock != -1) close(icmp_sock);
1295 if(udp_sock != -1) close(udp_sock);
1296 if(tcp_sock != -1) close(tcp_sock);
1297 1424
1298 if(debug) { 1425 if (sockset.socket4 != -1) {
1299 printf("icmp_sent: %u icmp_recv: %u icmp_lost: %u\n", 1426 FD_SET(sockset.socket4, &read_fds);
1300 icmp_sent, icmp_recv, icmp_lost); 1427 }
1301 printf("targets: %u targets_alive: %u\n", targets, targets_alive); 1428 if (sockset.socket6 != -1) {
1429 FD_SET(sockset.socket6, &read_fds);
1302 } 1430 }
1303 1431
1304 /* iterate thrice to calculate values, give output, and print perfparse */ 1432 int nfds = (sockset.socket4 > sockset.socket6 ? sockset.socket4 : sockset.socket6) + 1;
1305 status=STATE_OK;
1306 host = list;
1307 1433
1308 while(host) { 1434 struct timeval then;
1309 this_status = STATE_OK; 1435 gettimeofday(&then, NULL);
1310 1436
1311 if(!host->icmp_recv) { 1437 errno = 0;
1312 /* rta 0 is ofcourse not entirely correct, but will still show up 1438 int select_return = select(nfds, &read_fds, &dummy_write_fds, NULL, &real_timeout);
1313 * conspicuously as missing entries in perfparse and cacti */ 1439 if (select_return < 0) {
1314 pl = 100; 1440 crash("select() in recvfrom_wto");
1315 rta = 0; 1441 }
1316 status = STATE_CRITICAL;
1317 /* up the down counter if not already counted */
1318 if(!(host->flags & FLAG_LOST_CAUSE) && targets_alive) targets_down++;
1319 } else {
1320 pl = ((host->icmp_sent - host->icmp_recv) * 100) / host->icmp_sent;
1321 rta = (double)host->time_waited / host->icmp_recv;
1322 }
1323
1324 if (host->icmp_recv>1) {
1325 /*
1326 * This algorithm is probably pretty much blindly copied from
1327 * locations like this one: https://www.slac.stanford.edu/comp/net/wan-mon/tutorial.html#mos
1328 * It calculates a MOS value (range of 1 to 5, where 1 is bad and 5 really good).
1329 * According to some quick research MOS originates from the Audio/Video transport network area.
1330 * Whether it can and should be computed from ICMP data, I can not say.
1331 *
1332 * Anyway the basic idea is to map a value "R" with a range of 0-100 to the MOS value
1333 *
1334 * MOS stands likely for Mean Opinion Score ( https://en.wikipedia.org/wiki/Mean_Opinion_Score )
1335 *
1336 * More links:
1337 * - https://confluence.slac.stanford.edu/display/IEPM/MOS
1338 */
1339 host->jitter=(host->jitter / (host->icmp_recv - 1)/1000);
1340
1341 /*
1342 * Take the average round trip latency (in milliseconds), add
1343 * round trip jitter, but double the impact to latency
1344 * then add 10 for protocol latencies (in milliseconds).
1345 */
1346 host->EffectiveLatency = (rta/1000) + host->jitter * 2 + 10;
1347
1348 if (host->EffectiveLatency < 160) {
1349 R = 93.2 - (host->EffectiveLatency / 40);
1350 } else {
1351 R = 93.2 - ((host->EffectiveLatency - 120) / 10);
1352 }
1353 1442
1354 // Now, let us deduct 2.5 R values per percentage of packet loss (i.e. a 1443 struct timeval now;
1355 // loss of 5% will be entered as 5). 1444 gettimeofday(&now, NULL);
1356 R = R - (pl * 2.5); 1445 *timeout = get_timevaldiff(then, now);
1357 1446
1358 if (R < 0) { 1447 if (!select_return) {
1359 R = 0; 1448 return result; /* timeout */
1360 } 1449 }
1361 1450
1362 host->score = R; 1451 unsigned int slen = sizeof(struct sockaddr_storage);
1363 host->mos= 1 + ((0.035) * R) + ((.000007) * R * (R-60) * (100-R));
1364 } else {
1365 host->jitter=0;
1366 host->jitter_min=0;
1367 host->jitter_max=0;
1368 host->mos=0;
1369 }
1370 1452
1371 host->pl = pl; 1453 struct iovec iov = {
1372 host->rta = rta; 1454 .iov_base = buf,
1455 .iov_len = len,
1456 };
1373 1457
1374 /* if no new mode selected, use old schema */ 1458 struct msghdr hdr = {
1375 if (!rta_mode && !pl_mode && !jitter_mode && !score_mode && !mos_mode && !order_mode) { 1459 .msg_name = saddr,
1376 rta_mode = true; 1460 .msg_namelen = slen,
1377 pl_mode = true; 1461 .msg_iov = &iov,
1378 } 1462 .msg_iovlen = 1,
1463#ifdef HAVE_MSGHDR_MSG_CONTROL
1464 .msg_control = ans_data,
1465 .msg_controllen = sizeof(ans_data),
1466#endif
1467 };
1379 1468
1380 /* Check which mode is on and do the warn / Crit stuff */ 1469 ssize_t ret;
1381 if (rta_mode) { 1470 if (FD_ISSET(sockset.socket4, &read_fds)) {
1382 if(rta >= crit.rta) { 1471 ret = recvmsg(sockset.socket4, &hdr, 0);
1383 this_status = STATE_CRITICAL; 1472 result.recv_proto = AF_INET;
1384 status = STATE_CRITICAL; 1473 } else if (FD_ISSET(sockset.socket6, &read_fds)) {
1385 host->rta_status=STATE_CRITICAL; 1474 ret = recvmsg(sockset.socket6, &hdr, 0);
1386 } else if(status!=STATE_CRITICAL && (rta >= warn.rta)) { 1475 result.recv_proto = AF_INET6;
1387 this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status); 1476 } else {
1388 status = STATE_WARNING; 1477 assert(false);
1389 host->rta_status=STATE_WARNING; 1478 }
1390 }
1391 }
1392 1479
1393 if (pl_mode) { 1480 result.received = ret;
1394 if(pl >= crit.pl) {
1395 this_status = STATE_CRITICAL;
1396 status = STATE_CRITICAL;
1397 host->pl_status=STATE_CRITICAL;
1398 } else if(status!=STATE_CRITICAL && (pl >= warn.pl)) {
1399 this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
1400 status = STATE_WARNING;
1401 host->pl_status=STATE_WARNING;
1402 }
1403 }
1404 1481
1405 if (jitter_mode) { 1482#ifdef SO_TIMESTAMP
1406 if(host->jitter >= crit.jitter) { 1483 for (chdr = CMSG_FIRSTHDR(&hdr); chdr; chdr = CMSG_NXTHDR(&hdr, chdr)) {
1407 this_status = STATE_CRITICAL; 1484 if (chdr->cmsg_level == SOL_SOCKET && chdr->cmsg_type == SO_TIMESTAMP &&
1408 status = STATE_CRITICAL; 1485 chdr->cmsg_len >= CMSG_LEN(sizeof(struct timeval))) {
1409 host->jitter_status=STATE_CRITICAL; 1486 memcpy(received_timestamp, CMSG_DATA(chdr), sizeof(*received_timestamp));
1410 } else if(status!=STATE_CRITICAL && (host->jitter >= warn.jitter)) { 1487 break;
1411 this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
1412 status = STATE_WARNING;
1413 host->jitter_status=STATE_WARNING;
1414 }
1415 } 1488 }
1489 }
1416 1490
1417 if (mos_mode) { 1491 if (!chdr) {
1418 if(host->mos <= crit.mos) { 1492 gettimeofday(received_timestamp, NULL);
1419 this_status = STATE_CRITICAL; 1493 }
1420 status = STATE_CRITICAL; 1494#else
1421 host->mos_status=STATE_CRITICAL; 1495 gettimeofday(tv, NULL);
1422 } else if(status!=STATE_CRITICAL && (host->mos <= warn.mos)) { 1496#endif // SO_TIMESTAMP
1423 this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
1424 status = STATE_WARNING;
1425 host->mos_status=STATE_WARNING;
1426 }
1427 }
1428 1497
1429 if (score_mode) { 1498 return (result);
1430 if(host->score <= crit.score) { 1499}
1431 this_status = STATE_CRITICAL;
1432 status = STATE_CRITICAL;
1433 host->score_status=STATE_CRITICAL;
1434 } else if(status!=STATE_CRITICAL && (host->score <= warn.score)) {
1435 this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
1436 status = STATE_WARNING;
1437 host->score_status=STATE_WARNING;
1438 }
1439 }
1440 1500
1441 if (this_status == STATE_WARNING) { 1501static void finish(int sig, check_icmp_mode_switches modes, int min_hosts_alive,
1442 hosts_warn++; 1502 check_icmp_threshold warn, check_icmp_threshold crit,
1443 } else if (this_status == STATE_OK) { 1503 const unsigned short number_of_targets, check_icmp_state *program_state,
1444 hosts_ok++; 1504 check_icmp_target_container host_list[], unsigned short number_of_hosts,
1445 } 1505 mp_check overall[static 1]) {
1506 // Deactivate alarm
1507 alarm(0);
1446 1508
1447 host = host->next; 1509 if (debug > 1) {
1510 printf("finish(%d) called\n", sig);
1448 } 1511 }
1449 1512
1450 1513 if (debug) {
1451 /* this is inevitable */ 1514 printf("icmp_sent: %u icmp_recv: %u icmp_lost: %u\n", program_state->icmp_sent,
1452 if(!targets_alive) status = STATE_CRITICAL; 1515 program_state->icmp_recv, program_state->icmp_lost);
1453 if(min_hosts_alive > -1) { 1516 printf("targets: %u targets_alive: %u\n", number_of_targets,
1454 if(hosts_ok >= min_hosts_alive) status = STATE_OK; 1517 targets_alive(number_of_targets, program_state->targets_down));
1455 else if((hosts_ok + hosts_warn) >= min_hosts_alive) status = STATE_WARNING;
1456 } 1518 }
1457 printf("%s - ", status_string[status]);
1458 1519
1459 host = list; 1520 // loop over targets to evaluate each one
1460 while(host) { 1521 int targets_ok = 0;
1522 int targets_warn = 0;
1523 for (unsigned short i = 0; i < number_of_hosts; i++) {
1524 evaluate_host_wrapper host_check = evaluate_host(host_list[i], modes, warn, crit);
1461 1525
1462 if(debug) puts(""); 1526 targets_ok += host_check.targets_ok;
1463 if(i) { 1527 targets_warn += host_check.targets_warn;
1464 if(i < targets) printf(" :: ");
1465 else printf("\n");
1466 }
1467 i++;
1468 if(!host->icmp_recv) {
1469 status = STATE_CRITICAL;
1470 host->rtmin=0;
1471 host->jitter_min=0;
1472 if(host->flags & FLAG_LOST_CAUSE) {
1473 char address[INET6_ADDRSTRLEN];
1474 parse_address(&host->error_addr, address, sizeof(address));
1475 printf("%s: %s @ %s. rta nan, lost %d%%",
1476 host->name,
1477 get_icmp_error_msg(host->icmp_type, host->icmp_code),
1478 address,
1479 100);
1480 } else { /* not marked as lost cause, so we have no flags for it */
1481 printf("%s: rta nan, lost 100%%", host->name);
1482 }
1483 } else { /* !icmp_recv */
1484 printf("%s", host->name);
1485 /* rta text output */
1486 if (rta_mode) {
1487 if (status == STATE_OK)
1488 printf(" rta %0.3fms", host->rta / 1000);
1489 else if (status==STATE_WARNING && host->rta_status==status)
1490 printf(" rta %0.3fms > %0.3fms", (float)host->rta / 1000, (float)warn.rta/1000);
1491 else if (status==STATE_CRITICAL && host->rta_status==status)
1492 printf(" rta %0.3fms > %0.3fms", (float)host->rta / 1000, (float)crit.rta/1000);
1493 }
1494 /* pl text output */
1495 if (pl_mode) {
1496 if (status == STATE_OK)
1497 printf(" lost %u%%", host->pl);
1498 else if (status==STATE_WARNING && host->pl_status==status)
1499 printf(" lost %u%% > %u%%", host->pl, warn.pl);
1500 else if (status==STATE_CRITICAL && host->pl_status==status)
1501 printf(" lost %u%% > %u%%", host->pl, crit.pl);
1502 }
1503 /* jitter text output */
1504 if (jitter_mode) {
1505 if (status == STATE_OK)
1506 printf(" jitter %0.3fms", (float)host->jitter);
1507 else if (status==STATE_WARNING && host->jitter_status==status)
1508 printf(" jitter %0.3fms > %0.3fms", (float)host->jitter, warn.jitter);
1509 else if (status==STATE_CRITICAL && host->jitter_status==status)
1510 printf(" jitter %0.3fms > %0.3fms", (float)host->jitter, crit.jitter);
1511 }
1512 /* mos text output */
1513 if (mos_mode) {
1514 if (status == STATE_OK)
1515 printf(" MOS %0.1f", (float)host->mos);
1516 else if (status==STATE_WARNING && host->mos_status==status)
1517 printf(" MOS %0.1f < %0.1f", (float)host->mos, (float)warn.mos);
1518 else if (status==STATE_CRITICAL && host->mos_status==status)
1519 printf(" MOS %0.1f < %0.1f", (float)host->mos, (float)crit.mos);
1520 }
1521 /* score text output */
1522 if (score_mode) {
1523 if (status == STATE_OK)
1524 printf(" Score %u", (int)host->score);
1525 else if (status==STATE_WARNING && host->score_status==status )
1526 printf(" Score %u < %u", (int)host->score, (int)warn.score);
1527 else if (status==STATE_CRITICAL && host->score_status==status )
1528 printf(" Score %u < %u", (int)host->score, (int)crit.score);
1529 }
1530 /* order statis text output */
1531 if (order_mode) {
1532 if (status == STATE_OK)
1533 printf(" Packets in order");
1534 else if (status==STATE_CRITICAL && host->order_status==status)
1535 printf(" Packets out of order");
1536 }
1537 }
1538 host = host->next;
1539 }
1540 1528
1541 /* iterate once more for pretty perfparse output */ 1529 mp_add_subcheck_to_check(overall, host_check.sc_host);
1542 if (!(!rta_mode && !pl_mode && !jitter_mode && !score_mode && !mos_mode && order_mode)) {
1543 printf("|");
1544 } 1530 }
1545 i = 0;
1546 host = list;
1547 while(host) {
1548 if(debug) puts("");
1549
1550 if (rta_mode) {
1551 if (host->pl<100) {
1552 printf("%srta=%0.3fms;%0.3f;%0.3f;0; %srtmax=%0.3fms;;;; %srtmin=%0.3fms;;;; ",
1553 (targets > 1) ? host->name : "",
1554 host->rta / 1000, (float)warn.rta / 1000, (float)crit.rta / 1000,
1555 (targets > 1) ? host->name : "", (float)host->rtmax / 1000,
1556 (targets > 1) ? host->name : "", (host->rtmin < INFINITY) ? (float)host->rtmin / 1000 : (float)0);
1557 } else {
1558 printf("%srta=U;;;; %srtmax=U;;;; %srtmin=U;;;; ",
1559 (targets > 1) ? host->name : "",
1560 (targets > 1) ? host->name : "",
1561 (targets > 1) ? host->name : "");
1562 }
1563 }
1564 1531
1565 if (pl_mode) { 1532 if (min_hosts_alive > -1) {
1566 printf("%spl=%u%%;%u;%u;0;100 ", (targets > 1) ? host->name : "", host->pl, warn.pl, crit.pl); 1533 mp_subcheck sc_min_targets_alive = mp_subcheck_init();
1567 } 1534 sc_min_targets_alive = mp_set_subcheck_default_state(sc_min_targets_alive, STATE_OK);
1568
1569 if (jitter_mode) {
1570 if (host->pl<100) {
1571 printf("%sjitter_avg=%0.3fms;%0.3f;%0.3f;0; %sjitter_max=%0.3fms;;;; %sjitter_min=%0.3fms;;;; ",
1572 (targets > 1) ? host->name : "",
1573 (float)host->jitter,
1574 (float)warn.jitter,
1575 (float)crit.jitter,
1576 (targets > 1) ? host->name : "",
1577 (float)host->jitter_max / 1000, (targets > 1) ? host->name : "",
1578 (float)host->jitter_min / 1000
1579 );
1580 } else {
1581 printf("%sjitter_avg=U;;;; %sjitter_max=U;;;; %sjitter_min=U;;;; ",
1582 (targets > 1) ? host->name : "",
1583 (targets > 1) ? host->name : "",
1584 (targets > 1) ? host->name : "");
1585 }
1586 }
1587 1535
1588 if (mos_mode) { 1536 if (targets_ok >= min_hosts_alive) {
1589 if (host->pl<100) { 1537 sc_min_targets_alive = mp_set_subcheck_state(sc_min_targets_alive, STATE_OK);
1590 printf("%smos=%0.1f;%0.1f;%0.1f;0;5 ", 1538 xasprintf(&sc_min_targets_alive.output, "%u targets OK of a minimum of %u", targets_ok,
1591 (targets > 1) ? host->name : "", 1539 min_hosts_alive);
1592 (float)host->mos,
1593 (float)warn.mos,
1594 (float)crit.mos);
1595 } else {
1596 printf("%smos=U;;;; ", (targets > 1) ? host->name : "");
1597 }
1598 }
1599 1540
1600 if (score_mode) { 1541 // Overwrite main state here
1601 if (host->pl<100) { 1542 overall->evaluation_function = &mp_eval_ok;
1602 printf("%sscore=%u;%u;%u;0;100 ", 1543 } else if ((targets_ok + targets_warn) >= min_hosts_alive) {
1603 (targets > 1) ? host->name : "", 1544 sc_min_targets_alive = mp_set_subcheck_state(sc_min_targets_alive, STATE_WARNING);
1604 (int)host->score, 1545 xasprintf(&sc_min_targets_alive.output, "%u targets OK or Warning of a minimum of %u",
1605 (int)warn.score, 1546 targets_ok + targets_warn, min_hosts_alive);
1606 (int)crit.score); 1547 overall->evaluation_function = &mp_eval_warning;
1607 } else { 1548 } else {
1608 printf("%sscore=U;;;; ", (targets > 1) ? host->name : ""); 1549 sc_min_targets_alive = mp_set_subcheck_state(sc_min_targets_alive, STATE_CRITICAL);
1609 } 1550 xasprintf(&sc_min_targets_alive.output, "%u targets OK or Warning of a minimum of %u",
1551 targets_ok + targets_warn, min_hosts_alive);
1552 overall->evaluation_function = &mp_eval_critical;
1610 } 1553 }
1611 1554
1612 host = host->next; 1555 mp_add_subcheck_to_check(overall, sc_min_targets_alive);
1613 }
1614
1615 if(min_hosts_alive > -1) {
1616 if(hosts_ok >= min_hosts_alive) status = STATE_OK;
1617 else if((hosts_ok + hosts_warn) >= min_hosts_alive) status = STATE_WARNING;
1618 } 1556 }
1619 1557
1620 /* finish with an empty line */ 1558 /* finish with an empty line */
1621 puts(""); 1559 if (debug) {
1622 if(debug) printf("targets: %u, targets_alive: %u, hosts_ok: %u, hosts_warn: %u, min_hosts_alive: %i\n", 1560 printf(
1623 targets, targets_alive, hosts_ok, hosts_warn, min_hosts_alive); 1561 "targets: %u, targets_alive: %u, hosts_ok: %u, hosts_warn: %u, min_hosts_alive: %i\n",
1624 1562 number_of_targets, targets_alive(number_of_targets, program_state->targets_down),
1625 exit(status); 1563 targets_ok, targets_warn, min_hosts_alive);
1626}
1627
1628static u_int
1629get_timevaldiff(struct timeval *early, struct timeval *later)
1630{
1631 u_int ret;
1632 struct timeval now;
1633
1634 if(!later) {
1635 gettimeofday(&now, &tz);
1636 later = &now;
1637 } 1564 }
1638 if(!early) early = &prog_start; 1565}
1639 1566
1567static time_t get_timevaldiff(const struct timeval earlier, const struct timeval later) {
1640 /* if early > later we return 0 so as to indicate a timeout */ 1568 /* if early > later we return 0 so as to indicate a timeout */
1641 if(early->tv_sec > later->tv_sec || 1569 if (earlier.tv_sec > later.tv_sec ||
1642 (early->tv_sec == later->tv_sec && early->tv_usec > later->tv_usec)) 1570 (earlier.tv_sec == later.tv_sec && earlier.tv_usec > later.tv_usec)) {
1643 {
1644 return 0; 1571 return 0;
1645 } 1572 }
1646 ret = (later->tv_sec - early->tv_sec) * 1000000; 1573
1647 ret += later->tv_usec - early->tv_usec; 1574 time_t ret = (later.tv_sec - earlier.tv_sec) * 1000000;
1575 ret += later.tv_usec - earlier.tv_usec;
1648 1576
1649 return ret; 1577 return ret;
1650} 1578}
1651 1579
1652static int 1580static time_t get_timevaldiff_to_now(struct timeval earlier) {
1653add_target_ip(char *arg, struct sockaddr_storage *in) 1581 struct timeval now;
1654{ 1582 gettimeofday(&now, NULL);
1655 struct rta_host *host;
1656 struct sockaddr_in *sin, *host_sin;
1657 struct sockaddr_in6 *sin6, *host_sin6;
1658 1583
1659 if (address_family == AF_INET) 1584 return get_timevaldiff(earlier, now);
1660 sin = (struct sockaddr_in *)in; 1585}
1661 else
1662 sin6 = (struct sockaddr_in6 *)in;
1663 1586
1587static add_target_ip_wrapper add_target_ip(struct sockaddr_storage address) {
1588 assert((address.ss_family == AF_INET) || (address.ss_family == AF_INET6));
1589
1590 if (debug) {
1591 char straddr[INET6_ADDRSTRLEN];
1592 parse_address((&address), straddr, sizeof(straddr));
1593 printf("add_target_ip called with: %s\n", straddr);
1594 }
1595 struct sockaddr_in *sin;
1596 struct sockaddr_in6 *sin6;
1597 if (address.ss_family == AF_INET) {
1598 sin = (struct sockaddr_in *)&address;
1599 } else if (address.ss_family == AF_INET6) {
1600 sin6 = (struct sockaddr_in6 *)&address;
1601 } else {
1602 assert(false);
1603 }
1664 1604
1605 add_target_ip_wrapper result = {
1606 .error_code = OK,
1607 .target = NULL,
1608 };
1665 1609
1666 /* disregard obviously stupid addresses 1610 /* disregard obviously stupid addresses
1667 * (I didn't find an ipv6 equivalent to INADDR_NONE) */ 1611 * (I didn't find an ipv6 equivalent to INADDR_NONE) */
1668 if (((address_family == AF_INET && (sin->sin_addr.s_addr == INADDR_NONE 1612 if (((address.ss_family == AF_INET &&
1669 || sin->sin_addr.s_addr == INADDR_ANY))) 1613 (sin->sin_addr.s_addr == INADDR_NONE || sin->sin_addr.s_addr == INADDR_ANY))) ||
1670 || (address_family == AF_INET6 && (sin6->sin6_addr.s6_addr == in6addr_any.s6_addr))) { 1614 (address.ss_family == AF_INET6 && (sin6->sin6_addr.s6_addr == in6addr_any.s6_addr))) {
1671 return -1; 1615 result.error_code = ERROR;
1616 return result;
1672 } 1617 }
1673 1618
1674 /* no point in adding two identical IP's, so don't. ;) */ 1619 // get string representation of address
1675 host = list; 1620 char straddr[INET6_ADDRSTRLEN];
1676 while(host) { 1621 parse_address((&address), straddr, sizeof(straddr));
1677 host_sin = (struct sockaddr_in *)&host->saddr_in;
1678 host_sin6 = (struct sockaddr_in6 *)&host->saddr_in;
1679
1680 if( (address_family == AF_INET && host_sin->sin_addr.s_addr == sin->sin_addr.s_addr)
1681 || (address_family == AF_INET6 && host_sin6->sin6_addr.s6_addr == sin6->sin6_addr.s6_addr)) {
1682 if(debug) printf("Identical IP already exists. Not adding %s\n", arg);
1683 return -1;
1684 }
1685 host = host->next;
1686 }
1687 1622
1688 /* add the fresh ip */ 1623 /* add the fresh ip */
1689 host = (struct rta_host*)malloc(sizeof(struct rta_host)); 1624 ping_target *target = (ping_target *)calloc(1, sizeof(ping_target));
1690 if(!host) { 1625 if (!target) {
1691 char straddr[INET6_ADDRSTRLEN]; 1626 crash("add_target_ip(%s): malloc(%lu) failed", straddr, sizeof(ping_target));
1692 parse_address((struct sockaddr_storage*)&in, straddr, sizeof(straddr));
1693 crash("add_target_ip(%s, %s): malloc(%lu) failed",
1694 arg, straddr, sizeof(struct rta_host));
1695 } 1627 }
1696 memset(host, 0, sizeof(struct rta_host));
1697
1698 /* set the values. use calling name for output */
1699 host->name = strdup(arg);
1700 1628
1629 ping_target_create_wrapper target_wrapper = ping_target_create(address);
1701 1630
1702 /* fill out the sockaddr_storage struct */ 1631 if (target_wrapper.errorcode == OK) {
1703 if(address_family == AF_INET) { 1632 *target = target_wrapper.host;
1704 host_sin = (struct sockaddr_in *)&host->saddr_in; 1633 result.target = target;
1705 host_sin->sin_family = AF_INET; 1634 } else {
1706 host_sin->sin_addr.s_addr = sin->sin_addr.s_addr; 1635 result.error_code = target_wrapper.errorcode;
1707 } 1636 }
1708 else {
1709 host_sin6 = (struct sockaddr_in6 *)&host->saddr_in;
1710 host_sin6->sin6_family = AF_INET6;
1711 memcpy(host_sin6->sin6_addr.s6_addr, sin6->sin6_addr.s6_addr, sizeof host_sin6->sin6_addr.s6_addr);
1712 }
1713
1714 /* fill out the sockaddr_in struct */
1715 host->rtmin = INFINITY;
1716 host->rtmax = 0;
1717 host->jitter=0;
1718 host->jitter_max=0;
1719 host->jitter_min=INFINITY;
1720 host->last_tdiff=0;
1721 host->order_status=STATE_OK;
1722 host->last_icmp_seq=0;
1723 host->rta_status=0;
1724 host->pl_status=0;
1725 host->jitter_status=0;
1726 host->mos_status=0;
1727 host->score_status=0;
1728 host->pl_status=0;
1729
1730
1731 if(!list) list = cursor = host;
1732 else cursor->next = host;
1733
1734 cursor = host;
1735 targets++;
1736 1637
1737 return 0; 1638 return result;
1738} 1639}
1739 1640
1740/* wrapper for add_target_ip */ 1641/* wrapper for add_target_ip */
1741static int 1642static add_target_wrapper add_target(char *arg, const check_icmp_execution_mode mode,
1742add_target(char *arg) 1643 sa_family_t enforced_proto) {
1743{ 1644 if (debug > 0) {
1744 int error, result = -1; 1645 printf("add_target called with argument %s\n", arg);
1745 struct sockaddr_storage ip; 1646 }
1746 struct addrinfo hints, *res, *p; 1647
1747 struct sockaddr_in *sin; 1648 struct sockaddr_storage address_storage = {};
1748 struct sockaddr_in6 *sin6; 1649 struct sockaddr_in *sin = NULL;
1749 1650 struct sockaddr_in6 *sin6 = NULL;
1750 switch (address_family) { 1651 int error_code = -1;
1751 case -1: 1652
1752 /* -4 and -6 are not specified on cmdline */ 1653 switch (enforced_proto) {
1753 address_family = AF_INET; 1654 case AF_UNSPEC:
1754 sin = (struct sockaddr_in *)&ip; 1655 /*
1755 result = inet_pton(address_family, arg, &sin->sin_addr); 1656 * no enforced protocol family
1756#ifdef USE_IPV6 1657 * try to parse the address with each one
1757 if( result != 1 ){ 1658 */
1758 address_family = AF_INET6; 1659 sin = (struct sockaddr_in *)&address_storage;
1759 sin6 = (struct sockaddr_in6 *)&ip; 1660 error_code = inet_pton(AF_INET, arg, &sin->sin_addr);
1760 result = inet_pton(address_family, arg, &sin6->sin6_addr); 1661 address_storage.ss_family = AF_INET;
1761 } 1662
1762#endif 1663 if (error_code != 1) {
1763 /* If we don't find any valid addresses, we still don't know the address_family */ 1664 sin6 = (struct sockaddr_in6 *)&address_storage;
1764 if ( result != 1) { 1665 error_code = inet_pton(AF_INET6, arg, &sin6->sin6_addr);
1765 address_family = -1; 1666 address_storage.ss_family = AF_INET6;
1766 } 1667 }
1767 break; 1668 break;
1768 case AF_INET: 1669 case AF_INET:
1769 sin = (struct sockaddr_in *)&ip; 1670 sin = (struct sockaddr_in *)&address_storage;
1770 result = inet_pton(address_family, arg, &sin->sin_addr); 1671 error_code = inet_pton(AF_INET, arg, &sin->sin_addr);
1672 address_storage.ss_family = AF_INET;
1771 break; 1673 break;
1772 case AF_INET6: 1674 case AF_INET6:
1773 sin6 = (struct sockaddr_in6 *)&ip; 1675 sin6 = (struct sockaddr_in6 *)&address_storage;
1774 result = inet_pton(address_family, arg, &sin6->sin6_addr); 1676 error_code = inet_pton(AF_INET, arg, &sin6->sin6_addr);
1677 address_storage.ss_family = AF_INET6;
1775 break; 1678 break;
1776 default: crash("Address family not supported"); 1679 default:
1680 crash("Address family not supported");
1777 } 1681 }
1778 1682
1779 /* don't resolve if we don't have to */ 1683 add_target_wrapper result = {
1780 if(result == 1) { 1684 .error_code = OK,
1685 .targets = NULL,
1686 .has_v4 = false,
1687 .has_v6 = false,
1688 };
1689
1690 // if error_code == 1 the address was a valid address parsed above
1691 if (error_code == 1) {
1781 /* don't add all ip's if we were given a specific one */ 1692 /* don't add all ip's if we were given a specific one */
1782 return add_target_ip(arg, &ip); 1693 add_target_ip_wrapper targeted = add_target_ip(address_storage);
1783 } 1694
1784 else { 1695 if (targeted.error_code != OK) {
1785 errno = 0; 1696 result.error_code = ERROR;
1786 memset(&hints, 0, sizeof(hints)); 1697 return result;
1787 if (address_family == -1) {
1788 hints.ai_family = AF_UNSPEC;
1789 } else {
1790 hints.ai_family = address_family == AF_INET ? PF_INET : PF_INET6;
1791 } 1698 }
1792 hints.ai_socktype = SOCK_RAW; 1699
1793 if((error = getaddrinfo(arg, NULL, &hints, &res)) != 0) { 1700 if (targeted.target->address.ss_family == AF_INET) {
1794 errno = 0; 1701 result.has_v4 = true;
1795 crash("Failed to resolve %s: %s", arg, gai_strerror(error)); 1702 } else if (targeted.target->address.ss_family == AF_INET6) {
1796 return -1; 1703 result.has_v6 = true;
1704 } else {
1705 assert(false);
1797 } 1706 }
1798 address_family = res->ai_family; 1707 result.targets = targeted.target;
1708 result.number_of_targets = 1;
1709 return result;
1710 }
1711
1712 struct addrinfo hints = {};
1713 errno = 0;
1714 hints.ai_family = enforced_proto;
1715 hints.ai_socktype = SOCK_RAW;
1716
1717 int error;
1718 struct addrinfo *res;
1719 if ((error = getaddrinfo(arg, NULL, &hints, &res)) != 0) {
1720 errno = 0;
1721 crash("Failed to resolve %s: %s", arg, gai_strerror(error));
1722 result.error_code = ERROR;
1723 return result;
1799 } 1724 }
1800 1725
1801 /* possibly add all the IP's as targets */ 1726 /* possibly add all the IP's as targets */
1802 for(p = res; p != NULL; p = p->ai_next) { 1727 for (struct addrinfo *address = res; address != NULL; address = address->ai_next) {
1803 memcpy(&ip, p->ai_addr, p->ai_addrlen); 1728 struct sockaddr_storage temporary_ip_address;
1804 add_target_ip(arg, &ip); 1729 memcpy(&temporary_ip_address, address->ai_addr, address->ai_addrlen);
1730
1731 add_target_ip_wrapper tmp = add_target_ip(temporary_ip_address);
1732
1733 if (tmp.error_code != OK) {
1734 // No proper error handling
1735 // What to do?
1736 } else {
1737 if (result.targets == NULL) {
1738 result.targets = tmp.target;
1739 result.number_of_targets = 1;
1740 } else {
1741 result.number_of_targets += ping_target_list_append(result.targets, tmp.target);
1742 }
1743 if (address->ai_family == AF_INET) {
1744 result.has_v4 = true;
1745 } else if (address->ai_family == AF_INET6) {
1746 result.has_v6 = true;
1747 }
1748 }
1805 1749
1806 /* this is silly, but it works */ 1750 /* this is silly, but it works */
1807 if(mode == MODE_HOSTCHECK || mode == MODE_ALL) { 1751 if (mode == MODE_HOSTCHECK || mode == MODE_ALL) {
1808 if(debug > 2) printf("mode: %d\n", mode); 1752 if (debug > 2) {
1753 printf("mode: %d\n", mode);
1754 }
1809 continue; 1755 continue;
1810 } 1756 }
1757
1758 // Abort after first hit if not in of the modes above
1811 break; 1759 break;
1812 } 1760 }
1813 freeaddrinfo(res); 1761 freeaddrinfo(res);
1814 1762
1815 return 0; 1763 return result;
1816} 1764}
1817 1765
1818static void 1766static void set_source_ip(char *arg, const int icmp_sock, sa_family_t addr_family) {
1819set_source_ip(char *arg)
1820{
1821 struct sockaddr_in src; 1767 struct sockaddr_in src;
1822 1768
1823 memset(&src, 0, sizeof(src)); 1769 memset(&src, 0, sizeof(src));
1824 src.sin_family = address_family; 1770 src.sin_family = addr_family;
1825 if((src.sin_addr.s_addr = inet_addr(arg)) == INADDR_NONE) 1771 if ((src.sin_addr.s_addr = inet_addr(arg)) == INADDR_NONE) {
1826 src.sin_addr.s_addr = get_ip_address(arg); 1772 src.sin_addr.s_addr = get_ip_address(arg);
1827 if(bind(icmp_sock, (struct sockaddr *)&src, sizeof(src)) == -1) 1773 }
1774 if (bind(icmp_sock, (struct sockaddr *)&src, sizeof(src)) == -1) {
1828 crash("Cannot bind to IP address %s", arg); 1775 crash("Cannot bind to IP address %s", arg);
1776 }
1829} 1777}
1830 1778
1831/* TODO: Move this to netutils.c and also change check_dhcp to use that. */ 1779/* TODO: Move this to netutils.c and also change check_dhcp to use that. */
1832static in_addr_t 1780static in_addr_t get_ip_address(const char *ifname) {
1833get_ip_address(const char *ifname) 1781 // TODO: Rewrite this so the function return an error and we exit somewhere else
1834{ 1782 struct sockaddr_in ip_address;
1835 // TODO: Rewrite this so the function return an error and we exit somewhere else 1783 ip_address.sin_addr.s_addr = 0; // Fake initialization to make compiler happy
1836 struct sockaddr_in ip;
1837 ip.sin_addr.s_addr = 0; // Fake initialization to make compiler happy
1838#if defined(SIOCGIFADDR) 1784#if defined(SIOCGIFADDR)
1839 struct ifreq ifr; 1785 struct ifreq ifr;
1840 1786
@@ -1842,16 +1788,17 @@ get_ip_address(const char *ifname)
1842 1788
1843 ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0'; 1789 ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
1844 1790
1845 if(ioctl(icmp_sock, SIOCGIFADDR, &ifr) == -1) 1791 if (ioctl(icmp_sock, SIOCGIFADDR, &ifr) == -1) {
1846 crash("Cannot determine IP address of interface %s", ifname); 1792 crash("Cannot determine IP address of interface %s", ifname);
1793 }
1847 1794
1848 memcpy(&ip, &ifr.ifr_addr, sizeof(ip)); 1795 memcpy(&ip, &ifr.ifr_addr, sizeof(ip));
1849#else 1796#else
1850 (void) ifname; 1797 (void)ifname;
1851 errno = 0; 1798 errno = 0;
1852 crash("Cannot get interface IP address on this platform."); 1799 crash("Cannot get interface IP address on this platform.");
1853#endif 1800#endif
1854 return ip.sin_addr.s_addr; 1801 return ip_address.sin_addr.s_addr;
1855} 1802}
1856 1803
1857/* 1804/*
@@ -1860,76 +1807,127 @@ get_ip_address(const char *ifname)
1860 * s = seconds 1807 * s = seconds
1861 * return value is in microseconds 1808 * return value is in microseconds
1862 */ 1809 */
1863static u_int 1810static get_timevar_wrapper get_timevar(const char *str) {
1864get_timevar(const char *str) 1811 get_timevar_wrapper result = {
1865{ 1812 .error_code = OK,
1866 char p, u, *ptr; 1813 .time_range = 0,
1867 size_t len; 1814 };
1868 u_int i, d; /* integer and decimal, respectively */ 1815
1869 u_int factor = 1000; /* default to milliseconds */ 1816 if (!str) {
1870 1817 result.error_code = ERROR;
1871 if(!str) return 0; 1818 return result;
1872 len = strlen(str); 1819 }
1873 if(!len) return 0; 1820
1821 size_t len = strlen(str);
1822 if (!len) {
1823 result.error_code = ERROR;
1824 return result;
1825 }
1874 1826
1875 /* unit might be given as ms|m (millisec), 1827 /* unit might be given as ms|m (millisec),
1876 * us|u (microsec) or just plain s, for seconds */ 1828 * us|u (microsec) or just plain s, for seconds */
1877 p = '\0'; 1829 char tmp = '\0';
1878 u = str[len - 1]; 1830 char unit = str[len - 1];
1879 if(len >= 2 && !isdigit((int)str[len - 2])) p = str[len - 2]; 1831 if (len >= 2 && !isdigit((int)str[len - 2])) {
1880 if(p && u == 's') u = p; 1832 tmp = str[len - 2];
1881 else if(!p) p = u; 1833 }
1882 if(debug > 2) printf("evaluating %s, u: %c, p: %c\n", str, u, p); 1834
1883 1835 if (tmp && unit == 's') {
1884 if(u == 'u') factor = 1; /* microseconds */ 1836 unit = tmp;
1885 else if(u == 'm') factor = 1000; /* milliseconds */ 1837 } else if (!tmp) {
1886 else if(u == 's') factor = 1000000; /* seconds */ 1838 tmp = unit;
1887 if(debug > 2) printf("factor is %u\n", factor); 1839 }
1888 1840
1889 i = strtoul(str, &ptr, 0); 1841 if (debug > 2) {
1890 if(!ptr || *ptr != '.' || strlen(ptr) < 2 || factor == 1) 1842 printf("evaluating %s, u: %c, p: %c\n", str, unit, tmp);
1891 return i * factor; 1843 }
1844
1845 unsigned int factor = 1000; /* default to milliseconds */
1846 if (unit == 'u') {
1847 factor = 1; /* microseconds */
1848 } else if (unit == 'm') {
1849 factor = 1000; /* milliseconds */
1850 } else if (unit == 's') {
1851 factor = 1000000; /* seconds */
1852 }
1853
1854 if (debug > 2) {
1855 printf("factor is %u\n", factor);
1856 }
1857
1858 char *ptr;
1859 unsigned long pre_radix;
1860 pre_radix = strtoul(str, &ptr, 0);
1861 if (!ptr || *ptr != '.' || strlen(ptr) < 2 || factor == 1) {
1862 result.time_range = (unsigned int)(pre_radix * factor);
1863 return result;
1864 }
1892 1865
1893 /* time specified in usecs can't have decimal points, so ignore them */ 1866 /* time specified in usecs can't have decimal points, so ignore them */
1894 if(factor == 1) return i; 1867 if (factor == 1) {
1868 result.time_range = (unsigned int)pre_radix;
1869 return result;
1870 }
1895 1871
1896 d = strtoul(ptr + 1, NULL, 0); 1872 /* integer and decimal, respectively */
1873 unsigned int post_radix = (unsigned int)strtoul(ptr + 1, NULL, 0);
1897 1874
1898 /* d is decimal, so get rid of excess digits */ 1875 /* d is decimal, so get rid of excess digits */
1899 while(d >= factor) d /= 10; 1876 while (post_radix >= factor) {
1877 post_radix /= 10;
1878 }
1900 1879
1901 /* the last parenthesis avoids floating point exceptions. */ 1880 /* the last parenthesis avoids floating point exceptions. */
1902 return ((i * factor) + (d * (factor / 10))); 1881 result.time_range = (unsigned int)((pre_radix * factor) + (post_radix * (factor / 10)));
1882 return result;
1903} 1883}
1904 1884
1905/* not too good at checking errors, but it'll do (main() should barfe on -1) */ 1885static get_threshold_wrapper get_threshold(char *str, check_icmp_threshold threshold) {
1906static int 1886 get_threshold_wrapper result = {
1907get_threshold(char *str, threshold *th) 1887 .errorcode = OK,
1908{ 1888 .threshold = threshold,
1909 char *p = NULL, i = 0; 1889 };
1910 1890
1911 if(!str || !strlen(str) || !th) return -1; 1891 if (!str || !strlen(str)) {
1892 result.errorcode = ERROR;
1893 return result;
1894 }
1912 1895
1913 /* pointer magic slims code by 10 lines. i is bof-stop on stupid libc's */ 1896 /* pointer magic slims code by 10 lines. i is bof-stop on stupid libc's */
1914 p = &str[strlen(str) - 1]; 1897 bool is_at_last_char = false;
1915 while(p != &str[1]) { 1898 char *tmp = &str[strlen(str) - 1];
1916 if(*p == '%') *p = '\0'; 1899 while (tmp != &str[1]) {
1917 else if(*p == ',' && i) { 1900 if (*tmp == '%') {
1918 *p = '\0'; /* reset it so get_timevar(str) works nicely later */ 1901 *tmp = '\0';
1919 th->pl = (unsigned char)strtoul(p+1, NULL, 0); 1902 } else if (*tmp == ',' && is_at_last_char) {
1903 *tmp = '\0'; /* reset it so get_timevar(str) works nicely later */
1904 result.threshold.pl = (unsigned char)strtoul(tmp + 1, NULL, 0);
1920 break; 1905 break;
1921 } 1906 }
1922 i = 1; 1907 is_at_last_char = true;
1923 p--; 1908 tmp--;
1924 } 1909 }
1925 th->rta = get_timevar(str);
1926 1910
1927 if(!th->rta) return -1; 1911 get_timevar_wrapper parsed_time = get_timevar(str);
1928 1912
1929 if(th->rta > MAXTTL * 1000000) th->rta = MAXTTL * 1000000; 1913 if (parsed_time.error_code == OK) {
1930 if(th->pl > 100) th->pl = 100; 1914 result.threshold.rta = parsed_time.time_range;
1915 } else {
1916 if (debug > 1) {
1917 printf("%s: failed to parse rta threshold\n", __FUNCTION__);
1918 }
1919 result.errorcode = ERROR;
1920 return result;
1921 }
1931 1922
1932 return 0; 1923 if (result.threshold.rta > MAXTTL * 1000000) {
1924 result.threshold.rta = MAXTTL * 1000000;
1925 }
1926 if (result.threshold.pl > 100) {
1927 result.threshold.pl = 100;
1928 }
1929
1930 return result;
1933} 1931}
1934 1932
1935/* 1933/*
@@ -1940,190 +1938,537 @@ get_threshold(char *str, threshold *th)
1940 * @param[in] length strlen(str) 1938 * @param[in] length strlen(str)
1941 * @param[out] warn Pointer to the warn threshold struct to which the values should be assigned 1939 * @param[out] warn Pointer to the warn threshold struct to which the values should be assigned
1942 * @param[out] crit Pointer to the crit threshold struct to which the values should be assigned 1940 * @param[out] crit Pointer to the crit threshold struct to which the values should be assigned
1943 * @param[in] mode Determines whether this a threshold for rta, packet_loss, jitter, mos or score (exclusively) 1941 * @param[in] mode Determines whether this a threshold for rta, packet_loss, jitter, mos or score
1942 * (exclusively)
1944 */ 1943 */
1945static bool get_threshold2(char *str, size_t length, threshold *warn, threshold *crit, threshold_mode mode) { 1944static get_threshold2_wrapper get_threshold2(char *str, size_t length, check_icmp_threshold warn,
1946 if (!str || !length || !warn || !crit) return false; 1945 check_icmp_threshold crit, threshold_mode mode) {
1946 get_threshold2_wrapper result = {
1947 .errorcode = OK,
1948 .warn = warn,
1949 .crit = crit,
1950 };
1947 1951
1952 if (!str || !length) {
1953 result.errorcode = ERROR;
1954 return result;
1955 }
1948 1956
1949 // p points to the last char in str 1957 // p points to the last char in str
1950 char *p = &str[length - 1]; 1958 char *work_pointer = &str[length - 1];
1951 1959
1952 // first_iteration is bof-stop on stupid libc's 1960 // first_iteration is bof-stop on stupid libc's
1953 bool first_iteration = true; 1961 bool first_iteration = true;
1954 1962
1955 while(p != &str[0]) { 1963 while (work_pointer != &str[0]) {
1956 if( (*p == 'm') || (*p == '%') ) { 1964 if ((*work_pointer == 'm') || (*work_pointer == '%')) {
1957 *p = '\0'; 1965 *work_pointer = '\0';
1958 } else if(*p == ',' && !first_iteration) { 1966 } else if (*work_pointer == ',' && !first_iteration) {
1959 *p = '\0'; /* reset it so get_timevar(str) works nicely later */ 1967 *work_pointer = '\0'; /* reset it so get_timevar(str) works nicely later */
1960 1968
1961 char *start_of_value = p + 1; 1969 char *start_of_value = work_pointer + 1;
1962 1970
1963 if (!parse_threshold2_helper(start_of_value, strlen(start_of_value), crit, mode)){ 1971 parse_threshold2_helper_wrapper tmp =
1964 return false; 1972 parse_threshold2_helper(start_of_value, strlen(start_of_value), result.crit, mode);
1973 if (tmp.errorcode != OK) {
1974 result.errorcode = ERROR;
1975 return result;
1965 } 1976 }
1966 1977 result.crit = tmp.result;
1967 } 1978 }
1968 first_iteration = false; 1979 first_iteration = false;
1969 p--; 1980 work_pointer--;
1970 } 1981 }
1971 1982
1972 return parse_threshold2_helper(p, strlen(p), warn, mode); 1983 parse_threshold2_helper_wrapper tmp =
1984 parse_threshold2_helper(work_pointer, strlen(work_pointer), result.warn, mode);
1985 if (tmp.errorcode != OK) {
1986 result.errorcode = ERROR;
1987 } else {
1988 result.warn = tmp.result;
1989 }
1990 return result;
1973} 1991}
1974 1992
1975static bool parse_threshold2_helper(char *s, size_t length, threshold *thr, threshold_mode mode) { 1993static parse_threshold2_helper_wrapper parse_threshold2_helper(char *threshold_string,
1994 size_t length,
1995 check_icmp_threshold thr,
1996 threshold_mode mode) {
1976 char *resultChecker = {0}; 1997 char *resultChecker = {0};
1998 parse_threshold2_helper_wrapper result = {
1999 .result = thr,
2000 .errorcode = OK,
2001 };
1977 2002
1978 switch (mode) { 2003 switch (mode) {
1979 case const_rta_mode: 2004 case const_rta_mode:
1980 thr->rta = strtod(s, &resultChecker) * 1000; 2005 result.result.rta = (unsigned int)(strtod(threshold_string, &resultChecker) * 1000);
1981 break; 2006 break;
1982 case const_packet_loss_mode: 2007 case const_packet_loss_mode:
1983 thr->pl = (unsigned char)strtoul(s, &resultChecker, 0); 2008 result.result.pl = (unsigned char)strtoul(threshold_string, &resultChecker, 0);
1984 break; 2009 break;
1985 case const_jitter_mode: 2010 case const_jitter_mode:
1986 thr->jitter = strtod(s, &resultChecker); 2011 result.result.jitter = strtod(threshold_string, &resultChecker);
1987 2012 break;
1988 break; 2013 case const_mos_mode:
1989 case const_mos_mode: 2014 result.result.mos = strtod(threshold_string, &resultChecker);
1990 thr->mos = strtod(s, &resultChecker); 2015 break;
1991 break; 2016 case const_score_mode:
1992 case const_score_mode: 2017 result.result.score = strtod(threshold_string, &resultChecker);
1993 thr->score = strtod(s, &resultChecker); 2018 break;
1994 break;
1995 } 2019 }
1996 2020
1997 if (resultChecker == s) { 2021 if (resultChecker == threshold_string) {
1998 // Failed to parse 2022 // Failed to parse
1999 return false; 2023 result.errorcode = ERROR;
2024 return result;
2000 } 2025 }
2001 2026
2002 if (resultChecker != (s + length)) { 2027 if (resultChecker != (threshold_string + length)) {
2003 // Trailing symbols 2028 // Trailing symbols
2004 return false; 2029 result.errorcode = ERROR;
2005 } 2030 }
2006 2031
2007 return true; 2032 return result;
2008} 2033}
2009 2034
2010unsigned short 2035unsigned short icmp_checksum(uint16_t *packet, size_t packet_size) {
2011icmp_checksum(uint16_t *p, size_t n)
2012{
2013 unsigned short cksum;
2014 long sum = 0; 2036 long sum = 0;
2015 2037
2016 /* sizeof(uint16_t) == 2 */ 2038 /* sizeof(uint16_t) == 2 */
2017 while(n >= 2) { 2039 while (packet_size >= 2) {
2018 sum += *(p++); 2040 sum += *(packet++);
2019 n -= 2; 2041 packet_size -= 2;
2020 } 2042 }
2021 2043
2022 /* mop up the occasional odd byte */ 2044 /* mop up the occasional odd byte */
2023 if(n == 1) sum += *((uint8_t *)p -1); 2045 if (packet_size == 1) {
2046 sum += *((uint8_t *)packet - 1);
2047 }
2024 2048
2025 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 2049 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
2026 sum += (sum >> 16); /* add carry */ 2050 sum += (sum >> 16); /* add carry */
2027 cksum = ~sum; /* ones-complement, trunc to 16 bits */ 2051 unsigned short cksum;
2052 cksum = (unsigned short)~sum; /* ones-complement, trunc to 16 bits */
2028 2053
2029 return cksum; 2054 return cksum;
2030} 2055}
2031 2056
2032void 2057void print_help(void) {
2033print_help(void) 2058 // print_revision (progname); /* FIXME: Why? */
2034{ 2059 printf("Copyright (c) 2005 Andreas Ericsson <ae@op5.se>\n");
2035 /*print_revision (progname);*/ /* FIXME: Why? */ 2060
2036 printf ("Copyright (c) 2005 Andreas Ericsson <ae@op5.se>\n"); 2061 printf(COPYRIGHT, copyright, email);
2037 2062
2038 printf (COPYRIGHT, copyright, email); 2063 print_usage();
2039 2064
2040 printf ("\n\n"); 2065 printf(UT_HELP_VRSN);
2041 2066 printf(UT_EXTRA_OPTS);
2042 print_usage (); 2067
2043 2068 printf(" -H, --Host=HOST\n");
2044 printf (UT_HELP_VRSN); 2069 printf(" %s\n",
2045 printf (UT_EXTRA_OPTS); 2070 _("specify a target, might be one of: resolveable name | IPv6 address | IPv4 address\n"
2046 2071 " (required, can be given multiple times)"));
2047 printf (" %s\n", "-H"); 2072 printf(" %s\n", "[-4|-6], [--ipv4-only|--ipv6-only]");
2048 printf (" %s\n", _("specify a target")); 2073 printf(" %s\n", _("Use IPv4 or IPv6 only to communicate with the targets"));
2049 printf (" %s\n", "[-4|-6]"); 2074 printf(" %s\n", "-w, --warning=WARN_VALUE");
2050 printf (" %s\n", _("Use IPv4 (default) or IPv6 to communicate with the targets")); 2075 printf(" %s", _("warning threshold (default "));
2051 printf (" %s\n", "-w"); 2076 printf("%0.3fms,%u%%)\n", (float)DEFAULT_WARN_RTA / 1000, DEFAULT_WARN_PL);
2052 printf (" %s", _("warning threshold (currently ")); 2077 printf(" %s\n", "-c, --critical=CRIT_VALUE");
2053 printf ("%0.3fms,%u%%)\n", (float)warn.rta / 1000, warn.pl); 2078 printf(" %s", _("critical threshold (default "));
2054 printf (" %s\n", "-c"); 2079 printf("%0.3fms,%u%%)\n", (float)DEFAULT_CRIT_RTA / 1000, DEFAULT_CRIT_PL);
2055 printf (" %s", _("critical threshold (currently ")); 2080
2056 printf ("%0.3fms,%u%%)\n", (float)crit.rta / 1000, crit.pl); 2081 printf(" %s\n", "-R, --rta-mode-thresholds=RTA_THRESHOLDS");
2057 2082 printf(" %s\n",
2058 printf (" %s\n", "-R"); 2083 _("RTA (round trip average) mode warning,critical, ex. 100ms,200ms unit in ms"));
2059 printf (" %s\n", _("RTA, round trip average, mode warning,critical, ex. 100ms,200ms unit in ms")); 2084 printf(" %s\n", "-P, --packet-loss-mode-thresholds=PACKET_LOSS_THRESHOLD");
2060 printf (" %s\n", "-P"); 2085 printf(" %s\n", _("packet loss mode, ex. 40%,50% , unit in %"));
2061 printf (" %s\n", _("packet loss mode, ex. 40%,50% , unit in %")); 2086 printf(" %s\n", "-J, --jitter-mode-thresholds=JITTER_MODE_THRESHOLD");
2062 printf (" %s\n", "-J"); 2087 printf(" %s\n", _("jitter mode warning,critical, ex. 40.000ms,50.000ms , unit in ms "));
2063 printf (" %s\n", _("jitter mode warning,critical, ex. 40.000ms,50.000ms , unit in ms ")); 2088 printf(" %s\n", "-M, --mos-mode-thresholds=MOS_MODE_THRESHOLD");
2064 printf (" %s\n", "-M"); 2089 printf(" %s\n", _("MOS mode, between 0 and 4.4 warning,critical, ex. 3.5,3.0"));
2065 printf (" %s\n", _("MOS mode, between 0 and 4.4 warning,critical, ex. 3.5,3.0")); 2090 printf(" %s\n", "-S, --score-mode-thresholds=SCORE_MODE_THRESHOLD");
2066 printf (" %s\n", "-S"); 2091 printf(" %s\n", _("score mode, max value 100 warning,critical, ex. 80,70 "));
2067 printf (" %s\n", _("score mode, max value 100 warning,critical, ex. 80,70 ")); 2092 printf(" %s\n", "-O, --out-of-order-packets");
2068 printf (" %s\n", "-O"); 2093 printf(
2069 printf (" %s\n", _("detect out of order ICMP packts ")); 2094 " %s\n",
2070 printf (" %s\n", "-H"); 2095 _("detect out of order ICMP packets, if such packets are found, the result is CRITICAL"));
2071 printf (" %s\n", _("specify a target")); 2096 printf(" %s\n", "[-n|-p], --number-of-packets=NUMBER_OF_PACKETS");
2072 printf (" %s\n", "-s"); 2097 printf(" %s", _("number of packets to send (default "));
2073 printf (" %s\n", _("specify a source IP address or device name")); 2098 printf("%u)\n", DEFAULT_NUMBER_OF_PACKETS);
2074 printf (" %s\n", "-n"); 2099
2075 printf (" %s", _("number of packets to send (currently ")); 2100 printf(" %s\n", "-i");
2076 printf ("%u)\n",packets); 2101 printf(" %s", _("[DEPRECATED] packet interval (default "));
2077 printf (" %s\n", "-p"); 2102 printf("%0.3fms)\n", (float)DEFAULT_PKT_INTERVAL / 1000);
2078 printf (" %s", _("number of packets to send (currently ")); 2103 printf(" %s", _("This option was never actually used and is just mentioned here for "
2079 printf ("%u)\n",packets); 2104 "historical purposes\n"));
2080 printf (" %s\n", "-i"); 2105
2081 printf (" %s", _("max packet interval (currently ")); 2106 printf(" %s\n", "-I, --target-interval=TARGET_INTERVAL");
2082 printf ("%0.3fms)\n",(float)pkt_interval / 1000); 2107 printf(" %s%0.3fms)\n The time interval to wait in between one target and the next\n",
2083 printf (" %s\n", "-I"); 2108 _("max target interval (default "), (float)DEFAULT_TARGET_INTERVAL / 1000);
2084 printf (" %s", _("max target interval (currently ")); 2109 printf(" %s\n", "-m, --minimal-host-alive=MIN_ALIVE");
2085 printf ("%0.3fms)\n", (float)target_interval / 1000); 2110 printf(" %s", _("number of alive hosts required for success. If less than MIN_ALIVE hosts "
2086 printf (" %s\n", "-m"); 2111 "are OK, but MIN_ALIVE hosts are WARNING or OK, WARNING, else CRITICAL"));
2087 printf (" %s",_("number of alive hosts required for success")); 2112 printf("\n");
2088 printf ("\n"); 2113 printf(" %s\n", "-l, --outgoing-ttl=OUTGOING_TTL");
2089 printf (" %s\n", "-l"); 2114 printf(" %s", _("TTL on outgoing packets (default "));
2090 printf (" %s", _("TTL on outgoing packets (currently ")); 2115 printf("%u)\n", DEFAULT_TTL);
2091 printf ("%u)\n", ttl); 2116 printf(" %s\n", "-b, --size=SIZE");
2092 printf (" %s\n", "-t"); 2117 printf(" %s\n", _("Number of icmp ping data bytes to send"));
2093 printf (" %s",_("timeout value (seconds, currently ")); 2118 printf(" %s %lu + %d)\n", _("Packet size will be SIZE + icmp header (default"),
2094 printf ("%u)\n", timeout); 2119 DEFAULT_PING_DATA_SIZE, ICMP_MINLEN);
2095 printf (" %s\n", "-b"); 2120 printf(" %s\n", "-v, --verbose");
2096 printf (" %s\n", _("Number of icmp data bytes to send")); 2121 printf(" %s\n", _("Verbosity, can be given multiple times (for debugging)"));
2097 printf (" %s %u + %d)\n", _("Packet size will be data bytes + icmp header (currently"),icmp_data_size, ICMP_MINLEN); 2122
2098 printf (" %s\n", "-v"); 2123 printf(UT_OUTPUT_FORMAT);
2099 printf (" %s\n", _("verbose")); 2124
2100 printf ("\n"); 2125 printf("\n");
2101 printf ("%s\n", _("Notes:")); 2126 printf("%s\n", _("Notes:"));
2102 printf (" %s\n", _("If none of R,P,J,M,S or O is specified, default behavior is -R -P")); 2127 printf(" %s\n", _("If none of R,P,J,M,S or O is specified, default behavior is -R -P"));
2103 printf (" %s\n", _("The -H switch is optional. Naming a host (or several) to check is not.")); 2128 printf(" %s\n", _("Naming a host (or several) to check is not."));
2104 printf ("\n"); 2129 printf("\n");
2105 printf (" %s\n", _("Threshold format for -w and -c is 200.25,60% for 200.25 msec RTA and 60%")); 2130 printf(" %s\n", _("Threshold format for -w and -c is 200.25,60% for 200.25 msec RTA and 60%"));
2106 printf (" %s\n", _("packet loss. The default values should work well for most users.")); 2131 printf(" %s\n", _("packet loss. The default values should work well for most users."));
2107 printf (" %s\n", _("You can specify different RTA factors using the standardized abbreviations")); 2132 printf(" %s\n",
2108 printf (" %s\n", _("us (microseconds), ms (milliseconds, default) or just plain s for seconds.")); 2133 _("You can specify different RTA factors using the standardized abbreviations"));
2109 /* -d not yet implemented */ 2134 printf(" %s\n",
2110 /* printf ("%s\n", _("Threshold format for -d is warn,crit. 12,14 means WARNING if >= 12 hops")); 2135 _("us (microseconds), ms (milliseconds, default) or just plain s for seconds."));
2111 printf ("%s\n", _("are spent and CRITICAL if >= 14 hops are spent.")); 2136
2112 printf ("%s\n\n", _("NOTE: Some systems decrease TTL when forming ICMP_ECHOREPLY, others do not."));*/ 2137 printf(UT_SUPPORT);
2113 printf ("\n"); 2138}
2114 printf (" %s\n", _("The -v switch can be specified several times for increased verbosity.")); 2139
2115 /* printf ("%s\n", _("Long options are currently unsupported.")); 2140void print_usage(void) {
2116 printf ("%s\n", _("Options marked with * require an argument")); 2141 printf("%s\n", _("Usage:"));
2117 */ 2142 printf(" %s [options] [-H host1 [-H host2 [-H hostN]]]\n", progname);
2118 2143}
2119 printf (UT_SUPPORT); 2144
2145static add_host_wrapper add_host(char *arg, check_icmp_execution_mode mode,
2146 sa_family_t enforced_proto) {
2147 if (debug) {
2148 printf("add_host called with argument %s\n", arg);
2149 }
2150
2151 add_host_wrapper result = {
2152 .error_code = OK,
2153 .host = check_icmp_target_container_init(),
2154 .has_v4 = false,
2155 .has_v6 = false,
2156 };
2157
2158 add_target_wrapper targets = add_target(arg, mode, enforced_proto);
2159
2160 if (targets.error_code != OK) {
2161 result.error_code = targets.error_code;
2162 return result;
2163 }
2164
2165 result.has_v4 = targets.has_v4;
2166 result.has_v6 = targets.has_v6;
2167
2168 result.host = check_icmp_target_container_init();
2169
2170 result.host.name = strdup(arg);
2171 result.host.target_list = targets.targets;
2172 result.host.number_of_targets = targets.number_of_targets;
2173
2174 return result;
2175}
2176
2177mp_subcheck evaluate_target(ping_target target, check_icmp_mode_switches modes,
2178 check_icmp_threshold warn, check_icmp_threshold crit) {
2179 /* if no new mode selected, use old schema */
2180 if (!modes.rta_mode && !modes.pl_mode && !modes.jitter_mode && !modes.score_mode &&
2181 !modes.mos_mode && !modes.order_mode) {
2182 modes.rta_mode = true;
2183 modes.pl_mode = true;
2184 }
2185
2186 mp_subcheck result = mp_subcheck_init();
2187 result = mp_set_subcheck_default_state(result, STATE_OK);
2188
2189 char address[INET6_ADDRSTRLEN];
2190 memset(address, 0, INET6_ADDRSTRLEN);
2191 parse_address(&target.address, address, sizeof(address));
2192
2193 xasprintf(&result.output, "%s", address);
2194
2195 double packet_loss;
2196 time_t rta;
2197 if (!target.icmp_recv) {
2198 /* rta 0 is of course not entirely correct, but will still show up
2199 * conspicuously as missing entries in perfparse and cacti */
2200 packet_loss = 100;
2201 rta = 0;
2202 result = mp_set_subcheck_state(result, STATE_CRITICAL);
2203 /* up the down counter if not already counted */
2204
2205 if (target.flags & FLAG_LOST_CAUSE) {
2206 xasprintf(&result.output, "%s: %s @ %s", result.output,
2207 get_icmp_error_msg(target.icmp_type, target.icmp_code), address);
2208 } else { /* not marked as lost cause, so we have no flags for it */
2209 xasprintf(&result.output, "%s", result.output);
2210 }
2211 } else {
2212 packet_loss =
2213 (unsigned char)((target.icmp_sent - target.icmp_recv) * 100) / target.icmp_sent;
2214 rta = target.time_waited / target.icmp_recv;
2215 }
2216
2217 double EffectiveLatency;
2218 double mos; /* Mean opinion score */
2219 double score; /* score */
2220
2221 if (target.icmp_recv > 1) {
2222 /*
2223 * This algorithm is probably pretty much blindly copied from
2224 * locations like this one:
2225 * https://www.slac.stanford.edu/comp/net/wan-mon/tutorial.html#mos It calculates a MOS
2226 * value (range of 1 to 5, where 1 is bad and 5 really good). According to some quick
2227 * research MOS originates from the Audio/Video transport network area. Whether it can
2228 * and should be computed from ICMP data, I can not say.
2229 *
2230 * Anyway the basic idea is to map a value "R" with a range of 0-100 to the MOS value
2231 *
2232 * MOS stands likely for Mean Opinion Score (
2233 * https://en.wikipedia.org/wiki/Mean_Opinion_Score )
2234 *
2235 * More links:
2236 * - https://confluence.slac.stanford.edu/display/IEPM/MOS
2237 */
2238 target.jitter = (target.jitter / (target.icmp_recv - 1) / 1000);
2239
2240 /*
2241 * Take the average round trip latency (in milliseconds), add
2242 * round trip jitter, but double the impact to latency
2243 * then add 10 for protocol latencies (in milliseconds).
2244 */
2245 EffectiveLatency = ((double)rta / 1000) + target.jitter * 2 + 10;
2246
2247 double R;
2248 if (EffectiveLatency < 160) {
2249 R = 93.2 - (EffectiveLatency / 40);
2250 } else {
2251 R = 93.2 - ((EffectiveLatency - 120) / 10);
2252 }
2253
2254 // Now, let us deduct 2.5 R values per percentage of packet loss (i.e. a
2255 // loss of 5% will be entered as 5).
2256 R = R - (packet_loss * 2.5);
2257
2258 if (R < 0) {
2259 R = 0;
2260 }
2261
2262 score = R;
2263 mos = 1 + ((0.035) * R) + ((.000007) * R * (R - 60) * (100 - R));
2264 } else {
2265 target.jitter = 0;
2266 target.jitter_min = 0;
2267 target.jitter_max = 0;
2268 mos = 0;
2269 }
2270
2271 /* Check which mode is on and do the warn / Crit stuff */
2272 if (modes.rta_mode) {
2273 mp_subcheck sc_rta = mp_subcheck_init();
2274 sc_rta = mp_set_subcheck_default_state(sc_rta, STATE_OK);
2275 xasprintf(&sc_rta.output, "rta %0.3fms", (double)rta / 1000);
2276
2277 if (rta >= crit.rta) {
2278 sc_rta = mp_set_subcheck_state(sc_rta, STATE_CRITICAL);
2279 xasprintf(&sc_rta.output, "%s >= %0.3fms", sc_rta.output, (double)crit.rta / 1000);
2280 } else if (rta >= warn.rta) {
2281 sc_rta = mp_set_subcheck_state(sc_rta, STATE_WARNING);
2282 xasprintf(&sc_rta.output, "%s >= %0.3fms", sc_rta.output, (double)warn.rta / 1000);
2283 }
2284
2285 if (packet_loss < 100) {
2286 mp_perfdata pd_rta = perfdata_init();
2287 xasprintf(&pd_rta.label, "%srta", address);
2288 pd_rta.uom = strdup("ms");
2289 pd_rta.value = mp_create_pd_value(rta / 1000);
2290 pd_rta.min = mp_create_pd_value(0);
2291
2292 pd_rta.warn = mp_range_set_end(pd_rta.warn, mp_create_pd_value(warn.rta));
2293 pd_rta.crit = mp_range_set_end(pd_rta.crit, mp_create_pd_value(crit.rta));
2294 mp_add_perfdata_to_subcheck(&sc_rta, pd_rta);
2295
2296 mp_perfdata pd_rt_min = perfdata_init();
2297 xasprintf(&pd_rt_min.label, "%srtmin", address);
2298 pd_rt_min.value = mp_create_pd_value(target.rtmin / 1000);
2299 pd_rt_min.uom = strdup("ms");
2300 mp_add_perfdata_to_subcheck(&sc_rta, pd_rt_min);
2301
2302 mp_perfdata pd_rt_max = perfdata_init();
2303 xasprintf(&pd_rt_max.label, "%srtmax", address);
2304 pd_rt_max.value = mp_create_pd_value(target.rtmax / 1000);
2305 pd_rt_max.uom = strdup("ms");
2306 mp_add_perfdata_to_subcheck(&sc_rta, pd_rt_max);
2307 }
2308
2309 mp_add_subcheck_to_subcheck(&result, sc_rta);
2310 }
2311
2312 if (modes.pl_mode) {
2313 mp_subcheck sc_pl = mp_subcheck_init();
2314 sc_pl = mp_set_subcheck_default_state(sc_pl, STATE_OK);
2315 xasprintf(&sc_pl.output, "packet loss %.1f%%", packet_loss);
2316
2317 if (packet_loss >= crit.pl) {
2318 sc_pl = mp_set_subcheck_state(sc_pl, STATE_CRITICAL);
2319 xasprintf(&sc_pl.output, "%s >= %u%%", sc_pl.output, crit.pl);
2320 } else if (packet_loss >= warn.pl) {
2321 sc_pl = mp_set_subcheck_state(sc_pl, STATE_WARNING);
2322 xasprintf(&sc_pl.output, "%s >= %u%%", sc_pl.output, warn.pl);
2323 }
2324
2325 mp_perfdata pd_pl = perfdata_init();
2326 xasprintf(&pd_pl.label, "%spl", address);
2327 pd_pl.uom = strdup("%");
2328
2329 pd_pl.warn = mp_range_set_end(pd_pl.warn, mp_create_pd_value(warn.pl));
2330 pd_pl.crit = mp_range_set_end(pd_pl.crit, mp_create_pd_value(crit.pl));
2331 pd_pl.value = mp_create_pd_value(packet_loss);
2332
2333 mp_add_perfdata_to_subcheck(&sc_pl, pd_pl);
2334
2335 mp_add_subcheck_to_subcheck(&result, sc_pl);
2336 }
2337
2338 if (modes.jitter_mode) {
2339 mp_subcheck sc_jitter = mp_subcheck_init();
2340 sc_jitter = mp_set_subcheck_default_state(sc_jitter, STATE_OK);
2341 xasprintf(&sc_jitter.output, "jitter %0.3fms", target.jitter);
2342
2343 if (target.jitter >= crit.jitter) {
2344 sc_jitter = mp_set_subcheck_state(sc_jitter, STATE_CRITICAL);
2345 xasprintf(&sc_jitter.output, "%s >= %0.3fms", sc_jitter.output, crit.jitter);
2346 } else if (target.jitter >= warn.jitter) {
2347 sc_jitter = mp_set_subcheck_state(sc_jitter, STATE_WARNING);
2348 xasprintf(&sc_jitter.output, "%s >= %0.3fms", sc_jitter.output, warn.jitter);
2349 }
2350
2351 if (packet_loss < 100) {
2352 mp_perfdata pd_jitter = perfdata_init();
2353 pd_jitter.uom = strdup("ms");
2354 xasprintf(&pd_jitter.label, "%sjitter_avg", address);
2355 pd_jitter.value = mp_create_pd_value(target.jitter);
2356 pd_jitter.warn = mp_range_set_end(pd_jitter.warn, mp_create_pd_value(warn.jitter));
2357 pd_jitter.crit = mp_range_set_end(pd_jitter.crit, mp_create_pd_value(crit.jitter));
2358 mp_add_perfdata_to_subcheck(&sc_jitter, pd_jitter);
2359
2360 mp_perfdata pd_jitter_min = perfdata_init();
2361 pd_jitter_min.uom = strdup("ms");
2362 xasprintf(&pd_jitter_min.label, "%sjitter_min", address);
2363 pd_jitter_min.value = mp_create_pd_value(target.jitter_min);
2364 mp_add_perfdata_to_subcheck(&sc_jitter, pd_jitter_min);
2365
2366 mp_perfdata pd_jitter_max = perfdata_init();
2367 pd_jitter_max.uom = strdup("ms");
2368 xasprintf(&pd_jitter_max.label, "%sjitter_max", address);
2369 pd_jitter_max.value = mp_create_pd_value(target.jitter_max);
2370 mp_add_perfdata_to_subcheck(&sc_jitter, pd_jitter_max);
2371 }
2372 mp_add_subcheck_to_subcheck(&result, sc_jitter);
2373 }
2374
2375 if (modes.mos_mode) {
2376 mp_subcheck sc_mos = mp_subcheck_init();
2377 sc_mos = mp_set_subcheck_default_state(sc_mos, STATE_OK);
2378 xasprintf(&sc_mos.output, "MOS %0.1f", mos);
2379
2380 if (mos <= crit.mos) {
2381 sc_mos = mp_set_subcheck_state(sc_mos, STATE_CRITICAL);
2382 xasprintf(&sc_mos.output, "%s <= %0.1f", sc_mos.output, crit.mos);
2383 } else if (mos <= warn.mos) {
2384 sc_mos = mp_set_subcheck_state(sc_mos, STATE_WARNING);
2385 xasprintf(&sc_mos.output, "%s <= %0.1f", sc_mos.output, warn.mos);
2386 }
2387
2388 if (packet_loss < 100) {
2389 mp_perfdata pd_mos = perfdata_init();
2390 xasprintf(&pd_mos.label, "%smos", address);
2391 pd_mos.value = mp_create_pd_value(mos);
2392 pd_mos.warn = mp_range_set_end(pd_mos.warn, mp_create_pd_value(warn.mos));
2393 pd_mos.crit = mp_range_set_end(pd_mos.crit, mp_create_pd_value(crit.mos));
2394 pd_mos.min = mp_create_pd_value(0); // MOS starts at 0
2395 pd_mos.max = mp_create_pd_value(5); // MOS max is 5, by definition
2396 mp_add_perfdata_to_subcheck(&sc_mos, pd_mos);
2397 }
2398 mp_add_subcheck_to_subcheck(&result, sc_mos);
2399 }
2400
2401 if (modes.score_mode) {
2402 mp_subcheck sc_score = mp_subcheck_init();
2403 sc_score = mp_set_subcheck_default_state(sc_score, STATE_OK);
2404 xasprintf(&sc_score.output, "Score %f", score);
2405
2406 if (score <= crit.score) {
2407 sc_score = mp_set_subcheck_state(sc_score, STATE_CRITICAL);
2408 xasprintf(&sc_score.output, "%s <= %f", sc_score.output, crit.score);
2409 } else if (score <= warn.score) {
2410 sc_score = mp_set_subcheck_state(sc_score, STATE_WARNING);
2411 xasprintf(&sc_score.output, "%s <= %f", sc_score.output, warn.score);
2412 }
2413
2414 if (packet_loss < 100) {
2415 mp_perfdata pd_score = perfdata_init();
2416 xasprintf(&pd_score.label, "%sscore", address);
2417 pd_score.value = mp_create_pd_value(score);
2418 pd_score.warn = mp_range_set_end(pd_score.warn, mp_create_pd_value(warn.score));
2419 pd_score.crit = mp_range_set_end(pd_score.crit, mp_create_pd_value(crit.score));
2420 pd_score.min = mp_create_pd_value(0);
2421 pd_score.max = mp_create_pd_value(100);
2422 mp_add_perfdata_to_subcheck(&sc_score, pd_score);
2423 }
2424
2425 mp_add_subcheck_to_subcheck(&result, sc_score);
2426 }
2427
2428 if (modes.order_mode) {
2429 mp_subcheck sc_order = mp_subcheck_init();
2430 sc_order = mp_set_subcheck_default_state(sc_order, STATE_OK);
2431
2432 if (target.found_out_of_order_packets) {
2433 mp_set_subcheck_state(sc_order, STATE_CRITICAL);
2434 xasprintf(&sc_order.output, "Packets out of order");
2435 } else {
2436 xasprintf(&sc_order.output, "Packets in order");
2437 }
2438
2439 mp_add_subcheck_to_subcheck(&result, sc_order);
2440 }
2441
2442 return result;
2120} 2443}
2121 2444
2445evaluate_host_wrapper evaluate_host(check_icmp_target_container host,
2446 check_icmp_mode_switches modes, check_icmp_threshold warn,
2447 check_icmp_threshold crit) {
2448 evaluate_host_wrapper result = {
2449 .targets_warn = 0,
2450 .targets_ok = 0,
2451 .sc_host = mp_subcheck_init(),
2452 };
2453 result.sc_host = mp_set_subcheck_default_state(result.sc_host, STATE_OK);
2454
2455 result.sc_host.output = strdup(host.name);
2456
2457 ping_target *target = host.target_list;
2458 for (unsigned int i = 0; i < host.number_of_targets; i++) {
2459 mp_subcheck sc_target = evaluate_target(*target, modes, warn, crit);
2122 2460
2461 mp_state_enum target_state = mp_compute_subcheck_state(sc_target);
2462
2463 if (target_state == STATE_WARNING) {
2464 result.targets_warn++;
2465 } else if (target_state == STATE_OK) {
2466 result.targets_ok++;
2467 }
2468 mp_add_subcheck_to_subcheck(&result.sc_host, sc_target);
2469
2470 target = target->next;
2471 }
2123 2472
2124void 2473 return result;
2125print_usage (void)
2126{
2127 printf ("%s\n", _("Usage:"));
2128 printf(" %s [options] [-H] host1 host2 hostN\n", progname);
2129} 2474}
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..d56fbd8b
--- /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 = OK,
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 = ERROR;
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..c348bef5
--- /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/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-scripts/check_ifstatus.pl b/plugins-scripts/check_ifstatus.pl
index 38b87fcc..f0b7c491 100755
--- a/plugins-scripts/check_ifstatus.pl
+++ b/plugins-scripts/check_ifstatus.pl
@@ -97,11 +97,12 @@ my $opt_V ;
97my $opt_u; 97my $opt_u;
98my $opt_n; 98my $opt_n;
99my $opt_x ; 99my $opt_x ;
100my $opt_d;
100my %excluded ; 101my %excluded ;
101my %unused_names ; 102my %unused_names ;
102my @unused_ports ; 103my @unused_ports ;
103my %session_opts; 104my %session_opts;
104 105my @exclude_descriptions;
105 106
106 107
107 108
@@ -134,6 +135,7 @@ if (!defined($session)) {
134} 135}
135 136
136 137
138push(@snmpoids,$snmpLocIfDescr);
137push(@snmpoids,$snmpIfOperStatus); 139push(@snmpoids,$snmpIfOperStatus);
138push(@snmpoids,$snmpIfAdminStatus); 140push(@snmpoids,$snmpIfAdminStatus);
139push(@snmpoids,$snmpIfDescr); 141push(@snmpoids,$snmpIfDescr);
@@ -180,18 +182,28 @@ foreach $key (keys %ifStatus) {
180 if ($ifStatus{$key}{$snmpIfAdminStatus} == 1 ) { 182 if ($ifStatus{$key}{$snmpIfAdminStatus} == 1 ) {
181 #check only if interface is not excluded 183 #check only if interface is not excluded
182 if (!defined $unused_names{$ifStatus{$key}{$snmpIfDescr}} ) { 184 if (!defined $unused_names{$ifStatus{$key}{$snmpIfDescr}} ) {
183 # check only if interface type is not listed in %excluded 185 #check only if interface is not excluded (by description)
184 if (!defined $excluded{$ifStatus{$key}{$snmpIfType}} ) { 186 #counter for matching descriptions
185 if ($ifStatus{$key}{$snmpIfOperStatus} == 1 ) { $ifup++ ; } 187 my $match_descr = 0;
186 if ($ifStatus{$key}{$snmpIfOperStatus} == 2 ) { 188 foreach my $description (@exclude_descriptions) {
187 $ifdown++ ; 189 if ($ifStatus{$key}{$snmpLocIfDescr} =~ /^$description/) { $match_descr = 1; }
188 if (defined $ifXTable) { 190 }
189 $ifmessage .= sprintf("%s: down -> %s<BR>\n", $ifStatus{$key}{$snmpIfName}, $ifStatus{$key}{$snmpIfAlias}); 191 if ($match_descr == 0) {
190 }else{ 192 # check only if interface type is not listed in %excluded
191 $ifmessage .= sprintf("%s: down <BR>\n",$ifStatus{$key}{$snmpIfDescr}); 193 if (!defined $excluded{$ifStatus{$key}{$snmpIfType}} ) {
192 } 194 if ($ifStatus{$key}{$snmpIfOperStatus} == 1 ) { $ifup++ ; }
195 if ($ifStatus{$key}{$snmpIfOperStatus} == 2 ) {
196 $ifdown++ ;
197 if (defined $ifXTable) {
198 $ifmessage .= sprintf("%s: down -> %s<BR>\n", $ifStatus{$key}{$snmpIfName}, $ifStatus{$key}{$snmpIfAlias});
199 }else{
200 $ifmessage .= sprintf("%s: down <BR>\n",$ifStatus{$key}{$snmpIfDescr});
201 }
202 }
203 if ($ifStatus{$key}{$snmpIfOperStatus} == 5 ) { $ifdormant++ ;}
204 } else {
205 $ifexclude++;
193 } 206 }
194 if ($ifStatus{$key}{$snmpIfOperStatus} == 5 ) { $ifdormant++ ;}
195 } else { 207 } else {
196 $ifexclude++; 208 $ifexclude++;
197 } 209 }
@@ -264,6 +276,9 @@ sub print_help() {
264 printf " the descriptive name. Do not use if you don't know what this is. \n"; 276 printf " the descriptive name. Do not use if you don't know what this is. \n";
265 printf " -x (--exclude) A comma separated list of ifType values that should be excluded \n"; 277 printf " -x (--exclude) A comma separated list of ifType values that should be excluded \n";
266 printf " from the report (default for an empty list is PPP(23).\n"; 278 printf " from the report (default for an empty list is PPP(23).\n";
279 printf " -d (--exclude_ports_by_description) A comma separated list of LocIfDescr values that should be excluded \n";
280 printf " from the report (default is an empty exclusion list). Done using regexp '/^arg/', ex:\n";
281 printf " '-d connect,test' will match with descriptions like 'testing phase' but not 'in testing'.\n";
267 printf " -n (--unused_ports_by_name) A comma separated list of ifDescr values that should be excluded \n"; 282 printf " -n (--unused_ports_by_name) A comma separated list of ifDescr values that should be excluded \n";
268 printf " from the report (default is an empty exclusion list).\n"; 283 printf " from the report (default is an empty exclusion list).\n";
269 printf " -u (--unused_ports) A comma separated list of ifIndex values that should be excluded \n"; 284 printf " -u (--unused_ports) A comma separated list of ifIndex values that should be excluded \n";
@@ -306,6 +321,7 @@ sub process_arguments() {
306 "I" => \$ifXTable, "ifmib" => \$ifXTable, 321 "I" => \$ifXTable, "ifmib" => \$ifXTable,
307 "x:s" => \$opt_x, "exclude:s" => \$opt_x, 322 "x:s" => \$opt_x, "exclude:s" => \$opt_x,
308 "u=s" => \$opt_u, "unused_ports=s" => \$opt_u, 323 "u=s" => \$opt_u, "unused_ports=s" => \$opt_u,
324 "d=s" => \$opt_d, "exclude_ports_by_description=s" => \$opt_d,
309 "n=s" => \$opt_n, "unused_ports_by_name=s" => \$opt_n, 325 "n=s" => \$opt_n, "unused_ports_by_name=s" => \$opt_n,
310 "M=i" => \$maxmsgsize, "maxmsgsize=i" => \$maxmsgsize, 326 "M=i" => \$maxmsgsize, "maxmsgsize=i" => \$maxmsgsize,
311 "t=i" => \$timeout, "timeout=i" => \$timeout, 327 "t=i" => \$timeout, "timeout=i" => \$timeout,
@@ -414,6 +430,11 @@ sub process_arguments() {
414 } 430 }
415 } 431 }
416 432
433 # Exclude interfaces by descriptions
434 if (defined $opt_d) {
435 @exclude_descriptions = split(/,/,$opt_d);
436 }
437
417 # Excluded interface descriptors 438 # Excluded interface descriptors
418 if (defined $opt_n) { 439 if (defined $opt_n) {
419 my @unused = split(/,/,$opt_n); 440 my @unused = split(/,/,$opt_n);
diff --git a/plugins-scripts/check_rpc.pl b/plugins-scripts/check_rpc.pl
index 8a56b9fc..0968982e 100755
--- a/plugins-scripts/check_rpc.pl
+++ b/plugins-scripts/check_rpc.pl
@@ -311,18 +311,18 @@ sub get_rpcinfo {
311 printf "$line " if $verbose; 311 printf "$line " if $verbose;
312 chomp $line; 312 chomp $line;
313 313
314 if ( $line =~ /program $prognum version ([0-9]*) ready and waiting/ ) { 314 if ( $line =~ /[Pp]rogram $prognum version ([0-9]*) ready and waiting/ ) {
315 $response .= " version $1"; 315 $response .= " version $1";
316 $state = 'OK' unless $state ne 'UNKNOWN'; 316 $state = 'OK' unless $state ne 'UNKNOWN';
317 print "1:$response \n" if $verbose; 317 print "1:$response \n" if $verbose;
318 } 318 }
319 319
320 if ( $line =~ /program $prognum version ([0-9]*) is not available/ ) { 320 if ( $line =~ /[Pp]rogram $prognum version ([0-9]*) is not available/ ) {
321 $response2 .= " version $1"; 321 $response2 .= " version $1";
322 $state = 'CRITICAL'; 322 $state = 'CRITICAL';
323 print "2:$response2 \n" if $verbose; 323 print "2:$response2 \n" if $verbose;
324 } 324 }
325 if ( $line =~ /program $prognum is not available/ ) { 325 if ( $line =~ /[Pp]rogram $prognum is not available/ ) {
326 $response3 = ""; 326 $response3 = "";
327 $response3 = "tcp" if $opt_t; 327 $response3 = "tcp" if $opt_t;
328 $response3 = "udp" if $opt_u; 328 $response3 = "udp" if $opt_u;
diff --git a/plugins-scripts/check_sensors.sh b/plugins-scripts/check_sensors.sh
index 866e0e0f..ba3581b1 100755..100644
--- a/plugins-scripts/check_sensors.sh
+++ b/plugins-scripts/check_sensors.sh
@@ -20,7 +20,6 @@ print_help() {
20 echo "This plugin checks hardware status using the lm_sensors package." 20 echo "This plugin checks hardware status using the lm_sensors package."
21 echo "" 21 echo ""
22 support 22 support
23 exit "$STATE_OK"
24} 23}
25 24
26case "$1" in 25case "$1" in
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 49086b7a..192a2549 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -27,7 +27,7 @@ MATHLIBS = @MATHLIBS@
27#AM_CFLAGS = -Wall 27#AM_CFLAGS = -Wall
28 28
29libexec_PROGRAMS = check_apt check_cluster check_disk check_dummy check_http check_load \ 29libexec_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_overcr check_ping \ 30 check_mrtg check_mrtgtraf check_ntp check_ntp_peer check_ping \
31 check_real check_smtp check_ssh check_tcp check_time check_ntp_time \ 31 check_real check_smtp check_ssh check_tcp check_time check_ntp_time \
32 check_ups check_users negate \ 32 check_ups check_users negate \
33 urlize @EXTRAS@ 33 urlize @EXTRAS@
@@ -38,19 +38,63 @@ check_tcp_programs = check_ftp check_imap check_nntp check_pop \
38EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \ 38EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \
39 check_swap check_fping check_ldap check_game check_dig \ 39 check_swap check_fping check_ldap check_game check_dig \
40 check_nagios check_by_ssh check_dns check_nt check_ide_smart \ 40 check_nagios check_by_ssh check_dns check_nt check_ide_smart \
41 check_procs check_mysql_query check_apt check_dbi check_curl 41 check_procs check_mysql_query check_apt check_dbi check_curl \
42 \
43 tests/test_check_swap \
44 tests/test_check_disk
42 45
43SUBDIRS = picohttpparser 46SUBDIRS = picohttpparser
44 47
45EXTRA_DIST = t tests 48np_test_scripts = tests/test_check_swap.t \
49 tests/test_check_disk.t
50
51EXTRA_DIST = t \
52 tests \
53 $(np_test_scripts) \
54 negate.d \
55 check_swap.d \
56 check_ldap.d \
57 check_hpjd.d \
58 check_game.d \
59 check_radius.d \
60 check_disk.d \
61 check_time.d \
62 check_load.d \
63 check_nagios.d \
64 check_dbi.d \
65 check_tcp.d \
66 check_real.d \
67 check_ssh.d \
68 check_nt.d \
69 check_dns.d \
70 check_mrtgtraf.d \
71 check_mysql_query.d \
72 check_mrtg.d \
73 check_ntp_peer.d \
74 check_apt.d \
75 check_pgsql.d \
76 check_procs.d \
77 check_ping.d \
78 check_by_ssh.d \
79 check_smtp.d \
80 check_mysql.d \
81 check_ntp_time.d \
82 check_dig.d \
83 check_cluster.d \
84 check_ups.d \
85 check_fping.d
46 86
47PLUGINHDRS = common.h 87PLUGINHDRS = common.h
48 88
49noinst_LIBRARIES = libnpcommon.a 89noinst_LIBRARIES = libnpcommon.a
90noinst_PROGRAMS = @EXTRA_PLUGIN_TESTS@
91# These two lines support "make check", but we use "make test"
92check_PROGRAMS = @EXTRA_PLUGIN_TESTS@
50 93
51libnpcommon_a_SOURCES = utils.c netutils.c sslutils.c runcmd.c \ 94libnpcommon_a_SOURCES = utils.c netutils.c sslutils.c runcmd.c \
52 popen.c utils.h netutils.h popen.h common.h runcmd.c runcmd.h 95 popen.c utils.h netutils.h popen.h common.h runcmd.c runcmd.h
53 96
97
54BASEOBJS = libnpcommon.a ../lib/libmonitoringplug.a ../gl/libgnu.a $(LIB_CRYPTO) 98BASEOBJS = libnpcommon.a ../lib/libmonitoringplug.a ../gl/libgnu.a $(LIB_CRYPTO)
55NETOBJS = $(BASEOBJS) $(EXTRA_NETOBLS) 99NETOBJS = $(BASEOBJS) $(EXTRA_NETOBLS)
56NETLIBS = $(NETOBJS) $(SOCKETLIBS) 100NETLIBS = $(NETOBJS) $(SOCKETLIBS)
@@ -58,7 +102,10 @@ SSLOBJS = $(BASEOBJS) $(NETLIBS) $(SSLLIBS) $(LIB_CRYPTO)
58 102
59TESTS_ENVIRONMENT = perl -I $(top_builddir) -I $(top_srcdir) 103TESTS_ENVIRONMENT = perl -I $(top_builddir) -I $(top_srcdir)
60 104
61TESTS = @PLUGIN_TEST@ 105tap_ldflags = -L$(top_srcdir)/tap
106
107TESTS = @PLUGIN_TEST@ @EXTRA_PLUGIN_TESTS@
108
62 109
63test: 110test:
64 perl -I $(top_builddir) -I $(top_srcdir) ../test.pl 111 perl -I $(top_builddir) -I $(top_srcdir) ../test.pl
@@ -77,6 +124,7 @@ check_curl_LDADD = $(NETLIBS) $(LIBCURLLIBS) $(SSLOBJS) $(URIPARSERLIBS) picohtt
77check_dbi_LDADD = $(NETLIBS) $(DBILIBS) 124check_dbi_LDADD = $(NETLIBS) $(DBILIBS)
78check_dig_LDADD = $(NETLIBS) 125check_dig_LDADD = $(NETLIBS)
79check_disk_LDADD = $(BASEOBJS) 126check_disk_LDADD = $(BASEOBJS)
127check_disk_SOURCES = check_disk.c check_disk.d/utils_disk.c
80check_dns_LDADD = $(NETLIBS) 128check_dns_LDADD = $(NETLIBS)
81check_dummy_LDADD = $(BASEOBJS) 129check_dummy_LDADD = $(BASEOBJS)
82check_fping_LDADD = $(NETLIBS) 130check_fping_LDADD = $(NETLIBS)
@@ -97,8 +145,6 @@ check_nagios_LDADD = $(BASEOBJS)
97check_nt_LDADD = $(NETLIBS) 145check_nt_LDADD = $(NETLIBS)
98check_ntp_LDADD = $(NETLIBS) $(MATHLIBS) 146check_ntp_LDADD = $(NETLIBS) $(MATHLIBS)
99check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS) 147check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS)
100check_nwstat_LDADD = $(NETLIBS)
101check_overcr_LDADD = $(NETLIBS)
102check_pgsql_LDADD = $(NETLIBS) $(PGLIBS) 148check_pgsql_LDADD = $(NETLIBS) $(PGLIBS)
103check_ping_LDADD = $(NETLIBS) 149check_ping_LDADD = $(NETLIBS)
104check_procs_LDADD = $(BASEOBJS) 150check_procs_LDADD = $(BASEOBJS)
@@ -107,6 +153,7 @@ check_real_LDADD = $(NETLIBS)
107check_snmp_LDADD = $(BASEOBJS) 153check_snmp_LDADD = $(BASEOBJS)
108check_smtp_LDADD = $(SSLOBJS) 154check_smtp_LDADD = $(SSLOBJS)
109check_ssh_LDADD = $(NETLIBS) 155check_ssh_LDADD = $(NETLIBS)
156check_swap_SOURCES = check_swap.c check_swap.d/swap.c
110check_swap_LDADD = $(MATHLIBS) $(BASEOBJS) 157check_swap_LDADD = $(MATHLIBS) $(BASEOBJS)
111check_tcp_LDADD = $(SSLOBJS) 158check_tcp_LDADD = $(SSLOBJS)
112check_time_LDADD = $(NETLIBS) 159check_time_LDADD = $(NETLIBS)
@@ -122,6 +169,11 @@ if !HAVE_UTMPX
122check_users_LDADD += popen.o 169check_users_LDADD += popen.o
123endif 170endif
124 171
172tests_test_check_swap_LDADD = $(BASEOBJS) $(tap_ldflags) -ltap
173tests_test_check_swap_SOURCES = tests/test_check_swap.c check_swap.d/swap.c
174tests_test_check_disk_LDADD = $(BASEOBJS) $(tap_ldflags) check_disk.d/utils_disk.c -ltap
175tests_test_check_disk_SOURCES = tests/test_check_disk.c
176
125############################################################################## 177##############################################################################
126# secondary dependencies 178# secondary dependencies
127 179
diff --git a/plugins/check_apt.c b/plugins/check_apt.c
index 5c0f6e28..e840184b 100644
--- a/plugins/check_apt.c
+++ b/plugins/check_apt.c
@@ -1,55 +1,54 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_apt plugin 3 * Monitoring check_apt plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2006-2008 Monitoring Plugins Development Team 6 * Copyright (c) 2006-2024 Monitoring Plugins Development Team
7* 7 *
8* Original author: Sean Finney 8 * Original author: Sean Finney
9* 9 *
10* Description: 10 * Description:
11* 11 *
12* This file contains the check_apt plugin 12 * This file contains the check_apt plugin
13* 13 *
14* Check for available updates in apt package management systems 14 * Check for available updates in apt package management systems
15* 15 *
16* 16 *
17* This program is free software: you can redistribute it and/or modify 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 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 19 * the Free Software Foundation, either version 3 of the License, or
20* (at your option) any later version. 20 * (at your option) any later version.
21* 21 *
22* This program is distributed in the hope that it will be useful, 22 * This program is distributed in the hope that it will be useful,
23* but WITHOUT ANY WARRANTY; without even the implied warranty of 23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25* GNU General Public License for more details. 25 * GNU General Public License for more details.
26* 26 *
27* You should have received a copy of the GNU General Public License 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/>. 28 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32#include "states.h"
32const char *progname = "check_apt"; 33const char *progname = "check_apt";
33const char *copyright = "2006-2008"; 34const char *copyright = "2006-2024";
34const char *email = "devel@monitoring-plugins.org"; 35const char *email = "devel@monitoring-plugins.org";
35 36
36#include "common.h" 37#include "common.h"
37#include "runcmd.h" 38#include "runcmd.h"
38#include "utils.h" 39#include "utils.h"
39#include "regex.h" 40#include "regex.h"
40 41#include "check_apt.d/config.h"
41/* some constants */
42typedef enum { UPGRADE, DIST_UPGRADE, NO_UPGRADE } upgrade_type;
43 42
44/* Character for hidden input file option (for testing). */ 43/* Character for hidden input file option (for testing). */
45#define INPUT_FILE_OPT CHAR_MAX+1 44#define INPUT_FILE_OPT CHAR_MAX + 1
46/* the default opts can be overridden via the cmdline */ 45/* the default opts can be overridden via the cmdline */
47#define UPGRADE_DEFAULT_OPTS "-o 'Debug::NoLocking=true' -s -qq" 46#define UPGRADE_DEFAULT_OPTS "-o 'Debug::NoLocking=true' -s -qq"
48#define UPDATE_DEFAULT_OPTS "-q" 47#define UPDATE_DEFAULT_OPTS "-q"
49/* until i commit the configure.in patch which gets this, i'll define 48/* until i commit the configure.in patch which gets this, i'll define
50 * it here as well */ 49 * it here as well */
51#ifndef PATH_TO_APTGET 50#ifndef PATH_TO_APTGET
52# define PATH_TO_APTGET "/usr/bin/apt-get" 51# define PATH_TO_APTGET "/usr/bin/apt-get"
53#endif /* PATH_TO_APTGET */ 52#endif /* PATH_TO_APTGET */
54/* String found at the beginning of the apt output lines we're interested in */ 53/* String found at the beginning of the apt output lines we're interested in */
55#define PKGINST_PREFIX "Inst " 54#define PKGINST_PREFIX "Inst "
@@ -57,97 +56,106 @@ typedef enum { UPGRADE, DIST_UPGRADE, NO_UPGRADE } upgrade_type;
57#define SECURITY_RE "^[^\\(]*\\(.* (Debian-Security:|Ubuntu:[^/]*/[^-]*-security)" 56#define SECURITY_RE "^[^\\(]*\\(.* (Debian-Security:|Ubuntu:[^/]*/[^-]*-security)"
58 57
59/* some standard functions */ 58/* some standard functions */
60int process_arguments(int, char **); 59typedef struct {
61void print_help(void); 60 int errorcode;
61 check_apt_config config;
62} check_apt_config_wrapper;
63static check_apt_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
64static void print_help(void);
62void print_usage(void); 65void print_usage(void);
63 66
64/* construct the appropriate apt-get cmdline */ 67/* construct the appropriate apt-get cmdline */
65char* construct_cmdline(upgrade_type u, const char *opts); 68static char *construct_cmdline(upgrade_type /*u*/, const char * /*opts*/);
66/* run an apt-get update */ 69/* run an apt-get update */
67int run_update(void); 70static int run_update(char * /*update_opts*/);
71
72typedef struct {
73 int errorcode;
74 int package_count;
75 int security_package_count;
76 char **packages_list;
77 char **secpackages_list;
78} run_upgrade_result;
79
68/* run an apt-get upgrade */ 80/* run an apt-get upgrade */
69int run_upgrade(int *pkgcount, int *secpkgcount, char ***pkglist, char ***secpkglist); 81run_upgrade_result run_upgrade(upgrade_type upgrade, const char *do_include, const char *do_exclude, const char *do_critical,
82 const char *upgrade_opts, const char *input_filename);
83
70/* add another clause to a regexp */ 84/* add another clause to a regexp */
71char* add_to_regexp(char *expr, const char *next); 85static char *add_to_regexp(char * /*expr*/, const char * /*next*/);
72/* extract package name from Inst line */ 86/* extract package name from Inst line */
73char* pkg_name(char *line); 87static char *pkg_name(char * /*line*/);
74/* string comparison function for qsort */ 88/* string comparison function for qsort */
75int cmpstringp(const void *p1, const void *p2); 89static int cmpstringp(const void * /*p1*/, const void * /*p2*/);
76 90
77/* configuration variables */ 91/* configuration variables */
78static int verbose = 0; /* -v */ 92static int verbose = 0; /* -v */
79static bool list = false; /* list packages available for upgrade */
80static bool do_update = false; /* whether to call apt-get update */
81static bool only_critical = false; /* whether to warn about non-critical updates */
82static upgrade_type upgrade = UPGRADE; /* which type of upgrade to do */
83static char *upgrade_opts = NULL; /* options to override defaults for upgrade */
84static char *update_opts = NULL; /* options to override defaults for update */
85static char *do_include = NULL; /* regexp to only include certain packages */
86static char *do_exclude = NULL; /* regexp to only exclude certain packages */
87static char *do_critical = NULL; /* regexp specifying critical packages */
88static char *input_filename = NULL; /* input filename for testing */
89/* number of packages available for upgrade to return WARNING status */
90static int packages_warning = 1;
91 93
92/* other global variables */ 94/* other global variables */
93static int stderr_warning = 0; /* if a cmd issued output on stderr */ 95static bool stderr_warning = false; /* if a cmd issued output on stderr */
94static int exec_warning = 0; /* if a cmd exited non-zero */ 96static bool exec_warning = false; /* if a cmd exited non-zero */
95
96int main (int argc, char **argv) {
97 int result=STATE_UNKNOWN, packages_available=0, sec_count=0;
98 char **packages_list=NULL, **secpackages_list=NULL;
99 97
98int main(int argc, char **argv) {
100 /* Parse extra opts if any */ 99 /* Parse extra opts if any */
101 argv=np_extra_opts(&argc, argv, progname); 100 argv = np_extra_opts(&argc, argv, progname);
102 101
103 if (process_arguments(argc, argv) == ERROR) 102 check_apt_config_wrapper tmp_config = process_arguments(argc, argv);
103
104 if (tmp_config.errorcode == ERROR) {
104 usage_va(_("Could not parse arguments")); 105 usage_va(_("Could not parse arguments"));
106 }
107
108 const check_apt_config config = tmp_config.config;
105 109
106 /* Set signal handling and alarm timeout */ 110 /* Set signal handling and alarm timeout */
107 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 111 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
108 usage_va(_("Cannot catch SIGALRM")); 112 usage_va(_("Cannot catch SIGALRM"));
109 } 113 }
110 114
111 /* handle timeouts gracefully... */ 115 /* handle timeouts gracefully... */
112 alarm (timeout_interval); 116 alarm(timeout_interval);
113 117
118 mp_state_enum result = STATE_UNKNOWN;
114 /* if they want to run apt-get update first... */ 119 /* if they want to run apt-get update first... */
115 if(do_update) result = run_update(); 120 if (config.do_update) {
121 result = run_update(config.update_opts);
122 }
116 123
117 /* apt-get upgrade */ 124 /* apt-get upgrade */
118 result = max_state(result, run_upgrade(&packages_available, &sec_count, &packages_list, &secpackages_list)); 125 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);
127
128 result = max_state(result, upgrad_res.errorcode);
129 int packages_available = upgrad_res.package_count;
130 int sec_count = upgrad_res.security_package_count;
131 char **packages_list = upgrad_res.packages_list;
132 char **secpackages_list = upgrad_res.secpackages_list;
119 133
120 if(sec_count > 0){ 134 if (sec_count > 0) {
121 result = max_state(result, STATE_CRITICAL); 135 result = max_state(result, STATE_CRITICAL);
122 } else if(packages_available >= packages_warning && only_critical == false){ 136 } else if (packages_available >= config.packages_warning && !config.only_critical) {
123 result = max_state(result, STATE_WARNING); 137 result = max_state(result, STATE_WARNING);
124 } else if(result > STATE_UNKNOWN){ 138 } else if (result > STATE_UNKNOWN) {
125 result = STATE_UNKNOWN; 139 result = STATE_UNKNOWN;
126 } 140 }
127 141
128 printf(_("APT %s: %d packages available for %s (%d critical updates). %s%s%s%s|available_upgrades=%d;;;0 critical_updates=%d;;;0\n"), 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"),
129 state_text(result), 143 state_text(result), packages_available, (config.upgrade == DIST_UPGRADE) ? "dist-upgrade" : "upgrade", sec_count,
130 packages_available, 144 (stderr_warning) ? " warnings detected" : "", (stderr_warning && exec_warning) ? "," : "",
131 (upgrade==DIST_UPGRADE)?"dist-upgrade":"upgrade", 145 (exec_warning) ? " errors detected" : "", (stderr_warning || exec_warning) ? "." : "", packages_available, sec_count);
132 sec_count, 146
133 (stderr_warning)?" warnings detected":"", 147 if (config.list) {
134 (stderr_warning && exec_warning)?",":"", 148 qsort(secpackages_list, sec_count, sizeof(char *), cmpstringp);
135 (exec_warning)?" errors detected":"", 149 qsort(packages_list, packages_available - sec_count, sizeof(char *), cmpstringp);
136 (stderr_warning||exec_warning)?".":"", 150
137 packages_available, 151 for (int i = 0; i < sec_count; i++) {
138 sec_count
139 );
140
141 if(list) {
142 qsort(secpackages_list, sec_count, sizeof(char*), cmpstringp);
143 qsort(packages_list, packages_available-sec_count, sizeof(char*), cmpstringp);
144
145 for(int i = 0; i < sec_count; i++)
146 printf("%s (security)\n", secpackages_list[i]); 152 printf("%s (security)\n", secpackages_list[i]);
153 }
147 154
148 if (only_critical == false) { 155 if (!config.only_critical) {
149 for(int i = 0; i < packages_available - sec_count; i++) 156 for (int i = 0; i < packages_available - sec_count; i++) {
150 printf("%s\n", packages_list[i]); 157 printf("%s\n", packages_list[i]);
158 }
151 } 159 }
152 } 160 }
153 161
@@ -155,34 +163,37 @@ int main (int argc, char **argv) {
155} 163}
156 164
157/* process command-line arguments */ 165/* process command-line arguments */
158int process_arguments (int argc, char **argv) { 166check_apt_config_wrapper process_arguments(int argc, char **argv) {
159 int c; 167 static struct option longopts[] = {{"version", no_argument, 0, 'V'},
160 168 {"help", no_argument, 0, 'h'},
161 static struct option longopts[] = { 169 {"verbose", no_argument, 0, 'v'},
162 {"version", no_argument, 0, 'V'}, 170 {"timeout", required_argument, 0, 't'},
163 {"help", no_argument, 0, 'h'}, 171 {"update", optional_argument, 0, 'u'},
164 {"verbose", no_argument, 0, 'v'}, 172 {"upgrade", optional_argument, 0, 'U'},
165 {"timeout", required_argument, 0, 't'}, 173 {"no-upgrade", no_argument, 0, 'n'},
166 {"update", optional_argument, 0, 'u'}, 174 {"dist-upgrade", optional_argument, 0, 'd'},
167 {"upgrade", optional_argument, 0, 'U'}, 175 {"list", no_argument, 0, 'l'},
168 {"no-upgrade", no_argument, 0, 'n'}, 176 {"include", required_argument, 0, 'i'},
169 {"dist-upgrade", optional_argument, 0, 'd'}, 177 {"exclude", required_argument, 0, 'e'},
170 {"list", no_argument, false, 'l'}, 178 {"critical", required_argument, 0, 'c'},
171 {"include", required_argument, 0, 'i'}, 179 {"only-critical", no_argument, 0, 'o'},
172 {"exclude", required_argument, 0, 'e'}, 180 {"input-file", required_argument, 0, INPUT_FILE_OPT},
173 {"critical", required_argument, 0, 'c'}, 181 {"packages-warning", required_argument, 0, 'w'},
174 {"only-critical", no_argument, 0, 'o'}, 182 {0, 0, 0, 0}};
175 {"input-file", required_argument, 0, INPUT_FILE_OPT}, 183
176 {"packages-warning", required_argument, 0, 'w'}, 184 check_apt_config_wrapper result = {
177 {0, 0, 0, 0} 185 .errorcode = OK,
186 .config = check_apt_config_init(),
178 }; 187 };
179 188
180 while(1) { 189 while (true) {
181 c = getopt_long(argc, argv, "hVvt:u::U::d::nli:e:c:ow:", longopts, NULL); 190 int option_char = getopt_long(argc, argv, "hVvt:u::U::d::nli:e:c:ow:", longopts, NULL);
182 191
183 if(c == -1 || c == EOF || c == 1) break; 192 if (option_char == -1 || option_char == EOF || option_char == 1) {
193 break;
194 }
184 195
185 switch(c) { 196 switch (option_char) {
186 case 'h': 197 case 'h':
187 print_help(); 198 print_help();
188 exit(STATE_UNKNOWN); 199 exit(STATE_UNKNOWN);
@@ -193,52 +204,58 @@ int process_arguments (int argc, char **argv) {
193 verbose++; 204 verbose++;
194 break; 205 break;
195 case 't': 206 case 't':
196 timeout_interval=atoi(optarg); 207 timeout_interval = atoi(optarg);
197 break; 208 break;
198 case 'd': 209 case 'd':
199 upgrade=DIST_UPGRADE; 210 result.config.upgrade = DIST_UPGRADE;
200 if(optarg!=NULL){ 211 if (optarg != NULL) {
201 upgrade_opts=strdup(optarg); 212 result.config.upgrade_opts = strdup(optarg);
202 if(upgrade_opts==NULL) die(STATE_UNKNOWN, "strdup failed"); 213 if (result.config.upgrade_opts == NULL) {
214 die(STATE_UNKNOWN, "strdup failed");
215 }
203 } 216 }
204 break; 217 break;
205 case 'U': 218 case 'U':
206 upgrade=UPGRADE; 219 result.config.upgrade = UPGRADE;
207 if(optarg!=NULL){ 220 if (optarg != NULL) {
208 upgrade_opts=strdup(optarg); 221 result.config.upgrade_opts = strdup(optarg);
209 if(upgrade_opts==NULL) die(STATE_UNKNOWN, "strdup failed"); 222 if (result.config.upgrade_opts == NULL) {
223 die(STATE_UNKNOWN, "strdup failed");
224 }
210 } 225 }
211 break; 226 break;
212 case 'n': 227 case 'n':
213 upgrade=NO_UPGRADE; 228 result.config.upgrade = NO_UPGRADE;
214 break; 229 break;
215 case 'u': 230 case 'u':
216 do_update=true; 231 result.config.do_update = true;
217 if(optarg!=NULL){ 232 if (optarg != NULL) {
218 update_opts=strdup(optarg); 233 result.config.update_opts = strdup(optarg);
219 if(update_opts==NULL) die(STATE_UNKNOWN, "strdup failed"); 234 if (result.config.update_opts == NULL) {
235 die(STATE_UNKNOWN, "strdup failed");
236 }
220 } 237 }
221 break; 238 break;
222 case 'l': 239 case 'l':
223 list=true; 240 result.config.list = true;
224 break; 241 break;
225 case 'i': 242 case 'i':
226 do_include=add_to_regexp(do_include, optarg); 243 result.config.do_include = add_to_regexp(result.config.do_include, optarg);
227 break; 244 break;
228 case 'e': 245 case 'e':
229 do_exclude=add_to_regexp(do_exclude, optarg); 246 result.config.do_exclude = add_to_regexp(result.config.do_exclude, optarg);
230 break; 247 break;
231 case 'c': 248 case 'c':
232 do_critical=add_to_regexp(do_critical, optarg); 249 result.config.do_critical = add_to_regexp(result.config.do_critical, optarg);
233 break; 250 break;
234 case 'o': 251 case 'o':
235 only_critical=true; 252 result.config.only_critical = true;
236 break; 253 break;
237 case INPUT_FILE_OPT: 254 case INPUT_FILE_OPT:
238 input_filename = optarg; 255 result.config.input_filename = optarg;
239 break; 256 break;
240 case 'w': 257 case 'w':
241 packages_warning = atoi(optarg); 258 result.config.packages_warning = atoi(optarg);
242 break; 259 break;
243 default: 260 default:
244 /* print short usage statement if args not parsable */ 261 /* print short usage statement if args not parsable */
@@ -246,71 +263,82 @@ int process_arguments (int argc, char **argv) {
246 } 263 }
247 } 264 }
248 265
249 return OK; 266 return result;
250} 267}
251 268
252
253/* run an apt-get upgrade */ 269/* run an apt-get upgrade */
254int run_upgrade(int *pkgcount, int *secpkgcount, char ***pkglist, char ***secpkglist){ 270run_upgrade_result run_upgrade(const upgrade_type upgrade, const char *do_include, const char *do_exclude, const char *do_critical,
255 int result=STATE_UNKNOWN, regres=0, pc=0, spc=0; 271 const char *upgrade_opts, const char *input_filename) {
256 struct output chld_out, chld_err; 272 regex_t ereg;
257 regex_t ireg, ereg, sreg;
258 char *cmdline=NULL, rerrbuf[64];
259
260 /* initialize ereg as it is possible it is printed while uninitialized */ 273 /* initialize ereg as it is possible it is printed while uninitialized */
261 memset(&ereg, '\0', sizeof(ereg.buffer)); 274 memset(&ereg, '\0', sizeof(ereg.buffer));
262 275
263 if(upgrade==NO_UPGRADE) return STATE_OK; 276 run_upgrade_result result = {
277 .errorcode = STATE_UNKNOWN,
278 };
279
280 if (upgrade == NO_UPGRADE) {
281 result.errorcode = STATE_OK;
282 return result;
283 }
264 284
285 int regres = 0;
286 regex_t ireg;
287 char rerrbuf[64];
265 /* compile the regexps */ 288 /* compile the regexps */
266 if (do_include != NULL) { 289 if (do_include != NULL) {
267 regres=regcomp(&ireg, do_include, REG_EXTENDED); 290 regres = regcomp(&ireg, do_include, REG_EXTENDED);
268 if (regres!=0) { 291 if (regres != 0) {
269 regerror(regres, &ireg, rerrbuf, 64); 292 regerror(regres, &ireg, rerrbuf, 64);
270 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf); 293 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf);
271 } 294 }
272 } 295 }
273 296
274 if(do_exclude!=NULL){ 297 if (do_exclude != NULL) {
275 regres=regcomp(&ereg, do_exclude, REG_EXTENDED); 298 regres = regcomp(&ereg, do_exclude, REG_EXTENDED);
276 if(regres!=0) { 299 if (regres != 0) {
277 regerror(regres, &ereg, rerrbuf, 64); 300 regerror(regres, &ereg, rerrbuf, 64);
278 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), 301 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf);
279 progname, rerrbuf);
280 } 302 }
281 } 303 }
282 304
305 regex_t sreg;
283 const char *crit_ptr = (do_critical != NULL) ? do_critical : SECURITY_RE; 306 const char *crit_ptr = (do_critical != NULL) ? do_critical : SECURITY_RE;
284 regres=regcomp(&sreg, crit_ptr, REG_EXTENDED); 307 regres = regcomp(&sreg, crit_ptr, REG_EXTENDED);
285 if(regres!=0) { 308 if (regres != 0) {
286 regerror(regres, &ereg, rerrbuf, 64); 309 regerror(regres, &ereg, rerrbuf, 64);
287 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), 310 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf);
288 progname, rerrbuf);
289 } 311 }
290 312
291 cmdline=construct_cmdline(upgrade, upgrade_opts); 313 struct output chld_out;
314 struct output chld_err;
315 char *cmdline = NULL;
316 cmdline = construct_cmdline(upgrade, upgrade_opts);
292 if (input_filename != NULL) { 317 if (input_filename != NULL) {
293 /* read input from a file for testing */ 318 /* read input from a file for testing */
294 result = cmd_file_read(input_filename, &chld_out, 0); 319 result.errorcode = cmd_file_read(input_filename, &chld_out, 0);
295 } else { 320 } else {
296 /* run the upgrade */ 321 /* run the upgrade */
297 result = np_runcmd(cmdline, &chld_out, &chld_err, 0); 322 result.errorcode = np_runcmd(cmdline, &chld_out, &chld_err, 0);
298 } 323 }
299 324
300 /* apt-get upgrade only changes exit status if there is an 325 /* apt-get upgrade only changes exit status if there is an
301 * internal error when run in dry-run mode. therefore we will 326 * internal error when run in dry-run mode. therefore we will
302 * treat such an error as UNKNOWN */ 327 * treat such an error as UNKNOWN */
303 if(result != 0){ 328 if (result.errorcode != STATE_OK) {
304 exec_warning=1; 329 exec_warning = 1;
305 result = STATE_UNKNOWN; 330 result.errorcode = STATE_UNKNOWN;
306 fprintf(stderr, _("'%s' exited with non-zero status.\n"), 331 fprintf(stderr, _("'%s' exited with non-zero status.\n"), cmdline);
307 cmdline);
308 } 332 }
309 333
310 *pkglist=malloc(sizeof(char *) * chld_out.lines); 334 char **pkglist = malloc(sizeof(char *) * chld_out.lines);
311 if(!pkglist) die(STATE_UNKNOWN, "malloc failed!\n"); 335 if (!pkglist) {
312 *secpkglist=malloc(sizeof(char *) * chld_out.lines); 336 die(STATE_UNKNOWN, "malloc failed!\n");
313 if(!secpkglist) die(STATE_UNKNOWN, "malloc failed!\n"); 337 }
338 char **secpkglist = malloc(sizeof(char *) * chld_out.lines);
339 if (!secpkglist) {
340 die(STATE_UNKNOWN, "malloc failed!\n");
341 }
314 342
315 /* parse the output, which should only consist of lines like 343 /* parse the output, which should only consist of lines like
316 * 344 *
@@ -321,82 +349,91 @@ int run_upgrade(int *pkgcount, int *secpkgcount, char ***pkglist, char ***secpkg
321 * we may need to switch to the --print-uris output format, 349 * we may need to switch to the --print-uris output format,
322 * in which case the logic here will slightly change. 350 * in which case the logic here will slightly change.
323 */ 351 */
324 for(size_t i = 0; i < chld_out.lines; i++) { 352 int package_counter = 0;
325 if(verbose){ 353 int security_package_counter = 0;
354 for (size_t i = 0; i < chld_out.lines; i++) {
355 if (verbose) {
326 printf("%s\n", chld_out.line[i]); 356 printf("%s\n", chld_out.line[i]);
327 } 357 }
328 /* if it is a package we care about */ 358 /* if it is a package we care about */
329 if (strncmp(PKGINST_PREFIX, chld_out.line[i], strlen(PKGINST_PREFIX)) == 0 && 359 if (strncmp(PKGINST_PREFIX, chld_out.line[i], strlen(PKGINST_PREFIX)) == 0 &&
330 (do_include == NULL || regexec(&ireg, chld_out.line[i], 0, NULL, 0) == 0)) { 360 (do_include == NULL || regexec(&ireg, chld_out.line[i], 0, NULL, 0) == 0)) {
331 /* if we're not excluding, or it's not in the 361 /* if we're not excluding, or it's not in the
332 * list of stuff to exclude */ 362 * list of stuff to exclude */
333 if(do_exclude==NULL || 363 if (do_exclude == NULL || regexec(&ereg, chld_out.line[i], 0, NULL, 0) != 0) {
334 regexec(&ereg, chld_out.line[i], 0, NULL, 0)!=0){ 364 package_counter++;
335 pc++; 365 if (regexec(&sreg, chld_out.line[i], 0, NULL, 0) == 0) {
336 if(regexec(&sreg, chld_out.line[i], 0, NULL, 0)==0){ 366 security_package_counter++;
337 spc++; 367 if (verbose) {
338 if(verbose) printf("*"); 368 printf("*");
339 (*secpkglist)[spc-1] = pkg_name(chld_out.line[i]); 369 }
370 (secpkglist)[security_package_counter - 1] = pkg_name(chld_out.line[i]);
340 } else { 371 } else {
341 (*pkglist)[pc-spc-1] = pkg_name(chld_out.line[i]); 372 (pkglist)[package_counter - security_package_counter - 1] = pkg_name(chld_out.line[i]);
342 } 373 }
343 if(verbose){ 374 if (verbose) {
344 printf("*%s\n", chld_out.line[i]); 375 printf("*%s\n", chld_out.line[i]);
345 } 376 }
346 } 377 }
347 } 378 }
348 } 379 }
349 *pkgcount=pc; 380 result.package_count = package_counter;
350 *secpkgcount=spc; 381 result.security_package_count = security_package_counter;
382 result.packages_list = pkglist;
383 result.secpackages_list = secpkglist;
351 384
352 /* If we get anything on stderr, at least set warning */ 385 /* If we get anything on stderr, at least set warning */
353 if (input_filename == NULL && chld_err.buflen) { 386 if (input_filename == NULL && chld_err.buflen) {
354 stderr_warning=1; 387 stderr_warning = true;
355 result = max_state(result, STATE_WARNING); 388 result.errorcode = max_state(result.errorcode, STATE_WARNING);
356 if(verbose){ 389 if (verbose) {
357 for(size_t i = 0; i < chld_err.lines; i++) { 390 for (size_t i = 0; i < chld_err.lines; i++) {
358 fprintf(stderr, "%s\n", chld_err.line[i]); 391 fprintf(stderr, "%s\n", chld_err.line[i]);
359 } 392 }
360 } 393 }
361 } 394 }
362 if (do_include != NULL) regfree(&ireg); 395 if (do_include != NULL) {
396 regfree(&ireg);
397 }
363 regfree(&sreg); 398 regfree(&sreg);
364 if(do_exclude!=NULL) regfree(&ereg); 399 if (do_exclude != NULL) {
400 regfree(&ereg);
401 }
365 free(cmdline); 402 free(cmdline);
366 return result; 403 return result;
367} 404}
368 405
369/* run an apt-get update (needs root) */ 406/* run an apt-get update (needs root) */
370int run_update(void){ 407int run_update(char *update_opts) {
371 int result=STATE_UNKNOWN; 408 int result = STATE_UNKNOWN;
372 struct output chld_out, chld_err;
373 char *cmdline; 409 char *cmdline;
374
375 /* run the update */ 410 /* run the update */
376 cmdline = construct_cmdline(NO_UPGRADE, update_opts); 411 cmdline = construct_cmdline(NO_UPGRADE, update_opts);
412
413 struct output chld_out;
414 struct output chld_err;
377 result = np_runcmd(cmdline, &chld_out, &chld_err, 0); 415 result = np_runcmd(cmdline, &chld_out, &chld_err, 0);
378 /* apt-get update changes exit status if it can't fetch packages. 416 /* apt-get update changes exit status if it can't fetch packages.
379 * since we were explicitly asked to do so, this is treated as 417 * since we were explicitly asked to do so, this is treated as
380 * a critical error. */ 418 * a critical error. */
381 if(result != 0){ 419 if (result != 0) {
382 exec_warning=1; 420 exec_warning = true;
383 result = STATE_CRITICAL; 421 result = STATE_CRITICAL;
384 fprintf(stderr, _("'%s' exited with non-zero status.\n"), 422 fprintf(stderr, _("'%s' exited with non-zero status.\n"), cmdline);
385 cmdline);
386 } 423 }
387 424
388 if(verbose){ 425 if (verbose) {
389 for(size_t i = 0; i < chld_out.lines; i++) { 426 for (size_t i = 0; i < chld_out.lines; i++) {
390 printf("%s\n", chld_out.line[i]); 427 printf("%s\n", chld_out.line[i]);
391 } 428 }
392 } 429 }
393 430
394 /* If we get anything on stderr, at least set warning */ 431 /* If we get anything on stderr, at least set warning */
395 if(chld_err.buflen){ 432 if (chld_err.buflen) {
396 stderr_warning=1; 433 stderr_warning = 1;
397 result = max_state(result, STATE_WARNING); 434 result = max_state(result, STATE_WARNING);
398 if(verbose){ 435 if (verbose) {
399 for(size_t i = 0; i < chld_err.lines; i++) { 436 for (size_t i = 0; i < chld_err.lines; i++) {
400 fprintf(stderr, "%s\n", chld_err.line[i]); 437 fprintf(stderr, "%s\n", chld_err.line[i]);
401 } 438 }
402 } 439 }
@@ -405,158 +442,168 @@ int run_update(void){
405 return result; 442 return result;
406} 443}
407 444
408char* pkg_name(char *line){ 445char *pkg_name(char *line) {
409 char *start=NULL, *space=NULL, *pkg=NULL; 446 char *start = line + strlen(PKGINST_PREFIX);
410 int len=0;
411 447
412 start = line + strlen(PKGINST_PREFIX); 448 size_t len = strlen(start);
413 len = strlen(start);
414 449
415 space = index(start, ' '); 450 char *space = index(start, ' ');
416 if(space!=NULL){ 451 if (space != NULL) {
417 len = space - start; 452 len = space - start;
418 } 453 }
419 454
420 pkg=malloc(sizeof(char)*(len+1)); 455 char *pkg = malloc(sizeof(char) * (len + 1));
421 if(!pkg) die(STATE_UNKNOWN, "malloc failed!\n"); 456 if (!pkg) {
457 die(STATE_UNKNOWN, "malloc failed!\n");
458 }
422 459
423 strncpy(pkg, start, len); 460 strncpy(pkg, start, len);
424 pkg[len]='\0'; 461 pkg[len] = '\0';
425 462
426 return pkg; 463 return pkg;
427} 464}
428 465
429int cmpstringp(const void *p1, const void *p2){ 466int cmpstringp(const void *left_string, const void *right_string) {
430 return strcmp(* (char * const *) p1, * (char * const *) p2); 467 return strcmp(*(char *const *)left_string, *(char *const *)right_string);
431} 468}
432 469
433char* add_to_regexp(char *expr, const char *next){ 470char *add_to_regexp(char *expr, const char *next) {
434 char *re=NULL; 471 char *regex_string = NULL;
435 472
436 if(expr==NULL){ 473 if (expr == NULL) {
437 re=malloc(sizeof(char)*(strlen("()")+strlen(next)+1)); 474 regex_string = malloc(sizeof(char) * (strlen("()") + strlen(next) + 1));
438 if(!re) die(STATE_UNKNOWN, "malloc failed!\n"); 475 if (!regex_string) {
439 sprintf(re, "(%s)", next); 476 die(STATE_UNKNOWN, "malloc failed!\n");
477 }
478 sprintf(regex_string, "(%s)", next);
440 } else { 479 } else {
441 /* resize it, adding an extra char for the new '|' separator */ 480 /* resize it, adding an extra char for the new '|' separator */
442 re=realloc(expr, sizeof(char)*(strlen(expr)+1+strlen(next)+1)); 481 regex_string = realloc(expr, sizeof(char) * (strlen(expr) + 1 + strlen(next) + 1));
443 if(!re) die(STATE_UNKNOWN, "realloc failed!\n"); 482 if (!regex_string) {
483 die(STATE_UNKNOWN, "realloc failed!\n");
484 }
444 /* append it starting at ')' in the old re */ 485 /* append it starting at ')' in the old re */
445 sprintf((char*)(re+strlen(re)-1), "|%s)", next); 486 sprintf((char *)(regex_string + strlen(regex_string) - 1), "|%s)", next);
446 } 487 }
447 488
448 return re; 489 return regex_string;
449} 490}
450 491
451char* construct_cmdline(upgrade_type u, const char *opts){ 492char *construct_cmdline(upgrade_type upgrade, const char *opts) {
452 int len=0; 493 const char *opts_ptr = NULL;
453 const char *opts_ptr=NULL, *aptcmd=NULL; 494 const char *aptcmd = NULL;
454 char *cmd=NULL;
455 495
456 switch(u){ 496 switch (upgrade) {
457 case UPGRADE: 497 case UPGRADE:
458 if(opts==NULL) opts_ptr=UPGRADE_DEFAULT_OPTS; 498 if (opts == NULL) {
459 else opts_ptr=opts; 499 opts_ptr = UPGRADE_DEFAULT_OPTS;
460 aptcmd="upgrade"; 500 } else {
501 opts_ptr = opts;
502 }
503 aptcmd = "upgrade";
461 break; 504 break;
462 case DIST_UPGRADE: 505 case DIST_UPGRADE:
463 if(opts==NULL) opts_ptr=UPGRADE_DEFAULT_OPTS; 506 if (opts == NULL) {
464 else opts_ptr=opts; 507 opts_ptr = UPGRADE_DEFAULT_OPTS;
465 aptcmd="dist-upgrade"; 508 } else {
509 opts_ptr = opts;
510 }
511 aptcmd = "dist-upgrade";
466 break; 512 break;
467 case NO_UPGRADE: 513 case NO_UPGRADE:
468 if(opts==NULL) opts_ptr=UPDATE_DEFAULT_OPTS; 514 if (opts == NULL) {
469 else opts_ptr=opts; 515 opts_ptr = UPDATE_DEFAULT_OPTS;
470 aptcmd="update"; 516 } else {
517 opts_ptr = opts;
518 }
519 aptcmd = "update";
471 break; 520 break;
472 } 521 }
473 522
474 len+=strlen(PATH_TO_APTGET)+1; /* "/usr/bin/apt-get " */ 523 int len = 0;
475 len+=strlen(opts_ptr)+1; /* "opts " */ 524 len += strlen(PATH_TO_APTGET) + 1; /* "/usr/bin/apt-get " */
476 len+=strlen(aptcmd)+1; /* "upgrade\0" */ 525 len += strlen(opts_ptr) + 1; /* "opts " */
526 len += strlen(aptcmd) + 1; /* "upgrade\0" */
477 527
478 cmd=(char*)malloc(sizeof(char)*len); 528 char *cmd = (char *)malloc(sizeof(char) * len);
479 if(cmd==NULL) die(STATE_UNKNOWN, "malloc failed"); 529 if (cmd == NULL) {
530 die(STATE_UNKNOWN, "malloc failed");
531 }
480 sprintf(cmd, "%s %s %s", PATH_TO_APTGET, opts_ptr, aptcmd); 532 sprintf(cmd, "%s %s %s", PATH_TO_APTGET, opts_ptr, aptcmd);
481 return cmd; 533 return cmd;
482} 534}
483 535
484/* informative help message */ 536/* informative help message */
485void 537void print_help(void) {
486print_help (void) 538 print_revision(progname, NP_VERSION);
487{ 539
488 print_revision(progname, NP_VERSION); 540 printf(_(COPYRIGHT), copyright, email);
489 541
490 printf(_(COPYRIGHT), copyright, email); 542 printf("%s\n", _("This plugin checks for software updates on systems that use"));
491 543 printf("%s\n", _("package management systems based on the apt-get(8) command"));
492 printf("%s\n", _("This plugin checks for software updates on systems that use")); 544 printf("%s\n", _("found in Debian GNU/Linux"));
493 printf("%s\n", _("package management systems based on the apt-get(8) command")); 545
494 printf("%s\n", _("found in Debian GNU/Linux")); 546 printf("\n\n");
495 547
496 printf ("\n\n"); 548 print_usage();
497 549
498 print_usage(); 550 printf(UT_HELP_VRSN);
499 551 printf(UT_EXTRA_OPTS);
500 printf(UT_HELP_VRSN); 552
501 printf(UT_EXTRA_OPTS); 553 printf(UT_PLUG_TIMEOUT, timeout_interval);
502 554
503 printf(UT_PLUG_TIMEOUT, timeout_interval); 555 printf(" %s\n", "-n, --no-upgrade");
504 556 printf(" %s\n", _("Do not run the upgrade. Probably not useful (without -u at least)."));
505 printf (" %s\n", "-n, --no-upgrade"); 557 printf(" %s\n", "-l, --list");
506 printf (" %s\n", _("Do not run the upgrade. Probably not useful (without -u at least).")); 558 printf(" %s\n", _("List packages available for upgrade. Packages are printed sorted by"));
507 printf (" %s\n", "-l, --list"); 559 printf(" %s\n", _("name with security packages listed first."));
508 printf (" %s\n", _("List packages available for upgrade. Packages are printed sorted by")); 560 printf(" %s\n", "-i, --include=REGEXP");
509 printf (" %s\n", _("name with security packages listed first.")); 561 printf(" %s\n", _("Include only packages matching REGEXP. Can be specified multiple times"));
510 printf (" %s\n", "-i, --include=REGEXP"); 562 printf(" %s\n", _("the values will be combined together. Any packages matching this list"));
511 printf (" %s\n", _("Include only packages matching REGEXP. Can be specified multiple times")); 563 printf(" %s\n", _("cause the plugin to return WARNING status. Others will be ignored."));
512 printf (" %s\n", _("the values will be combined together. Any packages matching this list")); 564 printf(" %s\n", _("Default is to include all packages."));
513 printf (" %s\n", _("cause the plugin to return WARNING status. Others will be ignored.")); 565 printf(" %s\n", "-e, --exclude=REGEXP");
514 printf (" %s\n", _("Default is to include all packages.")); 566 printf(" %s\n", _("Exclude packages matching REGEXP from the list of packages that would"));
515 printf (" %s\n", "-e, --exclude=REGEXP"); 567 printf(" %s\n", _("otherwise be included. Can be specified multiple times; the values"));
516 printf (" %s\n", _("Exclude packages matching REGEXP from the list of packages that would")); 568 printf(" %s\n", _("will be combined together. Default is to exclude no packages."));
517 printf (" %s\n", _("otherwise be included. Can be specified multiple times; the values")); 569 printf(" %s\n", "-c, --critical=REGEXP");
518 printf (" %s\n", _("will be combined together. Default is to exclude no packages.")); 570 printf(" %s\n", _("If the full package information of any of the upgradable packages match"));
519 printf (" %s\n", "-c, --critical=REGEXP"); 571 printf(" %s\n", _("this REGEXP, the plugin will return CRITICAL status. Can be specified"));
520 printf (" %s\n", _("If the full package information of any of the upgradable packages match")); 572 printf(" %s\n", _("multiple times like above. Default is a regexp matching security"));
521 printf (" %s\n", _("this REGEXP, the plugin will return CRITICAL status. Can be specified")); 573 printf(" %s\n", _("upgrades for Debian and Ubuntu:"));
522 printf (" %s\n", _("multiple times like above. Default is a regexp matching security")); 574 printf(" \t%s\n", SECURITY_RE);
523 printf (" %s\n", _("upgrades for Debian and Ubuntu:")); 575 printf(" %s\n", _("Note that the package must first match the include list before its"));
524 printf (" \t%s\n", SECURITY_RE); 576 printf(" %s\n", _("information is compared against the critical list."));
525 printf (" %s\n", _("Note that the package must first match the include list before its")); 577 printf(" %s\n", "-o, --only-critical");
526 printf (" %s\n", _("information is compared against the critical list.")); 578 printf(" %s\n", _("Only warn about upgrades matching the critical list. The total number"));
527 printf (" %s\n", "-o, --only-critical"); 579 printf(" %s\n", _("of upgrades will be printed, but any non-critical upgrades will not cause"));
528 printf (" %s\n", _("Only warn about upgrades matching the critical list. The total number")); 580 printf(" %s\n", _("the plugin to return WARNING status."));
529 printf (" %s\n", _("of upgrades will be printed, but any non-critical upgrades will not cause")); 581 printf(" %s\n", "-w, --packages-warning");
530 printf (" %s\n", _("the plugin to return WARNING status.")); 582 printf(" %s\n", _("Minimum number of packages available for upgrade to return WARNING status."));
531 printf (" %s\n", "-w, --packages-warning"); 583 printf(" %s\n\n", _("Default is 1 package."));
532 printf (" %s\n", _("Minimum number of packages available for upgrade to return WARNING status.")); 584
533 printf (" %s\n\n", _("Default is 1 package.")); 585 printf("%s\n\n", _("The following options require root privileges and should be used with care:"));
534 586 printf(" %s\n", "-u, --update=OPTS");
535 printf ("%s\n\n", _("The following options require root privileges and should be used with care:")); 587 printf(" %s\n", _("First perform an 'apt-get update'. An optional OPTS parameter overrides"));
536 printf (" %s\n", "-u, --update=OPTS"); 588 printf(" %s\n", _("the default options. Note: you may also need to adjust the global"));
537 printf (" %s\n", _("First perform an 'apt-get update'. An optional OPTS parameter overrides")); 589 printf(" %s\n", _("timeout (with -t) to prevent the plugin from timing out if apt-get"));
538 printf (" %s\n", _("the default options. Note: you may also need to adjust the global")); 590 printf(" %s\n", _("upgrade is expected to take longer than the default timeout."));
539 printf (" %s\n", _("timeout (with -t) to prevent the plugin from timing out if apt-get")); 591 printf(" %s\n", "-U, --upgrade=OPTS");
540 printf (" %s\n", _("upgrade is expected to take longer than the default timeout.")); 592 printf(" %s\n", _("Perform an upgrade. If an optional OPTS argument is provided,"));
541 printf (" %s\n", "-U, --upgrade=OPTS"); 593 printf(" %s\n", _("apt-get will be run with these command line options instead of the"));
542 printf (" %s\n", _("Perform an upgrade. If an optional OPTS argument is provided,")); 594 printf(" %s", _("default "));
543 printf (" %s\n", _("apt-get will be run with these command line options instead of the")); 595 printf("(%s).\n", UPGRADE_DEFAULT_OPTS);
544 printf (" %s", _("default ")); 596 printf(" %s\n", _("Note that you may be required to have root privileges if you do not use"));
545 printf ("(%s).\n", UPGRADE_DEFAULT_OPTS); 597 printf(" %s\n", _("the default options, which will only run a simulation and NOT perform the upgrade"));
546 printf (" %s\n", _("Note that you may be required to have root privileges if you do not use")); 598 printf(" %s\n", "-d, --dist-upgrade=OPTS");
547 printf (" %s\n", _("the default options, which will only run a simulation and NOT perform the upgrade")); 599 printf(" %s\n", _("Perform a dist-upgrade instead of normal upgrade. Like with -U OPTS"));
548 printf (" %s\n", "-d, --dist-upgrade=OPTS"); 600 printf(" %s\n", _("can be provided to override the default options."));
549 printf (" %s\n", _("Perform a dist-upgrade instead of normal upgrade. Like with -U OPTS")); 601
550 printf (" %s\n", _("can be provided to override the default options.")); 602 printf(UT_SUPPORT);
551
552 printf(UT_SUPPORT);
553} 603}
554 604
555
556/* simple usage heading */ 605/* simple usage heading */
557void 606void print_usage(void) {
558print_usage(void) 607 printf("%s\n", _("Usage:"));
559{ 608 printf("%s [[-d|-u|-U]opts] [-n] [-l] [-t timeout] [-w packages-warning]\n", progname);
560 printf ("%s\n", _("Usage:"));
561 printf ("%s [[-d|-u|-U]opts] [-n] [-l] [-t timeout] [-w packages-warning]\n", progname);
562} 609}
diff --git a/plugins/check_apt.d/config.h b/plugins/check_apt.d/config.h
new file mode 100644
index 00000000..981f4f42
--- /dev/null
+++ b/plugins/check_apt.d/config.h
@@ -0,0 +1,41 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6/* some constants */
7typedef enum {
8 UPGRADE,
9 DIST_UPGRADE,
10 NO_UPGRADE
11} upgrade_type;
12
13typedef struct {
14 bool do_update; /* whether to call apt-get update */
15 upgrade_type upgrade; /* which type of upgrade to do */
16 bool only_critical; /* whether to warn about non-critical updates */
17 bool list; /* list packages available for upgrade */
18 /* number of packages available for upgrade to return WARNING status */
19 int packages_warning;
20
21 char *upgrade_opts; /* options to override defaults for upgrade */
22 char *update_opts; /* options to override defaults for update */
23 char *do_include; /* regexp to only include certain packages */
24 char *do_exclude; /* regexp to only exclude certain packages */
25 char *do_critical; /* regexp specifying critical packages */
26 char *input_filename; /* input filename for testing */
27} check_apt_config;
28
29check_apt_config check_apt_config_init() {
30 check_apt_config tmp = {.do_update = false,
31 .upgrade = UPGRADE,
32 .only_critical = false,
33 .list = false,
34 .packages_warning = 1,
35 .update_opts = NULL,
36 .do_include = NULL,
37 .do_exclude = NULL,
38 .do_critical = NULL,
39 .input_filename = NULL};
40 return tmp;
41}
diff --git a/plugins/check_by_ssh.c b/plugins/check_by_ssh.c
index 2a23b397..2bc38d49 100644
--- a/plugins/check_by_ssh.c
+++ b/plugins/check_by_ssh.c
@@ -1,495 +1,509 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_by_ssh plugin 3 * Monitoring check_by_ssh plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2008 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_by_ssh plugin 10 * This file contains the check_by_ssh plugin
11* 11 *
12* 12 *
13* This program is free software: you can redistribute it and/or modify 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 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 15 * the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16 * (at your option) any later version.
17* 17 *
18* This program is distributed in the hope that it will be useful, 18 * This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21 * GNU General Public License for more details.
22* 22 *
23* You should have received a copy of the GNU General Public License 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/>. 24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25 *
26* 26 *
27*****************************************************************************/ 27 *****************************************************************************/
28 28
29const char *progname = "check_by_ssh"; 29const char *progname = "check_by_ssh";
30const char *copyright = "2000-2008"; 30const char *copyright = "2000-2024";
31const char *email = "devel@monitoring-plugins.org"; 31const char *email = "devel@monitoring-plugins.org";
32 32
33#include "common.h" 33#include "common.h"
34#include "utils.h" 34#include "utils.h"
35#include "netutils.h"
36#include "utils_cmd.h" 35#include "utils_cmd.h"
36#include "check_by_ssh.d/config.h"
37#include "states.h"
37 38
38#ifndef NP_MAXARGS 39#ifndef NP_MAXARGS
39#define NP_MAXARGS 1024 40# define NP_MAXARGS 1024
40#endif 41#endif
41 42
42int process_arguments (int, char **); 43typedef struct {
43int validate_arguments (void); 44 int errorcode;
44void comm_append (const char *); 45 check_by_ssh_config config;
45void print_help (void); 46} check_by_ssh_config_wrapper;
46void print_usage (void); 47static check_by_ssh_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
47 48static check_by_ssh_config_wrapper validate_arguments(check_by_ssh_config_wrapper /*config_wrapper*/);
48unsigned int commands = 0;
49unsigned int services = 0;
50int skip_stdout = 0;
51int skip_stderr = 0;
52int warn_on_stderr = 0;
53bool unknown_timeout = false;
54char *remotecmd = NULL;
55char **commargv = NULL;
56int commargc = 0;
57char *hostname = NULL;
58char *outputfile = NULL;
59char *host_shortname = NULL;
60char **service;
61bool passive = false;
62bool verbose = false;
63
64int
65main (int argc, char **argv)
66{
67 49
68 char *status_text; 50static command_construct comm_append(command_construct /*cmd*/, const char * /*str*/);
69 int cresult; 51static void print_help(void);
70 int result = STATE_UNKNOWN; 52void print_usage(void);
71 time_t local_time;
72 FILE *fp = NULL;
73 output chld_out, chld_err;
74 53
75 remotecmd = ""; 54static bool verbose = false;
76 comm_append(SSH_COMMAND);
77 55
78 setlocale (LC_ALL, ""); 56int main(int argc, char **argv) {
79 bindtextdomain (PACKAGE, LOCALEDIR); 57 setlocale(LC_ALL, "");
80 textdomain (PACKAGE); 58 bindtextdomain(PACKAGE, LOCALEDIR);
59 textdomain(PACKAGE);
81 60
82 /* Parse extra opts if any */ 61 /* Parse extra opts if any */
83 argv=np_extra_opts (&argc, argv, progname); 62 argv = np_extra_opts(&argc, argv, progname);
63
64 check_by_ssh_config_wrapper tmp_config = process_arguments(argc, argv);
84 65
85 /* process arguments */ 66 /* process arguments */
86 if (process_arguments (argc, argv) == ERROR) 67 if (tmp_config.errorcode == ERROR) {
87 usage_va(_("Could not parse arguments")); 68 usage_va(_("Could not parse arguments"));
69 }
70
71 const check_by_ssh_config config = tmp_config.config;
88 72
89 /* Set signal handling and alarm timeout */ 73 /* Set signal handling and alarm timeout */
90 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 74 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
91 usage_va(_("Cannot catch SIGALRM")); 75 usage_va(_("Cannot catch SIGALRM"));
92 } 76 }
93 alarm (timeout_interval); 77 alarm(timeout_interval);
94 78
95 /* run the command */ 79 /* run the command */
96 if (verbose) { 80 if (verbose) {
97 printf ("Command: %s\n", commargv[0]); 81 printf("Command: %s\n", config.cmd.commargv[0]);
98 for (int i = 1; i < commargc; i++) 82 for (int i = 1; i < config.cmd.commargc; i++) {
99 printf ("Argument %i: %s\n", i, commargv[i]); 83 printf("Argument %i: %s\n", i, config.cmd.commargv[i]);
84 }
100 } 85 }
101 86
102 result = cmd_run_array (commargv, &chld_out, &chld_err, 0); 87 output chld_out;
88 output chld_err;
89 mp_state_enum result = cmd_run_array(config.cmd.commargv, &chld_out, &chld_err, 0);
103 90
104 /* SSH returns 255 if connection attempt fails; include the first line of error output */ 91 /* SSH returns 255 if connection attempt fails; include the first line of error output */
105 if (result == 255 && unknown_timeout) { 92 if (result == 255 && config.unknown_timeout) {
106 printf (_("SSH connection failed: %s\n"), 93 printf(_("SSH connection failed: %s\n"), chld_err.lines > 0 ? chld_err.line[0] : "(no error output)");
107 chld_err.lines > 0 ? chld_err.line[0] : "(no error output)");
108 return STATE_UNKNOWN; 94 return STATE_UNKNOWN;
109 } 95 }
110 96
111 if (verbose) { 97 if (verbose) {
112 for(size_t i = 0; i < chld_out.lines; i++) 98 for (size_t i = 0; i < chld_out.lines; i++) {
113 printf("stdout: %s\n", chld_out.line[i]); 99 printf("stdout: %s\n", chld_out.line[i]);
114 for(size_t i = 0; i < chld_err.lines; i++) 100 }
101 for (size_t i = 0; i < chld_err.lines; i++) {
115 printf("stderr: %s\n", chld_err.line[i]); 102 printf("stderr: %s\n", chld_err.line[i]);
103 }
116 } 104 }
117 105
118 if (skip_stdout == -1) /* --skip-stdout specified without argument */ 106 size_t skip_stdout = 0;
107 if (config.skip_stdout == -1) { /* --skip-stdout specified without argument */
119 skip_stdout = chld_out.lines; 108 skip_stdout = chld_out.lines;
120 if (skip_stderr == -1) /* --skip-stderr specified without argument */ 109 } else {
110 skip_stdout = config.skip_stdout;
111 }
112
113 size_t skip_stderr = 0;
114 if (config.skip_stderr == -1) { /* --skip-stderr specified without argument */
121 skip_stderr = chld_err.lines; 115 skip_stderr = chld_err.lines;
116 } else {
117 skip_stderr = config.skip_stderr;
118 }
122 119
123 /* UNKNOWN or worse if (non-skipped) output found on stderr */ 120 /* UNKNOWN or worse if (non-skipped) output found on stderr */
124 if(chld_err.lines > (size_t)skip_stderr) { 121 if (chld_err.lines > (size_t)skip_stderr) {
125 printf (_("Remote command execution failed: %s\n"), 122 printf(_("Remote command execution failed: %s\n"), chld_err.line[skip_stderr]);
126 chld_err.line[skip_stderr]); 123 if (config.warn_on_stderr) {
127 if ( warn_on_stderr )
128 return max_state_alt(result, STATE_WARNING); 124 return max_state_alt(result, STATE_WARNING);
129 else 125 }
130 return max_state_alt(result, STATE_UNKNOWN); 126 return max_state_alt(result, STATE_UNKNOWN);
131 } 127 }
132 128
133 /* this is simple if we're not supposed to be passive. 129 /* this is simple if we're not supposed to be passive.
134 * Wrap up quickly and keep the tricks below */ 130 * Wrap up quickly and keep the tricks below */
135 if(!passive) { 131 if (!config.passive) {
136 if (chld_out.lines > (size_t)skip_stdout) 132 if (chld_out.lines > (size_t)skip_stdout) {
137 for (size_t i = skip_stdout; i < chld_out.lines; i++) 133 for (size_t i = skip_stdout; i < chld_out.lines; i++) {
138 puts (chld_out.line[i]); 134 puts(chld_out.line[i]);
139 else 135 }
140 printf (_("%s - check_by_ssh: Remote command '%s' returned status %d\n"), 136 } else {
141 state_text(result), remotecmd, result); 137 printf(_("%s - check_by_ssh: Remote command '%s' returned status %d\n"), state_text(result), config.remotecmd, result);
142 return result; /* return error status from remote command */ 138 }
139 return result; /* return error status from remote command */
143 } 140 }
144 141
145
146 /* 142 /*
147 * Passive mode 143 * Passive mode
148 */ 144 */
149 145
150 /* process output */ 146 /* process output */
151 if (!(fp = fopen (outputfile, "a"))) { 147 FILE *file_pointer = NULL;
152 printf (_("SSH WARNING: could not open %s\n"), outputfile); 148 if (!(file_pointer = fopen(config.outputfile, "a"))) {
153 exit (STATE_UNKNOWN); 149 printf(_("SSH WARNING: could not open %s\n"), config.outputfile);
150 exit(STATE_UNKNOWN);
154 } 151 }
155 152
156 local_time = time (NULL); 153 time_t local_time = time(NULL);
157 commands = 0; 154 unsigned int commands = 0;
158 for(size_t i = skip_stdout; i < chld_out.lines; i++) { 155 char *status_text;
156 int cresult;
157 for (size_t i = skip_stdout; i < chld_out.lines; i++) {
159 status_text = chld_out.line[i++]; 158 status_text = chld_out.line[i++];
160 if (i == chld_out.lines || strstr (chld_out.line[i], "STATUS CODE: ") == NULL) 159 if (i == chld_out.lines || strstr(chld_out.line[i], "STATUS CODE: ") == NULL) {
161 die (STATE_UNKNOWN, _("%s: Error parsing output\n"), progname); 160 die(STATE_UNKNOWN, _("%s: Error parsing output\n"), progname);
162 161 }
163 if (service[commands] && status_text 162
164 && sscanf (chld_out.line[i], "STATUS CODE: %d", &cresult) == 1) 163 if (config.service[commands] && status_text && sscanf(chld_out.line[i], "STATUS CODE: %d", &cresult) == 1) {
165 { 164 fprintf(file_pointer, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n", (int)local_time, config.host_shortname,
166 fprintf (fp, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n", 165 config.service[commands++], cresult, status_text);
167 (int) local_time, host_shortname, service[commands++],
168 cresult, status_text);
169 } 166 }
170 } 167 }
171 168
172 /* Multiple commands and passive checking should always return OK */ 169 /* Multiple commands and passive checking should always return OK */
173 return result; 170 exit(result);
174} 171}
175 172
176/* process command-line arguments */ 173/* process command-line arguments */
177int 174check_by_ssh_config_wrapper process_arguments(int argc, char **argv) {
178process_arguments (int argc, char **argv) 175 static struct option longopts[] = {{"version", no_argument, 0, 'V'},
179{ 176 {"help", no_argument, 0, 'h'},
180 int c; 177 {"verbose", no_argument, 0, 'v'},
181 char *p1, *p2; 178 {"fork", no_argument, 0, 'f'},
182 179 {"timeout", required_argument, 0, 't'},
183 int option = 0; 180 {"unknown-timeout", no_argument, 0, 'U'},
184 static struct option longopts[] = { 181 {"host", required_argument, 0, 'H'}, /* backward compatibility */
185 {"version", no_argument, 0, 'V'}, 182 {"hostname", required_argument, 0, 'H'},
186 {"help", no_argument, 0, 'h'}, 183 {"port", required_argument, 0, 'p'},
187 {"verbose", no_argument, 0, 'v'}, 184 {"output", required_argument, 0, 'O'},
188 {"fork", no_argument, 0, 'f'}, 185 {"name", required_argument, 0, 'n'},
189 {"timeout", required_argument, 0, 't'}, 186 {"services", required_argument, 0, 's'},
190 {"unknown-timeout", no_argument, 0, 'U'}, 187 {"identity", required_argument, 0, 'i'},
191 {"host", required_argument, 0, 'H'}, /* backward compatibility */ 188 {"user", required_argument, 0, 'u'},
192 {"hostname", required_argument, 0, 'H'}, 189 {"logname", required_argument, 0, 'l'},
193 {"port", required_argument,0,'p'}, 190 {"command", required_argument, 0, 'C'},
194 {"output", required_argument, 0, 'O'}, 191 {"skip", optional_argument, 0, 'S'}, /* backwards compatibility */
195 {"name", required_argument, 0, 'n'}, 192 {"skip-stdout", optional_argument, 0, 'S'},
196 {"services", required_argument, 0, 's'}, 193 {"skip-stderr", optional_argument, 0, 'E'},
197 {"identity", required_argument, 0, 'i'}, 194 {"warn-on-stderr", no_argument, 0, 'W'},
198 {"user", required_argument, 0, 'u'}, 195 {"proto1", no_argument, 0, '1'},
199 {"logname", required_argument, 0, 'l'}, 196 {"proto2", no_argument, 0, '2'},
200 {"command", required_argument, 0, 'C'}, 197 {"use-ipv4", no_argument, 0, '4'},
201 {"skip", optional_argument, 0, 'S'}, /* backwards compatibility */ 198 {"use-ipv6", no_argument, 0, '6'},
202 {"skip-stdout", optional_argument, 0, 'S'}, 199 {"ssh-option", required_argument, 0, 'o'},
203 {"skip-stderr", optional_argument, 0, 'E'}, 200 {"quiet", no_argument, 0, 'q'},
204 {"warn-on-stderr", no_argument, 0, 'W'}, 201 {"configfile", optional_argument, 0, 'F'},
205 {"proto1", no_argument, 0, '1'}, 202 {0, 0, 0, 0}};
206 {"proto2", no_argument, 0, '2'}, 203
207 {"use-ipv4", no_argument, 0, '4'}, 204 check_by_ssh_config_wrapper result = {
208 {"use-ipv6", no_argument, 0, '6'}, 205 .errorcode = OK,
209 {"ssh-option", required_argument, 0, 'o'}, 206 .config = check_by_ssh_config_init(),
210 {"quiet", no_argument, 0, 'q'},
211 {"configfile", optional_argument, 0, 'F'},
212 {0, 0, 0, 0}
213 }; 207 };
214 208
215 if (argc < 2) 209 if (argc < 2) {
216 return ERROR; 210 result.errorcode = ERROR;
211 return result;
212 }
213
214 for (int index = 1; index < argc; index++) {
215 if (strcmp("-to", argv[index]) == 0) {
216 strcpy(argv[index], "-t");
217 }
218 }
217 219
218 for (c = 1; c < argc; c++) 220 result.config.cmd = comm_append(result.config.cmd, SSH_COMMAND);
219 if (strcmp ("-to", argv[c]) == 0)
220 strcpy (argv[c], "-t");
221 221
222 while (1) { 222 int option = 0;
223 c = getopt_long (argc, argv, "Vvh1246fqt:UH:O:p:i:u:l:C:S::E::n:s:o:F:", longopts, 223 while (true) {
224 &option); 224 int opt_index = getopt_long(argc, argv, "Vvh1246fqt:UH:O:p:i:u:l:C:S::E::n:s:o:F:", longopts, &option);
225 225
226 if (c == -1 || c == EOF) 226 if (opt_index == -1 || opt_index == EOF) {
227 break; 227 break;
228 }
228 229
229 switch (c) { 230 switch (opt_index) {
230 case 'V': /* version */ 231 case 'V': /* version */
231 print_revision (progname, NP_VERSION); 232 print_revision(progname, NP_VERSION);
232 exit (STATE_UNKNOWN); 233 exit(STATE_UNKNOWN);
233 case 'h': /* help */ 234 case 'h': /* help */
234 print_help (); 235 print_help();
235 exit (STATE_UNKNOWN); 236 exit(STATE_UNKNOWN);
236 case 'v': /* help */ 237 case 'v': /* help */
237 verbose = true; 238 verbose = true;
238 break; 239 break;
239 case 't': /* timeout period */ 240 case 't': /* timeout period */
240 if (!is_integer (optarg)) 241 if (!is_integer(optarg)) {
241 usage_va(_("Timeout interval must be a positive integer")); 242 usage_va(_("Timeout interval must be a positive integer"));
242 else 243 } else {
243 timeout_interval = atoi (optarg); 244 timeout_interval = atoi(optarg);
245 }
244 break; 246 break;
245 case 'U': 247 case 'U':
246 unknown_timeout = true; 248 result.config.unknown_timeout = true;
247 break; 249 break;
248 case 'H': /* host */ 250 case 'H': /* host */
249 hostname = optarg; 251 result.config.hostname = optarg;
250 break; 252 break;
251 case 'p': /* port number */ 253 case 'p': /* port number */
252 if (!is_integer (optarg)) 254 if (!is_integer(optarg)) {
253 usage_va(_("Port must be a positive integer")); 255 usage_va(_("Port must be a positive integer"));
254 comm_append("-p"); 256 }
255 comm_append(optarg); 257 result.config.cmd = comm_append(result.config.cmd, "-p");
258 result.config.cmd = comm_append(result.config.cmd, optarg);
256 break; 259 break;
257 case 'O': /* output file */ 260 case 'O': /* output file */
258 outputfile = optarg; 261 result.config.outputfile = optarg;
259 passive = true; 262 result.config.passive = true;
260 break; 263 break;
261 case 's': /* description of service to check */ 264 case 's': /* description of service to check */ {
265 char *p1;
266 char *p2;
267
262 p1 = optarg; 268 p1 = optarg;
263 service = realloc (service, (++services) * sizeof(char *)); 269 result.config.service = realloc(result.config.service, (++result.config.number_of_services) * sizeof(char *));
264 while ((p2 = index (p1, ':'))) { 270 while ((p2 = index(p1, ':'))) {
265 *p2 = '\0'; 271 *p2 = '\0';
266 service[services - 1] = p1; 272 result.config.service[result.config.number_of_services - 1] = p1;
267 service = realloc (service, (++services) * sizeof(char *)); 273 result.config.service = realloc(result.config.service, (++result.config.number_of_services) * sizeof(char *));
268 p1 = p2 + 1; 274 p1 = p2 + 1;
269 } 275 }
270 service[services - 1] = p1; 276 result.config.service[result.config.number_of_services - 1] = p1;
271 break; 277 break;
272 case 'n': /* short name of host in the monitoring configuration */ 278 case 'n': /* short name of host in the monitoring configuration */
273 host_shortname = optarg; 279 result.config.host_shortname = optarg;
274 break; 280 } break;
275
276 case 'u': 281 case 'u':
277 comm_append("-l"); 282 result.config.cmd = comm_append(result.config.cmd, "-l");
278 comm_append(optarg); 283 result.config.cmd = comm_append(result.config.cmd, optarg);
279 break; 284 break;
280 case 'l': /* login name */ 285 case 'l': /* login name */
281 comm_append("-l"); 286 result.config.cmd = comm_append(result.config.cmd, "-l");
282 comm_append(optarg); 287 result.config.cmd = comm_append(result.config.cmd, optarg);
283 break; 288 break;
284 case 'i': /* identity */ 289 case 'i': /* identity */
285 comm_append("-i"); 290 result.config.cmd = comm_append(result.config.cmd, "-i");
286 comm_append(optarg); 291 result.config.cmd = comm_append(result.config.cmd, optarg);
287 break; 292 break;
288 293
289 case '1': /* Pass these switches directly to ssh */ 294 case '1': /* Pass these switches directly to ssh */
290 comm_append("-1"); 295 result.config.cmd = comm_append(result.config.cmd, "-1");
291 break; 296 break;
292 case '2': /* 1 to force version 1, 2 to force version 2 */ 297 case '2': /* 1 to force version 1, 2 to force version 2 */
293 comm_append("-2"); 298 result.config.cmd = comm_append(result.config.cmd, "-2");
294 break; 299 break;
295 case '4': /* -4 for IPv4 */ 300 case '4': /* -4 for IPv4 */
296 comm_append("-4"); 301 result.config.cmd = comm_append(result.config.cmd, "-4");
297 break; 302 break;
298 case '6': /* -6 for IPv6 */ 303 case '6': /* -6 for IPv6 */
299 comm_append("-6"); 304 result.config.cmd = comm_append(result.config.cmd, "-6");
300 break; 305 break;
301 case 'f': /* fork to background */ 306 case 'f': /* fork to background */
302 comm_append("-f"); 307 result.config.cmd = comm_append(result.config.cmd, "-f");
303 break; 308 break;
304 case 'C': /* Command for remote machine */ 309 case 'C': /* Command for remote machine */
305 commands++; 310 result.config.commands++;
306 if (commands > 1) 311 if (result.config.commands > 1) {
307 xasprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd); 312 xasprintf(&result.config.remotecmd, "%s;echo STATUS CODE: $?;", result.config.remotecmd);
308 xasprintf (&remotecmd, "%s%s", remotecmd, optarg); 313 }
314 xasprintf(&result.config.remotecmd, "%s%s", result.config.remotecmd, optarg);
309 break; 315 break;
310 case 'S': /* skip n (or all) lines on stdout */ 316 case 'S': /* skip n (or all) lines on stdout */
311 if (optarg == NULL) 317 if (optarg == NULL) {
312 skip_stdout = -1; /* skip all output on stdout */ 318 result.config.skip_stdout = -1; /* skip all output on stdout */
313 else if (!is_integer (optarg)) 319 } else if (!is_integer(optarg)) {
314 usage_va(_("skip-stdout argument must be an integer")); 320 usage_va(_("skip-stdout argument must be an integer"));
315 else 321 } else {
316 skip_stdout = atoi (optarg); 322 result.config.skip_stdout = atoi(optarg);
323 }
317 break; 324 break;
318 case 'E': /* skip n (or all) lines on stderr */ 325 case 'E': /* skip n (or all) lines on stderr */
319 if (optarg == NULL) 326 if (optarg == NULL) {
320 skip_stderr = -1; /* skip all output on stderr */ 327 result.config.skip_stderr = -1; /* skip all output on stderr */
321 else if (!is_integer (optarg)) 328 } else if (!is_integer(optarg)) {
322 usage_va(_("skip-stderr argument must be an integer")); 329 usage_va(_("skip-stderr argument must be an integer"));
323 else 330 } else {
324 skip_stderr = atoi (optarg); 331 result.config.skip_stderr = atoi(optarg);
332 }
325 break; 333 break;
326 case 'W': /* exit with warning if there is an output on stderr */ 334 case 'W': /* exit with warning if there is an output on stderr */
327 warn_on_stderr = 1; 335 result.config.warn_on_stderr = true;
328 break; 336 break;
329 case 'o': /* Extra options for the ssh command */ 337 case 'o': /* Extra options for the ssh command */
330 comm_append("-o"); 338 result.config.cmd = comm_append(result.config.cmd, "-o");
331 comm_append(optarg); 339 result.config.cmd = comm_append(result.config.cmd, optarg);
332 break; 340 break;
333 case 'q': /* Tell the ssh command to be quiet */ 341 case 'q': /* Tell the ssh command to be quiet */
334 comm_append("-q"); 342 result.config.cmd = comm_append(result.config.cmd, "-q");
335 break; 343 break;
336 case 'F': /* ssh configfile */ 344 case 'F': /* ssh configfile */
337 comm_append("-F"); 345 result.config.cmd = comm_append(result.config.cmd, "-F");
338 comm_append(optarg); 346 result.config.cmd = comm_append(result.config.cmd, optarg);
339 break; 347 break;
340 default: /* help */ 348 default: /* help */
341 usage5(); 349 usage5();
342 } 350 }
343 } 351 }
344 352
345 c = optind; 353 int c = optind;
346 if (hostname == NULL) { 354 if (result.config.hostname == NULL) {
347 if (c <= argc) { 355 if (c <= argc) {
348 die (STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname); 356 die(STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname);
349 } 357 }
350 hostname = argv[c++]; 358 result.config.hostname = argv[c++];
351 } 359 }
352 360
353 if (strlen(remotecmd) == 0) { 361 if (strlen(result.config.remotecmd) == 0) {
354 for (; c < argc; c++) 362 for (; c < argc; c++) {
355 if (strlen(remotecmd) > 0) 363 if (strlen(result.config.remotecmd) > 0) {
356 xasprintf (&remotecmd, "%s %s", remotecmd, argv[c]); 364 xasprintf(&result.config.remotecmd, "%s %s", result.config.remotecmd, argv[c]);
357 else 365 } else {
358 xasprintf (&remotecmd, "%s", argv[c]); 366 xasprintf(&result.config.remotecmd, "%s", argv[c]);
367 }
368 }
359 } 369 }
360 370
361 if (commands > 1 || passive) 371 if (result.config.commands > 1 || result.config.passive) {
362 xasprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd); 372 xasprintf(&result.config.remotecmd, "%s;echo STATUS CODE: $?;", result.config.remotecmd);
373 }
363 374
364 if (remotecmd == NULL || strlen (remotecmd) <= 1) 375 if (result.config.remotecmd == NULL || strlen(result.config.remotecmd) <= 1) {
365 usage_va(_("No remotecmd")); 376 usage_va(_("No remotecmd"));
377 }
366 378
367 comm_append(hostname); 379 result.config.cmd = comm_append(result.config.cmd, result.config.hostname);
368 comm_append(remotecmd); 380 result.config.cmd = comm_append(result.config.cmd, result.config.remotecmd);
369 381
370 return validate_arguments (); 382 return validate_arguments(result);
371} 383}
372 384
385command_construct comm_append(command_construct cmd, const char *str) {
373 386
374void 387 if (verbose) {
375comm_append (const char *str) 388 for (int i = 0; i < cmd.commargc; i++) {
376{ 389 printf("Current command: [%i] %s\n", i, cmd.commargv[i]);
390 }
391
392 printf("Appending: %s\n", str);
393 }
377 394
378 if (++commargc > NP_MAXARGS) 395 if (++cmd.commargc > NP_MAXARGS) {
379 die(STATE_UNKNOWN, _("%s: Argument limit of %d exceeded\n"), progname, NP_MAXARGS); 396 die(STATE_UNKNOWN, _("%s: Argument limit of %d exceeded\n"), progname, NP_MAXARGS);
397 }
380 398
381 if ((commargv = (char **)realloc(commargv, (commargc+1) * sizeof(char *))) == NULL) 399 if ((cmd.commargv = (char **)realloc(cmd.commargv, (cmd.commargc + 1) * sizeof(char *))) == NULL) {
382 die(STATE_UNKNOWN, _("Can not (re)allocate 'commargv' buffer\n")); 400 die(STATE_UNKNOWN, _("Can not (re)allocate 'commargv' buffer\n"));
401 }
383 402
384 commargv[commargc-1] = strdup(str); 403 cmd.commargv[cmd.commargc - 1] = strdup(str);
385 commargv[commargc] = NULL; 404 cmd.commargv[cmd.commargc] = NULL;
386 405
406 return cmd;
387} 407}
388 408
389int 409check_by_ssh_config_wrapper validate_arguments(check_by_ssh_config_wrapper config_wrapper) {
390validate_arguments (void) 410 if (config_wrapper.config.remotecmd == NULL || config_wrapper.config.hostname == NULL) {
391{ 411 config_wrapper.errorcode = ERROR;
392 if (remotecmd == NULL || hostname == NULL) 412 return config_wrapper;
393 return ERROR; 413 }
394 414
395 if (passive && commands != services) 415 if (config_wrapper.config.passive && config_wrapper.config.commands != config_wrapper.config.number_of_services) {
396 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide a service name for each command.\n"), progname); 416 die(STATE_UNKNOWN, _("%s: In passive mode, you must provide a service name for each command.\n"), progname);
417 }
397 418
398 if (passive && host_shortname == NULL) 419 if (config_wrapper.config.passive && config_wrapper.config.host_shortname == NULL) {
399 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide the host short name from the monitoring configs.\n"), progname); 420 die(STATE_UNKNOWN, _("%s: In passive mode, you must provide the host short name from the monitoring configs.\n"), progname);
421 }
400 422
401 return OK; 423 return config_wrapper;
402} 424}
403 425
404 426void print_help(void) {
405void 427 print_revision(progname, NP_VERSION);
406print_help (void) 428
407{ 429 printf("Copyright (c) 1999 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n");
408 print_revision (progname, NP_VERSION); 430 printf(COPYRIGHT, copyright, email);
409 431
410 printf ("Copyright (c) 1999 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n"); 432 printf(_("This plugin uses SSH to execute commands on a remote host"));
411 printf (COPYRIGHT, copyright, email); 433
412 434 printf("\n\n");
413 printf (_("This plugin uses SSH to execute commands on a remote host")); 435
414 436 print_usage();
415 printf ("\n\n"); 437
416 438 printf(UT_HELP_VRSN);
417 print_usage (); 439
418 440 printf(UT_EXTRA_OPTS);
419 printf (UT_HELP_VRSN); 441
420 442 printf(UT_HOST_PORT, 'p', "none");
421 printf (UT_EXTRA_OPTS); 443
422 444 printf(UT_IPv46);
423 printf (UT_HOST_PORT, 'p', "none"); 445
424 446 printf(" %s\n", "-1, --proto1");
425 printf (UT_IPv46); 447 printf(" %s\n", _("tell ssh to use Protocol 1 [optional]"));
426 448 printf(" %s\n", "-2, --proto2");
427 printf (" %s\n", "-1, --proto1"); 449 printf(" %s\n", _("tell ssh to use Protocol 2 [optional]"));
428 printf (" %s\n", _("tell ssh to use Protocol 1 [optional]")); 450 printf(" %s\n", "-S, --skip-stdout[=n]");
429 printf (" %s\n", "-2, --proto2"); 451 printf(" %s\n", _("Ignore all or (if specified) first n lines on STDOUT [optional]"));
430 printf (" %s\n", _("tell ssh to use Protocol 2 [optional]")); 452 printf(" %s\n", "-E, --skip-stderr[=n]");
431 printf (" %s\n", "-S, --skip-stdout[=n]"); 453 printf(" %s\n", _("Ignore all or (if specified) first n lines on STDERR [optional]"));
432 printf (" %s\n", _("Ignore all or (if specified) first n lines on STDOUT [optional]")); 454 printf(" %s\n", "-W, --warn-on-stderr]");
433 printf (" %s\n", "-E, --skip-stderr[=n]"); 455 printf(" %s\n", _("Exit with an warning, if there is an output on STDERR"));
434 printf (" %s\n", _("Ignore all or (if specified) first n lines on STDERR [optional]")); 456 printf(" %s\n", "-f");
435 printf (" %s\n", "-W, --warn-on-stderr]"); 457 printf(" %s\n", _("tells ssh to fork rather than create a tty [optional]. This will always return OK if ssh is executed"));
436 printf (" %s\n", _("Exit with an warning, if there is an output on STDERR")); 458 printf(" %s\n", "-C, --command='COMMAND STRING'");
437 printf (" %s\n", "-f"); 459 printf(" %s\n", _("command to execute on the remote machine"));
438 printf (" %s\n", _("tells ssh to fork rather than create a tty [optional]. This will always return OK if ssh is executed")); 460 printf(" %s\n", "-l, --logname=USERNAME");
439 printf (" %s\n","-C, --command='COMMAND STRING'"); 461 printf(" %s\n", _("SSH user name on remote host [optional]"));
440 printf (" %s\n", _("command to execute on the remote machine")); 462 printf(" %s\n", "-i, --identity=KEYFILE");
441 printf (" %s\n","-l, --logname=USERNAME"); 463 printf(" %s\n", _("identity of an authorized key [optional]"));
442 printf (" %s\n", _("SSH user name on remote host [optional]")); 464 printf(" %s\n", "-O, --output=FILE");
443 printf (" %s\n","-i, --identity=KEYFILE"); 465 printf(" %s\n", _("external command file for monitoring [optional]"));
444 printf (" %s\n", _("identity of an authorized key [optional]")); 466 printf(" %s\n", "-s, --services=LIST");
445 printf (" %s\n","-O, --output=FILE"); 467 printf(" %s\n", _("list of monitoring service names, separated by ':' [optional]"));
446 printf (" %s\n", _("external command file for monitoring [optional]")); 468 printf(" %s\n", "-n, --name=NAME");
447 printf (" %s\n","-s, --services=LIST"); 469 printf(" %s\n", _("short name of host in the monitoring configuration [optional]"));
448 printf (" %s\n", _("list of monitoring service names, separated by ':' [optional]")); 470 printf(" %s\n", "-o, --ssh-option=OPTION");
449 printf (" %s\n","-n, --name=NAME"); 471 printf(" %s\n", _("Call ssh with '-o OPTION' (may be used multiple times) [optional]"));
450 printf (" %s\n", _("short name of host in the monitoring configuration [optional]")); 472 printf(" %s\n", "-F, --configfile");
451 printf (" %s\n","-o, --ssh-option=OPTION"); 473 printf(" %s\n", _("Tell ssh to use this configfile [optional]"));
452 printf (" %s\n", _("Call ssh with '-o OPTION' (may be used multiple times) [optional]")); 474 printf(" %s\n", "-q, --quiet");
453 printf (" %s\n","-F, --configfile"); 475 printf(" %s\n", _("Tell ssh to suppress warning and diagnostic messages [optional]"));
454 printf (" %s\n", _("Tell ssh to use this configfile [optional]")); 476 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
455 printf (" %s\n","-q, --quiet"); 477 printf(" %s\n", "-U, --unknown-timeout");
456 printf (" %s\n", _("Tell ssh to suppress warning and diagnostic messages [optional]")); 478 printf(" %s\n", _("Make connection problems return UNKNOWN instead of CRITICAL"));
457 printf (UT_WARN_CRIT); 479 printf(UT_VERBOSE);
458 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 480 printf("\n");
459 printf (" %s\n","-U, --unknown-timeout"); 481 printf(" %s\n", _("The most common mode of use is to refer to a local identity file with"));
460 printf (" %s\n", _("Make connection problems return UNKNOWN instead of CRITICAL")); 482 printf(" %s\n", _("the '-i' option. In this mode, the identity pair should have a null"));
461 printf (UT_VERBOSE); 483 printf(" %s\n", _("passphrase and the public key should be listed in the authorized_keys"));
484 printf(" %s\n", _("file of the remote host. Usually the key will be restricted to running"));
485 printf(" %s\n", _("only one command on the remote server. If the remote SSH server tracks"));
486 printf(" %s\n", _("invocation arguments, the one remote program may be an agent that can"));
487 printf(" %s\n", _("execute additional commands as proxy"));
462 printf("\n"); 488 printf("\n");
463 printf (" %s\n", _("The most common mode of use is to refer to a local identity file with")); 489 printf(" %s\n", _("To use passive mode, provide multiple '-C' options, and provide"));
464 printf (" %s\n", _("the '-i' option. In this mode, the identity pair should have a null")); 490 printf(" %s\n", _("all of -O, -s, and -n options (servicelist order must match '-C'options)"));
465 printf (" %s\n", _("passphrase and the public key should be listed in the authorized_keys")); 491 printf("\n");
466 printf (" %s\n", _("file of the remote host. Usually the key will be restricted to running")); 492 printf("%s\n", _("Examples:"));
467 printf (" %s\n", _("only one command on the remote server. If the remote SSH server tracks")); 493 printf(" %s\n", "$ check_by_ssh -H localhost -n lh -s c1:c2:c3 -C uptime -C uptime -C uptime -O /tmp/foo");
468 printf (" %s\n", _("invocation arguments, the one remote program may be an agent that can")); 494 printf(" %s\n", "$ cat /tmp/foo");
469 printf (" %s\n", _("execute additional commands as proxy")); 495 printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c1;0; up 2 days");
470 printf("\n"); 496 printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c2;0; up 2 days");
471 printf (" %s\n", _("To use passive mode, provide multiple '-C' options, and provide")); 497 printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c3;0; up 2 days");
472 printf (" %s\n", _("all of -O, -s, and -n options (servicelist order must match '-C'options)"));
473 printf ("\n");
474 printf ("%s\n", _("Examples:"));
475 printf (" %s\n", "$ check_by_ssh -H localhost -n lh -s c1:c2:c3 -C uptime -C uptime -C uptime -O /tmp/foo");
476 printf (" %s\n", "$ cat /tmp/foo");
477 printf (" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c1;0; up 2 days");
478 printf (" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c2;0; up 2 days");
479 printf (" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c3;0; up 2 days");
480 498
481 printf(UT_SUPPORT); 499 printf(UT_SUPPORT);
482} 500}
483 501
484 502void print_usage(void) {
485 503 printf("%s\n", _("Usage:"));
486void 504 printf(" %s -H <host> -C <command> [-fqvU] [-1|-2] [-4|-6]\n"
487print_usage (void) 505 " [-S [lines]] [-E [lines]] [-W] [-t timeout] [-i identity]\n"
488{ 506 " [-l user] [-n name] [-s servicelist] [-O outputfile]\n"
489 printf ("%s\n", _("Usage:")); 507 " [-p port] [-o ssh-option] [-F configfile]\n",
490 printf (" %s -H <host> -C <command> [-fqvU] [-1|-2] [-4|-6]\n" 508 progname);
491 " [-S [lines]] [-E [lines]] [-W] [-t timeout] [-i identity]\n"
492 " [-l user] [-n name] [-s servicelist] [-O outputfile]\n"
493 " [-p port] [-o ssh-option] [-F configfile]\n",
494 progname);
495} 509}
diff --git a/plugins/check_by_ssh.d/config.h b/plugins/check_by_ssh.d/config.h
new file mode 100644
index 00000000..05435def
--- /dev/null
+++ b/plugins/check_by_ssh.d/config.h
@@ -0,0 +1,56 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6typedef struct {
7 int commargc;
8 char **commargv;
9} command_construct;
10
11typedef struct {
12 char *hostname;
13 char *host_shortname;
14
15 char **service;
16 unsigned int number_of_services;
17
18 unsigned int commands; // Not needed during actual test run
19 char *remotecmd;
20
21 command_construct cmd;
22
23 bool unknown_timeout;
24 bool warn_on_stderr;
25 int skip_stdout;
26 int skip_stderr;
27 bool passive;
28 char *outputfile;
29} check_by_ssh_config;
30
31check_by_ssh_config check_by_ssh_config_init() {
32 check_by_ssh_config tmp = {
33 .hostname = NULL,
34 .host_shortname = NULL,
35
36 .service = NULL,
37 .number_of_services = 0,
38
39 .commands = 0,
40 .remotecmd = "",
41
42 .cmd =
43 {
44 .commargc = 0,
45 .commargv = NULL,
46 },
47
48 .unknown_timeout = false,
49 .warn_on_stderr = false,
50 .skip_stderr = 0,
51 .skip_stdout = 0,
52 .passive = false,
53 .outputfile = NULL,
54 };
55 return tmp;
56}
diff --git a/plugins/check_cluster.c b/plugins/check_cluster.c
index e1ede9f7..9b695499 100644
--- a/plugins/check_cluster.c
+++ b/plugins/check_cluster.c
@@ -1,92 +1,82 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* check_cluster.c - Host and Service Cluster Plugin for Monitoring 3 * check_cluster.c - Host and Service Cluster Plugin for Monitoring
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2004 Ethan Galstad (nagios@nagios.org) 6 * Copyright (c) 2000-2004 Ethan Galstad (nagios@nagios.org)
7* Copyright (c) 2007 Monitoring Plugins Development Team 7 * Copyright (c) 2007-2024 Monitoring Plugins Development Team
8* 8 *
9* This program is free software: you can redistribute it and/or modify 9 * This program is free software: you can redistribute it and/or modify
10* it under the terms of the GNU General Public License as published by 10 * it under the terms of the GNU General Public License as published by
11* the Free Software Foundation, either version 3 of the License, or 11 * the Free Software Foundation, either version 3 of the License, or
12* (at your option) any later version. 12 * (at your option) any later version.
13* 13 *
14* This program is distributed in the hope that it will be useful, 14 * This program is distributed in the hope that it will be useful,
15* but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17* GNU General Public License for more details. 17 * GNU General Public License for more details.
18* 18 *
19* You should have received a copy of the GNU General Public License 19 * You should have received a copy of the GNU General Public License
20* along with this program. If not, see <http://www.gnu.org/licenses/>. 20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21* 21 *
22* 22 *
23*****************************************************************************/ 23 *****************************************************************************/
24 24
25const char *progname = "check_cluster"; 25const char *progname = "check_cluster";
26const char *copyright = "2000-2007"; 26const char *copyright = "2000-2024";
27const char *email = "devel@monitoring-plugins.org"; 27const char *email = "devel@monitoring-plugins.org";
28 28
29#include "common.h" 29#include "common.h"
30#include "utils.h" 30#include "utils.h"
31#include "utils_base.h" 31#include "utils_base.h"
32#include "check_cluster.d/config.h"
32 33
33#define CHECK_SERVICES 1 34static void print_help(void);
34#define CHECK_HOSTS 2 35void print_usage(void);
35 36
36void print_help (void); 37static int verbose = 0;
37void print_usage (void);
38 38
39int total_services_ok=0; 39typedef struct {
40int total_services_warning=0; 40 int errorcode;
41int total_services_unknown=0; 41 check_cluster_config config;
42int total_services_critical=0; 42} check_cluster_config_wrapper;
43static check_cluster_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
43 44
44int total_hosts_up=0; 45int main(int argc, char **argv) {
45int total_hosts_down=0; 46 setlocale(LC_ALL, "");
46int total_hosts_unreachable=0; 47 bindtextdomain(PACKAGE, LOCALEDIR);
47 48 textdomain(PACKAGE);
48char *warn_threshold;
49char *crit_threshold;
50
51int check_type=CHECK_SERVICES;
52
53char *data_vals=NULL;
54char *label=NULL;
55
56int verbose=0;
57
58int process_arguments(int,char **);
59
60
61
62int main(int argc, char **argv){
63 char *ptr;
64 int data_val;
65 int return_code=STATE_OK;
66 thresholds *thresholds = NULL;
67
68 setlocale (LC_ALL, "");
69 bindtextdomain (PACKAGE, LOCALEDIR);
70 textdomain (PACKAGE);
71 49
72 /* Parse extra opts if any */ 50 /* Parse extra opts if any */
73 argv=np_extra_opts(&argc, argv, progname); 51 argv = np_extra_opts(&argc, argv, progname);
74 52
75 if(process_arguments(argc,argv)==ERROR) 53 check_cluster_config_wrapper tmp_config = process_arguments(argc, argv);
54 if (tmp_config.errorcode == ERROR) {
76 usage(_("Could not parse arguments")); 55 usage(_("Could not parse arguments"));
56 }
57
58 const check_cluster_config config = tmp_config.config;
77 59
78 /* Initialize the thresholds */ 60 /* Initialize the thresholds */
79 set_thresholds(&thresholds, warn_threshold, crit_threshold); 61 if (verbose) {
80 if(verbose) 62 print_thresholds("check_cluster", config.thresholds);
81 print_thresholds("check_cluster", thresholds); 63 }
82 64
65 int data_val;
66 int total_services_ok = 0;
67 int total_services_warning = 0;
68 int total_services_unknown = 0;
69 int total_services_critical = 0;
70 int total_hosts_up = 0;
71 int total_hosts_down = 0;
72 int total_hosts_unreachable = 0;
83 /* check the data values */ 73 /* check the data values */
84 for(ptr=strtok(data_vals,",");ptr!=NULL;ptr=strtok(NULL,",")){ 74 for (char *ptr = strtok(config.data_vals, ","); ptr != NULL; ptr = strtok(NULL, ",")) {
85 75
86 data_val=atoi(ptr); 76 data_val = atoi(ptr);
87 77
88 if(check_type==CHECK_SERVICES){ 78 if (config.check_type == CHECK_SERVICES) {
89 switch(data_val){ 79 switch (data_val) {
90 case 0: 80 case 0:
91 total_services_ok++; 81 total_services_ok++;
92 break; 82 break;
@@ -101,10 +91,9 @@ int main(int argc, char **argv){
101 break; 91 break;
102 default: 92 default:
103 break; 93 break;
104 } 94 }
105 } 95 } else {
106 else{ 96 switch (data_val) {
107 switch(data_val){
108 case 0: 97 case 0:
109 total_hosts_up++; 98 total_hosts_up++;
110 break; 99 break;
@@ -116,125 +105,117 @@ int main(int argc, char **argv){
116 break; 105 break;
117 default: 106 default:
118 break; 107 break;
119 } 108 }
120 } 109 }
121 } 110 }
122
123 111
112 int return_code = STATE_OK;
124 /* return the status of the cluster */ 113 /* return the status of the cluster */
125 if(check_type==CHECK_SERVICES){ 114 if (config.check_type == CHECK_SERVICES) {
126 return_code=get_status(total_services_warning+total_services_unknown+total_services_critical, thresholds); 115 return_code = get_status(total_services_warning + total_services_unknown + total_services_critical, config.thresholds);
127 printf("CLUSTER %s: %s: %d ok, %d warning, %d unknown, %d critical\n", 116 printf("CLUSTER %s: %s: %d ok, %d warning, %d unknown, %d critical\n", state_text(return_code),
128 state_text(return_code), (label==NULL)?"Service cluster":label, 117 (config.label == NULL) ? "Service cluster" : config.label, total_services_ok, total_services_warning, total_services_unknown,
129 total_services_ok,total_services_warning, 118 total_services_critical);
130 total_services_unknown,total_services_critical); 119 } else {
131 } 120 return_code = get_status(total_hosts_down + total_hosts_unreachable, config.thresholds);
132 else{ 121 printf("CLUSTER %s: %s: %d up, %d down, %d unreachable\n", state_text(return_code),
133 return_code=get_status(total_hosts_down+total_hosts_unreachable, thresholds); 122 (config.label == NULL) ? "Host cluster" : config.label, total_hosts_up, total_hosts_down, total_hosts_unreachable);
134 printf("CLUSTER %s: %s: %d up, %d down, %d unreachable\n",
135 state_text(return_code), (label==NULL)?"Host cluster":label,
136 total_hosts_up,total_hosts_down,total_hosts_unreachable);
137 } 123 }
138 124
139 return return_code; 125 exit(return_code);
140} 126}
141 127
128check_cluster_config_wrapper process_arguments(int argc, char **argv) {
129 static struct option longopts[] = {{"data", required_argument, 0, 'd'}, {"warning", required_argument, 0, 'w'},
130 {"critical", required_argument, 0, 'c'}, {"label", required_argument, 0, 'l'},
131 {"host", no_argument, 0, 'h'}, {"service", no_argument, 0, 's'},
132 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
133 {"help", no_argument, 0, 'H'}, {0, 0, 0, 0}};
142 134
143 135 check_cluster_config_wrapper result = {
144int process_arguments(int argc, char **argv){ 136 .errorcode = OK,
145 int c; 137 .config = check_cluster_config_init(),
146 char *ptr;
147 int option=0;
148 static struct option longopts[]={
149 {"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 {0,0,0,0}
159 }; 138 };
160 139
161 /* no options were supplied */ 140 /* no options were supplied */
162 if(argc<2) 141 if (argc < 2) {
163 return ERROR; 142 result.errorcode = ERROR;
164 143 return result;
165 while(1){ 144 }
166 145
167 c=getopt_long(argc,argv,"hHsvVw:c:d:l:",longopts,&option); 146 int option = 0;
147 char *warn_threshold = NULL;
148 char *crit_threshold = NULL;
149 while (true) {
150 int option_index = getopt_long(argc, argv, "hHsvVw:c:d:l:", longopts, &option);
168 151
169 if(c==-1 || c==EOF || c==1) 152 if (option_index == -1 || option_index == EOF || option_index == 1) {
170 break; 153 break;
154 }
171 155
172 switch(c){ 156 switch (option_index) {
173
174 case 'h': /* host cluster */ 157 case 'h': /* host cluster */
175 check_type=CHECK_HOSTS; 158 result.config.check_type = CHECK_HOSTS;
176 break; 159 break;
177
178 case 's': /* service cluster */ 160 case 's': /* service cluster */
179 check_type=CHECK_SERVICES; 161 result.config.check_type = CHECK_SERVICES;
180 break; 162 break;
181
182 case 'w': /* warning threshold */ 163 case 'w': /* warning threshold */
183 warn_threshold = strdup(optarg); 164 warn_threshold = strdup(optarg);
184 break; 165 break;
185
186 case 'c': /* warning threshold */ 166 case 'c': /* warning threshold */
187 crit_threshold = strdup(optarg); 167 crit_threshold = strdup(optarg);
188 break; 168 break;
189
190 case 'd': /* data values */ 169 case 'd': /* data values */
191 data_vals=(char *)strdup(optarg); 170 result.config.data_vals = strdup(optarg);
192 /* validate data */ 171 /* validate data */
193 for (ptr=data_vals;ptr!=NULL;ptr+=2){ 172 for (char *ptr = result.config.data_vals; ptr != NULL; ptr += 2) {
194 if (ptr[0]<'0' || ptr[0]>'3') 173 if (ptr[0] < '0' || ptr[0] > '3') {
195 return ERROR; 174 result.errorcode = ERROR;
196 if (ptr[1]=='\0') 175 return result;
176 }
177 if (ptr[1] == '\0') {
197 break; 178 break;
198 if (ptr[1]!=',') 179 }
199 return ERROR; 180 if (ptr[1] != ',') {
181 result.errorcode = ERROR;
182 return result;
183 }
200 } 184 }
201 break; 185 break;
202
203 case 'l': /* text label */ 186 case 'l': /* text label */
204 label=(char *)strdup(optarg); 187 result.config.label = strdup(optarg);
205 break; 188 break;
206
207 case 'v': /* verbose */ 189 case 'v': /* verbose */
208 verbose++; 190 verbose++;
209 break; 191 break;
210
211 case 'V': /* version */ 192 case 'V': /* version */
212 print_revision (progname, NP_VERSION); 193 print_revision(progname, NP_VERSION);
213 exit (STATE_UNKNOWN); 194 exit(STATE_UNKNOWN);
214 break; 195 break;
215
216 case 'H': /* help */ 196 case 'H': /* help */
217 print_help(); 197 print_help();
218 exit(STATE_UNKNOWN); 198 exit(STATE_UNKNOWN);
219 break; 199 break;
220
221 default: 200 default:
222 return ERROR; 201 result.errorcode = ERROR;
202 return result;
223 break; 203 break;
224 } 204 }
225 } 205 }
226 206
227 if(data_vals==NULL) 207 if (result.config.data_vals == NULL) {
228 return ERROR; 208 result.errorcode = ERROR;
209 return result;
210 }
229 211
230 return OK; 212 set_thresholds(&result.config.thresholds, warn_threshold, crit_threshold);
213 return result;
231} 214}
232 215
233void 216void print_help(void) {
234print_help(void)
235{
236 print_revision(progname, NP_VERSION); 217 print_revision(progname, NP_VERSION);
237 printf ("Copyright (c) 2000-2004 Ethan Galstad (nagios@nagios.org)\n"); 218 printf("Copyright (c) 2000-2004 Ethan Galstad (nagios@nagios.org)\n");
238 printf(COPYRIGHT, copyright, email); 219 printf(COPYRIGHT, copyright, email);
239 220
240 printf(_("Host/Service Cluster Plugin for Monitoring")); 221 printf(_("Host/Service Cluster Plugin for Monitoring"));
@@ -245,21 +226,21 @@ print_help(void)
245 printf("\n"); 226 printf("\n");
246 printf("%s\n", _("Options:")); 227 printf("%s\n", _("Options:"));
247 printf(UT_EXTRA_OPTS); 228 printf(UT_EXTRA_OPTS);
248 printf (" %s\n", "-s, --service"); 229 printf(" %s\n", "-s, --service");
249 printf (" %s\n", _("Check service cluster status")); 230 printf(" %s\n", _("Check service cluster status"));
250 printf (" %s\n", "-h, --host"); 231 printf(" %s\n", "-h, --host");
251 printf (" %s\n", _("Check host cluster status")); 232 printf(" %s\n", _("Check host cluster status"));
252 printf (" %s\n", "-l, --label=STRING"); 233 printf(" %s\n", "-l, --label=STRING");
253 printf (" %s\n", _("Optional prepended text output (i.e. \"Host cluster\")")); 234 printf(" %s\n", _("Optional prepended text output (i.e. \"Host cluster\")"));
254 printf (" %s\n", "-w, --warning=THRESHOLD"); 235 printf(" %s\n", "-w, --warning=THRESHOLD");
255 printf (" %s\n", _("Specifies the range of hosts or services in cluster that must be in a")); 236 printf(" %s\n", _("Specifies the range of hosts or services in cluster that must be in a"));
256 printf (" %s\n", _("non-OK state in order to return a WARNING status level")); 237 printf(" %s\n", _("non-OK state in order to return a WARNING status level"));
257 printf (" %s\n", "-c, --critical=THRESHOLD"); 238 printf(" %s\n", "-c, --critical=THRESHOLD");
258 printf (" %s\n", _("Specifies the range of hosts or services in cluster that must be in a")); 239 printf(" %s\n", _("Specifies the range of hosts or services in cluster that must be in a"));
259 printf (" %s\n", _("non-OK state in order to return a CRITICAL status level")); 240 printf(" %s\n", _("non-OK state in order to return a CRITICAL status level"));
260 printf (" %s\n", "-d, --data=LIST"); 241 printf(" %s\n", "-d, --data=LIST");
261 printf (" %s\n", _("The status codes of the hosts or services in the cluster, separated by")); 242 printf(" %s\n", _("The status codes of the hosts or services in the cluster, separated by"));
262 printf (" %s\n", _("commas")); 243 printf(" %s\n", _("commas"));
263 244
264 printf(UT_VERBOSE); 245 printf(UT_VERBOSE);
265 246
@@ -267,23 +248,18 @@ print_help(void)
267 printf("%s\n", _("Notes:")); 248 printf("%s\n", _("Notes:"));
268 printf(UT_THRESHOLDS_NOTES); 249 printf(UT_THRESHOLDS_NOTES);
269 250
270 printf ("\n"); 251 printf("\n");
271 printf ("%s\n", _("Examples:")); 252 printf("%s\n", _("Examples:"));
272 printf (" %s\n", "check_cluster -s -d 2,0,2,0 -c @3:"); 253 printf(" %s\n", "check_cluster -s -d 2,0,2,0 -c @3:");
273 printf (" %s\n", _("Will alert critical if there are 3 or more service data points in a non-OK") ); 254 printf(" %s\n", _("Will alert critical if there are 3 or more service data points in a non-OK"));
274 printf (" %s\n", _("state.") ); 255 printf(" %s\n", _("state."));
275 256
276 printf(UT_SUPPORT); 257 printf(UT_SUPPORT);
277} 258}
278 259
279 260void print_usage(void) {
280void
281print_usage(void)
282{
283 261
284 printf("%s\n", _("Usage:")); 262 printf("%s\n", _("Usage:"));
285 printf(" %s (-s | -h) -d val1[,val2,...,valn] [-l label]\n", progname); 263 printf(" %s (-s | -h) -d val1[,val2,...,valn] [-l label]\n", progname);
286 printf("[-w threshold] [-c threshold] [-v] [--help]\n"); 264 printf("[-w threshold] [-c threshold] [-v] [--help]\n");
287
288} 265}
289
diff --git a/plugins/check_cluster.d/config.h b/plugins/check_cluster.d/config.h
new file mode 100644
index 00000000..fc386415
--- /dev/null
+++ b/plugins/check_cluster.d/config.h
@@ -0,0 +1,27 @@
1#pragma once
2
3#include "../../config.h"
4#include "../../lib/thresholds.h"
5#include <stddef.h>
6
7enum {
8 CHECK_SERVICES = 1,
9 CHECK_HOSTS = 2
10};
11
12typedef struct {
13 char *data_vals;
14 thresholds *thresholds;
15 int check_type;
16 char *label;
17} check_cluster_config;
18
19check_cluster_config check_cluster_config_init() {
20 check_cluster_config tmp = {
21 .data_vals = NULL,
22 .thresholds = NULL,
23 .check_type = CHECK_SERVICES,
24 .label = NULL,
25 };
26 return tmp;
27}
diff --git a/plugins/check_curl.c b/plugins/check_curl.c
index e25d7a79..748201e8 100644
--- a/plugins/check_curl.c
+++ b/plugins/check_curl.c
@@ -1,40 +1,40 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_curl plugin 3 * Monitoring check_curl plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2019 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_curl plugin 10 * This file contains the check_curl 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* This plugin uses functions from the curl library, see 17 * This plugin uses functions from the curl library, see
18* http://curl.haxx.se 18 * http://curl.haxx.se
19* 19 *
20* This program is free software: you can redistribute it and/or modify 20 * This program is free software: you can redistribute it and/or modify
21* it under the terms of the GNU General Public License as published by 21 * it under the terms of the GNU General Public License as published by
22* the Free Software Foundation, either version 3 of the License, or 22 * the Free Software Foundation, either version 3 of the License, or
23* (at your option) any later version. 23 * (at your option) any later version.
24* 24 *
25* This program is distributed in the hope that it will be useful, 25 * This program is distributed in the hope that it will be useful,
26* but WITHOUT ANY WARRANTY; without even the implied warranty of 26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28* GNU General Public License for more details. 28 * GNU General Public License for more details.
29* 29 *
30* You should have received a copy of the GNU General Public License 30 * You should have received a copy of the GNU General Public License
31* along with this program. If not, see <http://www.gnu.org/licenses/>. 31 * along with this program. If not, see <http://www.gnu.org/licenses/>.
32* 32 *
33* 33 *
34*****************************************************************************/ 34 *****************************************************************************/
35const char *progname = "check_curl"; 35const char *progname = "check_curl";
36 36
37const char *copyright = "2006-2019"; 37const char *copyright = "2006-2024";
38const char *email = "devel@monitoring-plugins.org"; 38const char *email = "devel@monitoring-plugins.org";
39 39
40#include <stdbool.h> 40#include <stdbool.h>
@@ -44,7 +44,7 @@ const char *email = "devel@monitoring-plugins.org";
44#include "utils.h" 44#include "utils.h"
45 45
46#ifndef LIBCURL_PROTOCOL_HTTP 46#ifndef LIBCURL_PROTOCOL_HTTP
47#error libcurl compiled without HTTP support, compiling check_curl plugin does not makes a lot of sense 47# error libcurl compiled without HTTP support, compiling check_curl plugin does not makes a lot of sense
48#endif 48#endif
49 49
50#include "curl/curl.h" 50#include "curl/curl.h"
@@ -58,7 +58,7 @@ const char *email = "devel@monitoring-plugins.org";
58#include <netinet/in.h> 58#include <netinet/in.h>
59 59
60#if defined(HAVE_SSL) && defined(USE_OPENSSL) 60#if defined(HAVE_SSL) && defined(USE_OPENSSL)
61#include <openssl/opensslv.h> 61# include <openssl/opensslv.h>
62#endif 62#endif
63 63
64#include <netdb.h> 64#include <netdb.h>
@@ -66,1092 +66,1052 @@ const char *email = "devel@monitoring-plugins.org";
66#define MAKE_LIBCURL_VERSION(major, minor, patch) ((major)*0x10000 + (minor)*0x100 + (patch)) 66#define MAKE_LIBCURL_VERSION(major, minor, patch) ((major)*0x10000 + (minor)*0x100 + (patch))
67 67
68#define DEFAULT_BUFFER_SIZE 2048 68#define DEFAULT_BUFFER_SIZE 2048
69#define DEFAULT_SERVER_URL "/" 69#define DEFAULT_SERVER_URL "/"
70#define HTTP_EXPECT "HTTP/" 70#define HTTP_EXPECT "HTTP/"
71#define INET_ADDR_MAX_SIZE INET6_ADDRSTRLEN 71#define INET_ADDR_MAX_SIZE INET6_ADDRSTRLEN
72enum { 72enum {
73 MAX_IPV4_HOSTLENGTH = 255, 73 MAX_IPV4_HOSTLENGTH = 255,
74 HTTP_PORT = 80, 74 HTTP_PORT = 80,
75 HTTPS_PORT = 443, 75 HTTPS_PORT = 443,
76 MAX_PORT = 65535, 76 MAX_PORT = 65535,
77 DEFAULT_MAX_REDIRS = 15 77 DEFAULT_MAX_REDIRS = 15
78}; 78};
79 79
80enum { 80enum {
81 STICKY_NONE = 0, 81 STICKY_NONE = 0,
82 STICKY_HOST = 1, 82 STICKY_HOST = 1,
83 STICKY_PORT = 2 83 STICKY_PORT = 2
84}; 84};
85 85
86enum { 86enum {
87 FOLLOW_HTTP_CURL = 0, 87 FOLLOW_HTTP_CURL = 0,
88 FOLLOW_LIBCURL = 1 88 FOLLOW_LIBCURL = 1
89}; 89};
90 90
91/* for buffers for header and body */ 91/* for buffers for header and body */
92typedef struct { 92typedef struct {
93 char *buf; 93 char *buf;
94 size_t buflen; 94 size_t buflen;
95 size_t bufsize; 95 size_t bufsize;
96} curlhelp_write_curlbuf; 96} curlhelp_write_curlbuf;
97 97
98/* for buffering the data sent in PUT */ 98/* for buffering the data sent in PUT */
99typedef struct { 99typedef struct {
100 char *buf; 100 char *buf;
101 size_t buflen; 101 size_t buflen;
102 off_t pos; 102 off_t pos;
103} curlhelp_read_curlbuf; 103} curlhelp_read_curlbuf;
104 104
105/* for parsing the HTTP status line */ 105/* for parsing the HTTP status line */
106typedef struct { 106typedef struct {
107 int http_major; /* major version of the protocol, always 1 (HTTP/0.9 107 int http_major; /* major version of the protocol, always 1 (HTTP/0.9
108 * never reached the big internet most likely) */ 108 * never reached the big internet most likely) */
109 int http_minor; /* minor version of the protocol, usually 0 or 1 */ 109 int http_minor; /* minor version of the protocol, usually 0 or 1 */
110 int http_code; /* HTTP return code as in RFC 2145 */ 110 int http_code; /* HTTP return code as in RFC 2145 */
111 int http_subcode; /* Microsoft IIS extension, HTTP subcodes, see 111 int http_subcode; /* Microsoft IIS extension, HTTP subcodes, see
112 * http://support.microsoft.com/kb/318380/en-us */ 112 * http://support.microsoft.com/kb/318380/en-us */
113 const char *msg; /* the human readable message */ 113 const char *msg; /* the human readable message */
114 char *first_line; /* a copy of the first line */ 114 char *first_line; /* a copy of the first line */
115} curlhelp_statusline; 115} curlhelp_statusline;
116 116
117/* to know the underlying SSL library used by libcurl */ 117/* to know the underlying SSL library used by libcurl */
118typedef enum curlhelp_ssl_library { 118typedef enum curlhelp_ssl_library {
119 CURLHELP_SSL_LIBRARY_UNKNOWN, 119 CURLHELP_SSL_LIBRARY_UNKNOWN,
120 CURLHELP_SSL_LIBRARY_OPENSSL, 120 CURLHELP_SSL_LIBRARY_OPENSSL,
121 CURLHELP_SSL_LIBRARY_LIBRESSL, 121 CURLHELP_SSL_LIBRARY_LIBRESSL,
122 CURLHELP_SSL_LIBRARY_GNUTLS, 122 CURLHELP_SSL_LIBRARY_GNUTLS,
123 CURLHELP_SSL_LIBRARY_NSS 123 CURLHELP_SSL_LIBRARY_NSS
124} curlhelp_ssl_library; 124} curlhelp_ssl_library;
125 125
126enum { 126enum {
127 REGS = 2, 127 REGS = 2,
128 MAX_RE_SIZE = 1024 128 MAX_RE_SIZE = 1024
129}; 129};
130#include "regex.h" 130#include "regex.h"
131regex_t preg; 131static regex_t preg;
132regmatch_t pmatch[REGS]; 132static regmatch_t pmatch[REGS];
133char regexp[MAX_RE_SIZE]; 133static char regexp[MAX_RE_SIZE];
134int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE; 134static int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
135int errcode; 135static int errcode;
136bool invert_regex = false; 136static bool invert_regex = false;
137int state_regex = STATE_CRITICAL; 137static int state_regex = STATE_CRITICAL;
138 138
139char *server_address = NULL; 139static char *server_address = NULL;
140char *host_name = NULL; 140static char *host_name = NULL;
141char *server_url = 0; 141static char *server_url = 0;
142char server_ip[DEFAULT_BUFFER_SIZE]; 142static struct curl_slist *server_ips = NULL;
143struct curl_slist *server_ips = NULL; 143static bool specify_port = false;
144bool specify_port = false; 144static unsigned short server_port = HTTP_PORT;
145unsigned short server_port = HTTP_PORT; 145static unsigned short virtual_port = 0;
146unsigned short virtual_port = 0; 146static int host_name_length;
147int host_name_length; 147static char output_header_search[30] = "";
148char output_header_search[30] = ""; 148static char output_string_search[30] = "";
149char output_string_search[30] = ""; 149static char *warning_thresholds = NULL;
150char *warning_thresholds = NULL; 150static char *critical_thresholds = NULL;
151char *critical_thresholds = NULL; 151static int days_till_exp_warn, days_till_exp_crit;
152int days_till_exp_warn, days_till_exp_crit; 152static thresholds *thlds;
153thresholds *thlds; 153static char user_agent[DEFAULT_BUFFER_SIZE];
154char user_agent[DEFAULT_BUFFER_SIZE]; 154static int verbose = 0;
155int verbose = 0; 155static bool show_extended_perfdata = false;
156bool show_extended_perfdata = false; 156static bool show_body = false;
157bool show_body = false; 157static int min_page_len = 0;
158int min_page_len = 0; 158static int max_page_len = 0;
159int max_page_len = 0; 159static int redir_depth = 0;
160int redir_depth = 0; 160static int max_depth = DEFAULT_MAX_REDIRS;
161int max_depth = DEFAULT_MAX_REDIRS; 161static char *http_method = NULL;
162char *http_method = NULL; 162static char *http_post_data = NULL;
163char *http_post_data = NULL; 163static char *http_content_type = NULL;
164char *http_content_type = NULL; 164static CURL *curl;
165CURL *curl; 165static bool curl_global_initialized = false;
166bool curl_global_initialized = false; 166static bool curl_easy_initialized = false;
167bool curl_easy_initialized = false; 167static struct curl_slist *header_list = NULL;
168struct curl_slist *header_list = NULL; 168static bool body_buf_initialized = false;
169bool body_buf_initialized = false; 169static curlhelp_write_curlbuf body_buf;
170curlhelp_write_curlbuf body_buf; 170static bool header_buf_initialized = false;
171bool header_buf_initialized = false; 171static curlhelp_write_curlbuf header_buf;
172curlhelp_write_curlbuf header_buf; 172static bool status_line_initialized = false;
173bool status_line_initialized = false; 173static curlhelp_statusline status_line;
174curlhelp_statusline status_line; 174static bool put_buf_initialized = false;
175bool put_buf_initialized = false; 175static curlhelp_read_curlbuf put_buf;
176curlhelp_read_curlbuf put_buf; 176static char http_header[DEFAULT_BUFFER_SIZE];
177char http_header[DEFAULT_BUFFER_SIZE]; 177static long code;
178long code; 178static long socket_timeout = DEFAULT_SOCKET_TIMEOUT;
179long socket_timeout = DEFAULT_SOCKET_TIMEOUT; 179static double total_time;
180double total_time; 180static double time_connect;
181double time_connect; 181static double time_appconnect;
182double time_appconnect; 182static double time_headers;
183double time_headers; 183static double time_firstbyte;
184double time_firstbyte; 184static char errbuf[MAX_INPUT_BUFFER];
185char errbuf[MAX_INPUT_BUFFER]; 185static CURLcode res;
186CURLcode res; 186static char url[DEFAULT_BUFFER_SIZE];
187char url[DEFAULT_BUFFER_SIZE]; 187static char msg[DEFAULT_BUFFER_SIZE];
188char msg[DEFAULT_BUFFER_SIZE]; 188static char perfstring[DEFAULT_BUFFER_SIZE];
189char perfstring[DEFAULT_BUFFER_SIZE]; 189static char header_expect[MAX_INPUT_BUFFER] = "";
190char header_expect[MAX_INPUT_BUFFER] = ""; 190static char string_expect[MAX_INPUT_BUFFER] = "";
191char string_expect[MAX_INPUT_BUFFER] = ""; 191static char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
192char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT; 192static int server_expect_yn = 0;
193int server_expect_yn = 0; 193static char user_auth[MAX_INPUT_BUFFER] = "";
194char user_auth[MAX_INPUT_BUFFER] = ""; 194static char proxy_auth[MAX_INPUT_BUFFER] = "";
195char proxy_auth[MAX_INPUT_BUFFER] = ""; 195static char **http_opt_headers;
196char **http_opt_headers; 196static int http_opt_headers_count = 0;
197int http_opt_headers_count = 0; 197static bool display_html = false;
198bool display_html = false; 198static int onredirect = STATE_OK;
199int onredirect = STATE_OK; 199static int followmethod = FOLLOW_HTTP_CURL;
200int followmethod = FOLLOW_HTTP_CURL; 200static int followsticky = STICKY_NONE;
201int followsticky = STICKY_NONE; 201static bool use_ssl = false;
202bool use_ssl = false; 202static bool check_cert = false;
203bool use_sni = true; 203static bool continue_after_check_cert = false;
204bool check_cert = false;
205bool continue_after_check_cert = false;
206typedef union { 204typedef union {
207 struct curl_slist* to_info; 205 struct curl_slist *to_info;
208 struct curl_certinfo* to_certinfo; 206 struct curl_certinfo *to_certinfo;
209} cert_ptr_union; 207} cert_ptr_union;
210cert_ptr_union cert_ptr; 208static cert_ptr_union cert_ptr;
211int ssl_version = CURL_SSLVERSION_DEFAULT; 209static int ssl_version = CURL_SSLVERSION_DEFAULT;
212char *client_cert = NULL; 210static char *client_cert = NULL;
213char *client_privkey = NULL; 211static char *client_privkey = NULL;
214char *ca_cert = NULL; 212static char *ca_cert = NULL;
215bool verify_peer_and_host = false; 213static bool verify_peer_and_host = false;
216bool is_openssl_callback = false; 214static bool is_openssl_callback = false;
215static bool add_sslctx_verify_fun = false;
217#if defined(HAVE_SSL) && defined(USE_OPENSSL) 216#if defined(HAVE_SSL) && defined(USE_OPENSSL)
218X509 *cert = NULL; 217static X509 *cert = NULL;
219#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */ 218#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
220bool no_body = false; 219static bool no_body = false;
221int maximum_age = -1; 220static int maximum_age = -1;
222int address_family = AF_UNSPEC; 221static int address_family = AF_UNSPEC;
223curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN; 222static curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
224int curl_http_version = CURL_HTTP_VERSION_NONE; 223static int curl_http_version = CURL_HTTP_VERSION_NONE;
225bool automatic_decompression = false; 224static bool automatic_decompression = false;
226char *cookie_jar_file = NULL; 225static char *cookie_jar_file = NULL;
227bool haproxy_protocol = false; 226static bool haproxy_protocol = false;
228 227
229bool process_arguments (int, char**); 228static bool process_arguments(int /*argc*/, char ** /*argv*/);
230void handle_curl_option_return_code (CURLcode res, const char* option); 229static void handle_curl_option_return_code(CURLcode res, const char *option);
231int check_http (void); 230static int check_http(void);
232void redir (curlhelp_write_curlbuf*); 231static void redir(curlhelp_write_curlbuf * /*header_buf*/);
233char *perfd_time (double microsec); 232static char *perfd_time(double elapsed_time);
234char *perfd_time_connect (double microsec); 233static char *perfd_time_connect(double elapsed_time_connect);
235char *perfd_time_ssl (double microsec); 234static char *perfd_time_ssl(double elapsed_time_ssl);
236char *perfd_time_firstbyte (double microsec); 235static char *perfd_time_firstbyte(double elapsed_time_firstbyte);
237char *perfd_time_headers (double microsec); 236static char *perfd_time_headers(double elapsed_time_headers);
238char *perfd_time_transfer (double microsec); 237static char *perfd_time_transfer(double elapsed_time_transfer);
239char *perfd_size (int page_len); 238static char *perfd_size(int page_len);
240void print_help (void); 239static void print_help(void);
241void print_usage (void); 240void print_usage(void);
242void print_curl_version (void); 241static void print_curl_version(void);
243int curlhelp_initwritebuffer (curlhelp_write_curlbuf*); 242static int curlhelp_initwritebuffer(curlhelp_write_curlbuf * /*buf*/);
244size_t curlhelp_buffer_write_callback(void*, size_t , size_t , void*); 243static size_t curlhelp_buffer_write_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/, void * /*stream*/);
245void curlhelp_freewritebuffer (curlhelp_write_curlbuf*); 244static void curlhelp_freewritebuffer(curlhelp_write_curlbuf * /*buf*/);
246int curlhelp_initreadbuffer (curlhelp_read_curlbuf *, const char *, size_t); 245static int curlhelp_initreadbuffer(curlhelp_read_curlbuf * /*buf*/, const char * /*data*/, size_t /*datalen*/);
247size_t curlhelp_buffer_read_callback(void *, size_t , size_t , void *); 246static size_t curlhelp_buffer_read_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/, void * /*stream*/);
248void curlhelp_freereadbuffer (curlhelp_read_curlbuf *); 247static void curlhelp_freereadbuffer(curlhelp_read_curlbuf * /*buf*/);
249curlhelp_ssl_library curlhelp_get_ssl_library (); 248static curlhelp_ssl_library curlhelp_get_ssl_library(void);
250const char* curlhelp_get_ssl_library_string (curlhelp_ssl_library); 249static const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library /*ssl_library*/);
251int net_noopenssl_check_certificate (cert_ptr_union*, int, int); 250int net_noopenssl_check_certificate(cert_ptr_union *, int, int);
252 251
253int curlhelp_parse_statusline (const char*, curlhelp_statusline *); 252static int curlhelp_parse_statusline(const char * /*buf*/, curlhelp_statusline * /*status_line*/);
254void curlhelp_free_statusline (curlhelp_statusline *); 253static void curlhelp_free_statusline(curlhelp_statusline * /*status_line*/);
255char *get_header_value (const struct phr_header* headers, const size_t nof_headers, const char* header); 254static char *get_header_value(const struct phr_header *headers, size_t nof_headers, const char *header);
256int check_document_dates (const curlhelp_write_curlbuf *, char (*msg)[DEFAULT_BUFFER_SIZE]); 255static int check_document_dates(const curlhelp_write_curlbuf * /*header_buf*/, char (*msg)[DEFAULT_BUFFER_SIZE]);
257int get_content_length (const curlhelp_write_curlbuf* header_buf, const curlhelp_write_curlbuf* body_buf); 256static int get_content_length(const curlhelp_write_curlbuf *header_buf, const curlhelp_write_curlbuf *body_buf);
258 257
259#if defined(HAVE_SSL) && defined(USE_OPENSSL) 258#if defined(HAVE_SSL) && defined(USE_OPENSSL)
260int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit); 259int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit);
261#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */ 260#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
262 261
263void remove_newlines (char *); 262static void test_file(char * /*path*/);
264void test_file (char *);
265 263
266int 264int main(int argc, char **argv) {
267main (int argc, char **argv) 265 int result = STATE_UNKNOWN;
268{
269 int result = STATE_UNKNOWN;
270 266
271 setlocale (LC_ALL, ""); 267 setlocale(LC_ALL, "");
272 bindtextdomain (PACKAGE, LOCALEDIR); 268 bindtextdomain(PACKAGE, LOCALEDIR);
273 textdomain (PACKAGE); 269 textdomain(PACKAGE);
274 270
275 /* Parse extra opts if any */ 271 /* Parse extra opts if any */
276 argv = np_extra_opts (&argc, argv, progname); 272 argv = np_extra_opts(&argc, argv, progname);
277 273
278 /* set defaults */ 274 /* set defaults */
279 snprintf( user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s, %s)", 275 snprintf(user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s, %s)", progname, NP_VERSION, VERSION, curl_version());
280 progname, NP_VERSION, VERSION, curl_version());
281 276
282 /* parse arguments */ 277 /* parse arguments */
283 if (process_arguments (argc, argv) == false) 278 if (process_arguments(argc, argv) == false)
284 usage4 (_("Could not parse arguments")); 279 usage4(_("Could not parse arguments"));
285 280
286 if (display_html) 281 if (display_html)
287 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", 282 printf("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", use_ssl ? "https" : "http", host_name ? host_name : server_address,
288 use_ssl ? "https" : "http", 283 virtual_port ? virtual_port : server_port, server_url);
289 host_name ? host_name : server_address,
290 virtual_port ? virtual_port : server_port,
291 server_url);
292 284
293 result = check_http (); 285 result = check_http();
294 return result; 286 return result;
295} 287}
296 288
297#ifdef HAVE_SSL 289#ifdef HAVE_SSL
298#ifdef USE_OPENSSL 290# ifdef USE_OPENSSL
299 291
300int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) 292int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) {
301{ 293 (void)preverify_ok;
302 (void) preverify_ok; 294 /* TODO: we get all certificates of the chain, so which ones
303 /* TODO: we get all certificates of the chain, so which ones 295 * should we test?
304 * should we test? 296 * TODO: is the last certificate always the server certificate?
305 * TODO: is the last certificate always the server certificate? 297 */
306 */ 298 cert = X509_STORE_CTX_get_current_cert(x509_ctx);
307 cert = X509_STORE_CTX_get_current_cert(x509_ctx); 299# if OPENSSL_VERSION_NUMBER >= 0x10100000L
308#if OPENSSL_VERSION_NUMBER >= 0x10100000L 300 X509_up_ref(cert);
309 X509_up_ref(cert); 301# endif
310#endif 302 if (verbose >= 2) {
311 if (verbose>=2) { 303 puts("* SSL verify callback with certificate:");
312 puts("* SSL verify callback with certificate:"); 304 X509_NAME *subject;
313 X509_NAME *subject, *issuer; 305 X509_NAME *issuer;
314 printf("* issuer:\n"); 306 printf("* issuer:\n");
315 issuer = X509_get_issuer_name( cert ); 307 issuer = X509_get_issuer_name(cert);
316 X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE); 308 X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE);
317 printf("* curl verify_callback:\n* subject:\n"); 309 printf("* curl verify_callback:\n* subject:\n");
318 subject = X509_get_subject_name( cert ); 310 subject = X509_get_subject_name(cert);
319 X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE); 311 X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE);
320 puts(""); 312 puts("");
321 } 313 }
322 return 1; 314 return 1;
323} 315}
324 316
325CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) 317CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) {
326{ 318 (void)curl; // ignore unused parameter
327 (void) curl; // ignore unused parameter 319 (void)parm; // ignore unused parameter
328 (void) parm; // ignore unused parameter 320 if (add_sslctx_verify_fun) {
329 SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, verify_callback); 321 SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, verify_callback);
322 }
330 323
331 return CURLE_OK; 324 // workaround for issue:
325 // OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0
326 // see discussion https://github.com/openssl/openssl/discussions/22690
327# ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
328 SSL_CTX_set_options(sslctx, SSL_OP_IGNORE_UNEXPECTED_EOF);
329# endif
330
331 return CURLE_OK;
332} 332}
333 333
334#endif /* USE_OPENSSL */ 334# endif /* USE_OPENSSL */
335#endif /* HAVE_SSL */ 335#endif /* HAVE_SSL */
336 336
337/* returns a string "HTTP/1.x" or "HTTP/2" */ 337/* returns a string "HTTP/1.x" or "HTTP/2" */
338static char *string_statuscode (int major, int minor) 338static char *string_statuscode(int major, int minor) {
339{ 339 static char buf[10];
340 static char buf[10]; 340
341 341 switch (major) {
342 switch (major) { 342 case 1:
343 case 1: 343 snprintf(buf, sizeof(buf), "HTTP/%d.%d", major, minor);
344 snprintf (buf, sizeof (buf), "HTTP/%d.%d", major, minor); 344 break;
345 break; 345 case 2:
346 case 2: 346 case 3:
347 case 3: 347 snprintf(buf, sizeof(buf), "HTTP/%d", major);
348 snprintf (buf, sizeof (buf), "HTTP/%d", major); 348 break;
349 break; 349 default:
350 default: 350 /* assuming here HTTP/N with N>=4 */
351 /* assuming here HTTP/N with N>=4 */ 351 snprintf(buf, sizeof(buf), "HTTP/%d", major);
352 snprintf (buf, sizeof (buf), "HTTP/%d", major); 352 break;
353 break; 353 }
354 } 354
355 355 return buf;
356 return buf;
357} 356}
358 357
359/* Checks if the server 'reply' is one of the expected 'statuscodes' */ 358/* Checks if the server 'reply' is one of the expected 'statuscodes' */
360static int 359static int expected_statuscode(const char *reply, const char *statuscodes) {
361expected_statuscode (const char *reply, const char *statuscodes) 360 char *expected;
362{ 361 char *code;
363 char *expected, *code; 362 int result = 0;
364 int result = 0; 363
365 364 if ((expected = strdup(statuscodes)) == NULL)
366 if ((expected = strdup (statuscodes)) == NULL) 365 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
367 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n")); 366
368 367 for (code = strtok(expected, ","); code != NULL; code = strtok(NULL, ","))
369 for (code = strtok (expected, ","); code != NULL; code = strtok (NULL, ",")) 368 if (strstr(reply, code) != NULL) {
370 if (strstr (reply, code) != NULL) { 369 result = 1;
371 result = 1; 370 break;
372 break; 371 }
373 } 372
374 373 free(expected);
375 free (expected); 374 return result;
376 return result;
377} 375}
378 376
379void 377void handle_curl_option_return_code(CURLcode res, const char *option) {
380handle_curl_option_return_code (CURLcode res, const char* option) 378 if (res != CURLE_OK) {
381{ 379 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Error while setting cURL option '%s': cURL returned %d - %s"), option, res,
382 if (res != CURLE_OK) { 380 curl_easy_strerror(res));
383 snprintf (msg, 381 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
384 DEFAULT_BUFFER_SIZE, 382 }
385 _("Error while setting cURL option '%s': cURL returned %d - %s"),
386 option,
387 res,
388 curl_easy_strerror(res));
389 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
390 }
391} 383}
392 384
393int 385int lookup_host(const char *host, char *buf, size_t buflen) {
394lookup_host (const char *host, char *buf, size_t buflen) 386 struct addrinfo hints, *res, *result;
395{ 387 char addrstr[100];
396 struct addrinfo hints, *res, *result; 388 size_t addrstr_len;
397 char addrstr[100]; 389 int errcode;
398 size_t addrstr_len; 390 void *ptr = {0};
399 int errcode; 391 size_t buflen_remaining = buflen - 1;
400 void *ptr = { 0 }; 392
401 size_t buflen_remaining = buflen - 1; 393 memset(&hints, 0, sizeof(hints));
402 394 hints.ai_family = address_family;
403 memset (&hints, 0, sizeof (hints)); 395 hints.ai_socktype = SOCK_STREAM;
404 hints.ai_family = address_family; 396 hints.ai_flags |= AI_CANONNAME;
405 hints.ai_socktype = SOCK_STREAM; 397
406 hints.ai_flags |= AI_CANONNAME; 398 errcode = getaddrinfo(host, NULL, &hints, &result);
407 399 if (errcode != 0)
408 errcode = getaddrinfo (host, NULL, &hints, &result); 400 return errcode;
409 if (errcode != 0) 401
410 return errcode; 402 strcpy(buf, "");
411 403 res = result;
412 strcpy(buf, ""); 404
413 res = result; 405 while (res) {
414 406 switch (res->ai_family) {
415 while (res) { 407 case AF_INET:
416 switch (res->ai_family) { 408 ptr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
417 case AF_INET: 409 break;
418 ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr; 410 case AF_INET6:
419 break; 411 ptr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
420 case AF_INET6: 412 break;
421 ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr; 413 }
422 break; 414
423 } 415 inet_ntop(res->ai_family, ptr, addrstr, 100);
424 416 if (verbose >= 1) {
425 inet_ntop (res->ai_family, ptr, addrstr, 100); 417 printf("* getaddrinfo IPv%d address: %s\n", res->ai_family == PF_INET6 ? 6 : 4, addrstr);
426 if (verbose >= 1) { 418 }
427 printf ("* getaddrinfo IPv%d address: %s\n", 419
428 res->ai_family == PF_INET6 ? 6 : 4, addrstr); 420 // Append all IPs to buf as a comma-separated string
429 } 421 addrstr_len = strlen(addrstr);
430 422 if (buflen_remaining > addrstr_len + 1) {
431 // Append all IPs to buf as a comma-separated string 423 if (buf[0] != '\0') {
432 addrstr_len = strlen(addrstr); 424 strncat(buf, ",", buflen_remaining);
433 if (buflen_remaining > addrstr_len + 1) { 425 buflen_remaining -= 1;
434 if (buf[0] != '\0') { 426 }
435 strncat(buf, ",", buflen_remaining); 427 strncat(buf, addrstr, buflen_remaining);
436 buflen_remaining -= 1; 428 buflen_remaining -= addrstr_len;
437 } 429 }
438 strncat(buf, addrstr, buflen_remaining); 430
439 buflen_remaining -= addrstr_len; 431 res = res->ai_next;
440 } 432 }
441 433
442 res = res->ai_next; 434 freeaddrinfo(result);
443 } 435
444 436 return 0;
445 freeaddrinfo(result);
446
447 return 0;
448} 437}
449 438
450static void 439static void cleanup(void) {
451cleanup (void) 440 if (status_line_initialized)
452{ 441 curlhelp_free_statusline(&status_line);
453 if (status_line_initialized) curlhelp_free_statusline(&status_line); 442 status_line_initialized = false;
454 status_line_initialized = false; 443 if (curl_easy_initialized)
455 if (curl_easy_initialized) curl_easy_cleanup (curl); 444 curl_easy_cleanup(curl);
456 curl_easy_initialized = false; 445 curl_easy_initialized = false;
457 if (curl_global_initialized) curl_global_cleanup (); 446 if (curl_global_initialized)
458 curl_global_initialized = false; 447 curl_global_cleanup();
459 if (body_buf_initialized) curlhelp_freewritebuffer (&body_buf); 448 curl_global_initialized = false;
460 body_buf_initialized = false; 449 if (body_buf_initialized)
461 if (header_buf_initialized) curlhelp_freewritebuffer (&header_buf); 450 curlhelp_freewritebuffer(&body_buf);
462 header_buf_initialized = false; 451 body_buf_initialized = false;
463 if (put_buf_initialized) curlhelp_freereadbuffer (&put_buf); 452 if (header_buf_initialized)
464 put_buf_initialized = false; 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;
465} 458}
466 459
467int 460int check_http(void) {
468check_http (void) 461 int result = STATE_OK;
469{ 462 int result_ssl = STATE_OK;
470 int result = STATE_OK; 463 int page_len = 0;
471 int result_ssl = STATE_OK; 464 int i;
472 int page_len = 0; 465 char *force_host_header = NULL;
473 int i; 466 struct curl_slist *host = NULL;
474 char *force_host_header = NULL; 467 char addrstr[DEFAULT_BUFFER_SIZE / 2];
475 struct curl_slist *host = NULL; 468 char dnscache[DEFAULT_BUFFER_SIZE];
476 char addrstr[DEFAULT_BUFFER_SIZE/2]; 469
477 char dnscache[DEFAULT_BUFFER_SIZE]; 470 /* initialize curl */
478 471 if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK)
479 /* initialize curl */ 472 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n");
480 if (curl_global_init (CURL_GLOBAL_DEFAULT) != CURLE_OK) 473 curl_global_initialized = true;
481 die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n"); 474
482 curl_global_initialized = true; 475 if ((curl = curl_easy_init()) == NULL) {
483 476 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n");
484 if ((curl = curl_easy_init()) == NULL) { 477 }
485 die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n"); 478 curl_easy_initialized = true;
486 } 479
487 curl_easy_initialized = true; 480 /* register cleanup function to shut down libcurl properly */
488 481 atexit(cleanup);
489 /* register cleanup function to shut down libcurl properly */ 482
490 atexit (cleanup); 483 if (verbose >= 1)
491 484 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_VERBOSE, 1), "CURLOPT_VERBOSE");
492 if (verbose >= 1) 485
493 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_VERBOSE, 1), "CURLOPT_VERBOSE"); 486 /* print everything on stdout like check_http would do */
494 487 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_STDERR, stdout), "CURLOPT_STDERR");
495 /* print everything on stdout like check_http would do */ 488
496 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_STDERR, stdout), "CURLOPT_STDERR"); 489 if (automatic_decompression)
497
498 if (automatic_decompression)
499#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) 490#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6)
500 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""), "CURLOPT_ACCEPT_ENCODING"); 491 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""), "CURLOPT_ACCEPT_ENCODING");
501#else 492#else
502 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_ENCODING, ""), "CURLOPT_ENCODING"); 493 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ENCODING, ""), "CURLOPT_ENCODING");
503#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */ 494#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */
504 495
505 /* initialize buffer for body of the answer */ 496 /* initialize buffer for body of the answer */
506 if (curlhelp_initwritebuffer(&body_buf) < 0) 497 if (curlhelp_initwritebuffer(&body_buf) < 0)
507 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n"); 498 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n");
508 body_buf_initialized = true; 499 body_buf_initialized = true;
509 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback), "CURLOPT_WRITEFUNCTION"); 500 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback),
510 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void *)&body_buf), "CURLOPT_WRITEDATA"); 501 "CURLOPT_WRITEFUNCTION");
511 502 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&body_buf), "CURLOPT_WRITEDATA");
512 /* initialize buffer for header of the answer */ 503
513 if (curlhelp_initwritebuffer( &header_buf ) < 0) 504 /* initialize buffer for header of the answer */
514 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n" ); 505 if (curlhelp_initwritebuffer(&header_buf) < 0)
515 header_buf_initialized = true; 506 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n");
516 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback), "CURLOPT_HEADERFUNCTION"); 507 header_buf_initialized = true;
517 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEHEADER, (void *)&header_buf), "CURLOPT_WRITEHEADER"); 508 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback),
518 509 "CURLOPT_HEADERFUNCTION");
519 /* set the error buffer */ 510 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEHEADER, (void *)&header_buf), "CURLOPT_WRITEHEADER");
520 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, errbuf), "CURLOPT_ERRORBUFFER"); 511
521 512 /* set the error buffer */
522 /* set timeouts */ 513 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf), "CURLOPT_ERRORBUFFER");
523 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, socket_timeout), "CURLOPT_CONNECTTIMEOUT"); 514
524 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_TIMEOUT, socket_timeout), "CURLOPT_TIMEOUT"); 515 /* set timeouts */
525 516 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, socket_timeout), "CURLOPT_CONNECTTIMEOUT");
526 /* enable haproxy protocol */ 517 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_TIMEOUT, socket_timeout), "CURLOPT_TIMEOUT");
527 if (haproxy_protocol) { 518
528 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L), "CURLOPT_HAPROXYPROTOCOL"); 519 /* enable haproxy protocol */
529 } 520 if (haproxy_protocol) {
530 521 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L), "CURLOPT_HAPROXYPROTOCOL");
531 // fill dns resolve cache to make curl connect to the given server_address instead of the host_name, only required for ssl, because we use the host_name later on to make SNI happy 522 }
532 if(use_ssl && host_name != NULL) { 523
533 if ( (res=lookup_host (server_address, addrstr, DEFAULT_BUFFER_SIZE/2)) != 0) { 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
534 snprintf (msg, 525 // use the host_name later on to make SNI happy
535 DEFAULT_BUFFER_SIZE, 526 if (use_ssl && host_name != NULL) {
536 _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"), 527 if ((res = lookup_host(server_address, addrstr, DEFAULT_BUFFER_SIZE / 2)) != 0) {
537 server_address, 528 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"), server_address, res,
538 res, 529 gai_strerror(res));
539 gai_strerror (res)); 530 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
540 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 531 }
541 } 532 snprintf(dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", host_name, server_port, addrstr);
542 snprintf (dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", host_name, server_port, addrstr); 533 host = curl_slist_append(NULL, dnscache);
543 host = curl_slist_append(NULL, dnscache); 534 curl_easy_setopt(curl, CURLOPT_RESOLVE, host);
544 curl_easy_setopt(curl, CURLOPT_RESOLVE, host); 535 if (verbose >= 1)
545 if (verbose>=1) 536 printf("* curl CURLOPT_RESOLVE: %s\n", dnscache);
546 printf ("* curl CURLOPT_RESOLVE: %s\n", dnscache); 537 }
547 } 538
548 539 // If server_address is an IPv6 address it must be surround by square brackets
549 // If server_address is an IPv6 address it must be surround by square brackets 540 struct in6_addr tmp_in_addr;
550 struct in6_addr tmp_in_addr; 541 if (inet_pton(AF_INET6, server_address, &tmp_in_addr) == 1) {
551 if (inet_pton(AF_INET6, server_address, &tmp_in_addr) == 1) { 542 char *new_server_address = malloc(strlen(server_address) + 3);
552 char *new_server_address = malloc(strlen(server_address) + 3); 543 if (new_server_address == NULL) {
553 if (new_server_address == NULL) { 544 die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n");
554 die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n"); 545 }
555 } 546 snprintf(new_server_address, strlen(server_address) + 3, "[%s]", server_address);
556 snprintf(new_server_address, strlen(server_address)+3, "[%s]", server_address); 547 free(server_address);
557 free(server_address); 548 server_address = new_server_address;
558 server_address = new_server_address; 549 }
559 } 550
560 551 /* compose URL: use the address we want to connect to, set Host: header later */
561 /* 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",
562 snprintf (url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", 553 (use_ssl & (host_name != NULL)) ? host_name : server_address, server_port, server_url);
563 use_ssl ? "https" : "http", 554
564 ( use_ssl & ( host_name != NULL ) ) ? host_name : server_address, 555 if (verbose >= 1)
565 server_port, 556 printf("* curl CURLOPT_URL: %s\n", url);
566 server_url 557 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_URL, url), "CURLOPT_URL");
567 ); 558
568 559 /* extract proxy information for legacy proxy https requests */
569 if (verbose>=1) 560 if (!strcmp(http_method, "CONNECT") || strstr(server_url, "http") == server_url) {
570 printf ("* curl CURLOPT_URL: %s\n", url); 561 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXY, server_address), "CURLOPT_PROXY");
571 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_URL, url), "CURLOPT_URL"); 562 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXYPORT, (long)server_port), "CURLOPT_PROXYPORT");
572 563 if (verbose >= 2)
573 /* extract proxy information for legacy proxy https requests */ 564 printf("* curl CURLOPT_PROXY: %s:%d\n", server_address, server_port);
574 if (!strcmp(http_method, "CONNECT") || strstr(server_url, "http") == server_url) { 565 http_method = "GET";
575 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_PROXY, server_address), "CURLOPT_PROXY"); 566 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_URL, server_url), "CURLOPT_URL");
576 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_PROXYPORT, (long)server_port), "CURLOPT_PROXYPORT"); 567 }
577 if (verbose>=2) 568
578 printf ("* curl CURLOPT_PROXY: %s:%d\n", server_address, server_port); 569 /* disable body for HEAD request */
579 http_method = "GET"; 570 if (http_method && !strcmp(http_method, "HEAD")) {
580 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_URL, server_url), "CURLOPT_URL"); 571 no_body = true;
581 } 572 }
582 573
583 /* disable body for HEAD request */ 574 /* set HTTP protocol version */
584 if (http_method && !strcmp (http_method, "HEAD" )) { 575 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, curl_http_version), "CURLOPT_HTTP_VERSION");
585 no_body = true; 576
586 } 577 /* set HTTP method */
587 578 if (http_method) {
588 /* set HTTP protocol version */ 579 if (!strcmp(http_method, "POST"))
589 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_HTTP_VERSION, curl_http_version), "CURLOPT_HTTP_VERSION"); 580 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_POST, 1), "CURLOPT_POST");
590 581 else if (!strcmp(http_method, "PUT"))
591 /* set HTTP method */ 582 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_UPLOAD, 1), "CURLOPT_UPLOAD");
592 if (http_method) { 583 else
593 if (!strcmp(http_method, "POST")) 584 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, http_method), "CURLOPT_CUSTOMREQUEST");
594 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_POST, 1), "CURLOPT_POST"); 585 }
595 else if (!strcmp(http_method, "PUT")) 586
596 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_UPLOAD, 1), "CURLOPT_UPLOAD"); 587 /* check if Host header is explicitly set in options */
597 else 588 if (http_opt_headers_count) {
598 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CUSTOMREQUEST, http_method), "CURLOPT_CUSTOMREQUEST"); 589 for (i = 0; i < http_opt_headers_count; i++) {
599 } 590 if (strncmp(http_opt_headers[i], "Host:", 5) == 0) {
600 591 force_host_header = http_opt_headers[i];
601 /* check if Host header is explicitly set in options */ 592 }
602 if (http_opt_headers_count) { 593 }
603 for (i = 0; i < http_opt_headers_count ; i++) { 594 }
604 if (strncmp(http_opt_headers[i], "Host:", 5) == 0) { 595
605 force_host_header = http_opt_headers[i]; 596 /* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in anyway */
606 } 597 if (host_name != NULL && force_host_header == NULL) {
607 } 598 if ((virtual_port != HTTP_PORT && !use_ssl) || (virtual_port != HTTPS_PORT && use_ssl)) {
608 } 599 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", host_name, virtual_port);
609 600 } else {
610 /* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in anyway */ 601 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", host_name);
611 if(host_name != NULL && force_host_header == NULL) { 602 }
612 if((virtual_port != HTTP_PORT && !use_ssl) || (virtual_port != HTTPS_PORT && use_ssl)) { 603 header_list = curl_slist_append(header_list, http_header);
613 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", host_name, virtual_port); 604 }
614 } else { 605
615 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", host_name); 606 /* always close connection, be nice to servers */
616 } 607 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Connection: close");
617 header_list = curl_slist_append (header_list, http_header); 608 header_list = curl_slist_append(header_list, http_header);
618 } 609
619 610 /* attach additional headers supplied by the user */
620 /* always close connection, be nice to servers */ 611 /* optionally send any other header tag */
621 snprintf (http_header, DEFAULT_BUFFER_SIZE, "Connection: close"); 612 if (http_opt_headers_count) {
622 header_list = curl_slist_append (header_list, http_header); 613 for (i = 0; i < http_opt_headers_count; i++) {
623 614 header_list = curl_slist_append(header_list, http_opt_headers[i]);
624 /* attach additional headers supplied by the user */ 615 }
625 /* optionally send any other header tag */ 616 /* This cannot be free'd here because a redirection will then try to access this and segfault */
626 if (http_opt_headers_count) { 617 /* Covered in a testcase in tests/check_http.t */
627 for (i = 0; i < http_opt_headers_count ; i++) { 618 /* free(http_opt_headers); */
628 header_list = curl_slist_append (header_list, http_opt_headers[i]); 619 }
629 } 620
630 /* This cannot be free'd here because a redirection will then try to access this and segfault */ 621 /* set HTTP headers */
631 /* Covered in a testcase in tests/check_http.t */ 622 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list), "CURLOPT_HTTPHEADER");
632 /* free(http_opt_headers); */
633 }
634
635 /* set HTTP headers */
636 handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPHEADER, header_list ), "CURLOPT_HTTPHEADER");
637 623
638#ifdef LIBCURL_FEATURE_SSL 624#ifdef LIBCURL_FEATURE_SSL
639 625
640 /* set SSL version, warn about insecure or unsupported versions */ 626 /* set SSL version, warn about insecure or unsupported versions */
641 if (use_ssl) { 627 if (use_ssl) {
642 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLVERSION, ssl_version), "CURLOPT_SSLVERSION"); 628 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLVERSION, ssl_version), "CURLOPT_SSLVERSION");
643 } 629 }
644 630
645 /* client certificate and key to present to server (SSL) */ 631 /* client certificate and key to present to server (SSL) */
646 if (client_cert) 632 if (client_cert)
647 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLCERT, client_cert), "CURLOPT_SSLCERT"); 633 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLCERT, client_cert), "CURLOPT_SSLCERT");
648 if (client_privkey) 634 if (client_privkey)
649 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLKEY, client_privkey), "CURLOPT_SSLKEY"); 635 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLKEY, client_privkey), "CURLOPT_SSLKEY");
650 if (ca_cert) { 636 if (ca_cert) {
651 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CAINFO, ca_cert), "CURLOPT_CAINFO"); 637 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CAINFO, ca_cert), "CURLOPT_CAINFO");
652 } 638 }
653 if (ca_cert || verify_peer_and_host) { 639 if (ca_cert || verify_peer_and_host) {
654 /* per default if we have a CA verify both the peer and the 640 /* per default if we have a CA verify both the peer and the
655 * hostname in the certificate, can be switched off later */ 641 * hostname in the certificate, can be switched off later */
656 handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 1), "CURLOPT_SSL_VERIFYPEER"); 642 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1), "CURLOPT_SSL_VERIFYPEER");
657 handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_SSL_VERIFYHOST, 2), "CURLOPT_SSL_VERIFYHOST"); 643 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2), "CURLOPT_SSL_VERIFYHOST");
658 } else { 644 } else {
659 /* backward-compatible behaviour, be tolerant in checks 645 /* backward-compatible behaviour, be tolerant in checks
660 * TODO: depending on more options have aspects we want 646 * TODO: depending on more options have aspects we want
661 * to be less tolerant about ssl verfications 647 * to be less tolerant about ssl verfications
662 */ 648 */
663 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0), "CURLOPT_SSL_VERIFYPEER"); 649 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0), "CURLOPT_SSL_VERIFYPEER");
664 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0), "CURLOPT_SSL_VERIFYHOST"); 650 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0), "CURLOPT_SSL_VERIFYHOST");
665 } 651 }
666 652
667 /* detect SSL library used by libcurl */ 653 /* detect SSL library used by libcurl */
668 ssl_library = curlhelp_get_ssl_library (); 654 ssl_library = curlhelp_get_ssl_library();
669 655
670 /* try hard to get a stack of certificates to verify against */ 656 /* try hard to get a stack of certificates to verify against */
671 if (check_cert) { 657 if (check_cert) {
672#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) 658# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1)
673 /* inform curl to report back certificates */ 659 /* inform curl to report back certificates */
674 switch (ssl_library) { 660 switch (ssl_library) {
675 case CURLHELP_SSL_LIBRARY_OPENSSL: 661 case CURLHELP_SSL_LIBRARY_OPENSSL:
676 case CURLHELP_SSL_LIBRARY_LIBRESSL: 662 case CURLHELP_SSL_LIBRARY_LIBRESSL:
677 /* set callback to extract certificate with OpenSSL context function (works with 663 /* set callback to extract certificate with OpenSSL context function (works with
678 * OpenSSL-style libraries only!) */ 664 * OpenSSL-style libraries only!) */
679#ifdef USE_OPENSSL 665# ifdef USE_OPENSSL
680 /* libcurl and monitoring plugins built with OpenSSL, good */ 666 /* libcurl and monitoring plugins built with OpenSSL, good */
681 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION"); 667 add_sslctx_verify_fun = true;
682 is_openssl_callback = true; 668 is_openssl_callback = true;
683#else /* USE_OPENSSL */ 669# endif /* USE_OPENSSL */
684#endif /* USE_OPENSSL */ 670 /* libcurl is built with OpenSSL, monitoring plugins, so falling
685 /* libcurl is built with OpenSSL, monitoring plugins, so falling 671 * back to manually extracting certificate information */
686 * back to manually extracting certificate information */ 672 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
687 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); 673 break;
688 break; 674
689 675 case CURLHELP_SSL_LIBRARY_NSS:
690 case CURLHELP_SSL_LIBRARY_NSS: 676# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
691#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 677 /* NSS: support for CERTINFO is implemented since 7.34.0 */
692 /* 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");
693 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) */
694#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",
695 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n", curlhelp_get_ssl_library_string (ssl_library)); 681 curlhelp_get_ssl_library_string(ssl_library));
696#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 682# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
697 break; 683 break;
698 684
699 case CURLHELP_SSL_LIBRARY_GNUTLS: 685 case CURLHELP_SSL_LIBRARY_GNUTLS:
700#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) 686# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0)
701 /* GnuTLS: support for CERTINFO is implemented since 7.42.0 */ 687 /* GnuTLS: support for CERTINFO is implemented since 7.42.0 */
702 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); 688 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
703#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */ 689# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
704 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n", curlhelp_get_ssl_library_string (ssl_library)); 690 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n",
705#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */ 691 curlhelp_get_ssl_library_string(ssl_library));
706 break; 692# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
707 693 break;
708 case CURLHELP_SSL_LIBRARY_UNKNOWN: 694
709 default: 695 case CURLHELP_SSL_LIBRARY_UNKNOWN:
710 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (unknown SSL library '%s', must implement first)\n", curlhelp_get_ssl_library_string (ssl_library)); 696 default:
711 break; 697 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (unknown SSL library '%s', must implement first)\n",
712 } 698 curlhelp_get_ssl_library_string(ssl_library));
713#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */ 699 break;
714 /* old libcurl, our only hope is OpenSSL, otherwise we are out of luck */ 700 }
715 if (ssl_library == CURLHELP_SSL_LIBRARY_OPENSSL || ssl_library == CURLHELP_SSL_LIBRARY_LIBRESSL) 701# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
716 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION"); 702 /* old libcurl, our only hope is OpenSSL, otherwise we are out of luck */
717 else 703 if (ssl_library == CURLHELP_SSL_LIBRARY_OPENSSL || ssl_library == CURLHELP_SSL_LIBRARY_LIBRESSL)
718 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (no CURLOPT_SSL_CTX_FUNCTION, no OpenSSL library or libcurl too old and has no CURLOPT_CERTINFO)\n"); 704 add_sslctx_verify_fun = true;
719#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */ 705 else
720 } 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 }
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
721 716
722#endif /* LIBCURL_FEATURE_SSL */ 717#endif /* LIBCURL_FEATURE_SSL */
723 718
724 /* set default or user-given user agent identification */ 719 /* set default or user-given user agent identification */
725 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_USERAGENT, user_agent), "CURLOPT_USERAGENT"); 720 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent), "CURLOPT_USERAGENT");
726 721
727 /* proxy-authentication */ 722 /* proxy-authentication */
728 if (strcmp(proxy_auth, "")) 723 if (strcmp(proxy_auth, ""))
729 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_PROXYUSERPWD, proxy_auth), "CURLOPT_PROXYUSERPWD"); 724 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxy_auth), "CURLOPT_PROXYUSERPWD");
730 725
731 /* authentication */ 726 /* authentication */
732 if (strcmp(user_auth, "")) 727 if (strcmp(user_auth, ""))
733 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_USERPWD, user_auth), "CURLOPT_USERPWD"); 728 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_USERPWD, user_auth), "CURLOPT_USERPWD");
734 729
735 /* TODO: parameter auth method, bitfield of following methods: 730 /* TODO: parameter auth method, bitfield of following methods:
736 * CURLAUTH_BASIC (default) 731 * CURLAUTH_BASIC (default)
737 * CURLAUTH_DIGEST 732 * CURLAUTH_DIGEST
738 * CURLAUTH_DIGEST_IE 733 * CURLAUTH_DIGEST_IE
739 * CURLAUTH_NEGOTIATE 734 * CURLAUTH_NEGOTIATE
740 * CURLAUTH_NTLM 735 * CURLAUTH_NTLM
741 * CURLAUTH_NTLM_WB 736 * CURLAUTH_NTLM_WB
742 * 737 *
743 * convenience tokens for typical sets of methods: 738 * convenience tokens for typical sets of methods:
744 * CURLAUTH_ANYSAFE: most secure, without BASIC 739 * CURLAUTH_ANYSAFE: most secure, without BASIC
745 * or CURLAUTH_ANY: most secure, even BASIC if necessary 740 * or CURLAUTH_ANY: most secure, even BASIC if necessary
746 * 741 *
747 * handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_DIGEST ), "CURLOPT_HTTPAUTH"); 742 * handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_DIGEST ), "CURLOPT_HTTPAUTH");
748 */ 743 */
749 744
750 /* handle redirections */ 745 /* handle redirections */
751 if (onredirect == STATE_DEPENDENT) { 746 if (onredirect == STATE_DEPENDENT) {
752 if( followmethod == FOLLOW_LIBCURL ) { 747 if (followmethod == FOLLOW_LIBCURL) {
753 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1), "CURLOPT_FOLLOWLOCATION"); 748 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1), "CURLOPT_FOLLOWLOCATION");
754 749
755 /* default -1 is infinite, not good, could lead to zombie plugins! 750 /* default -1 is infinite, not good, could lead to zombie plugins!
756 Setting it to one bigger than maximal limit to handle errors nicely below 751 Setting it to one bigger than maximal limit to handle errors nicely below
757 */ 752 */
758 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_MAXREDIRS, max_depth+1), "CURLOPT_MAXREDIRS"); 753 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_MAXREDIRS, max_depth + 1), "CURLOPT_MAXREDIRS");
759 754
760 /* for now allow only http and https (we are a http(s) check plugin in the end) */ 755 /* for now allow only http and https (we are a http(s) check plugin in the end) */
761#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0) 756#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0)
762 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"), "CURLOPT_REDIR_PROTOCOLS_STR"); 757 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"),
758 "CURLOPT_REDIR_PROTOCOLS_STR");
763#elif LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4) 759#elif LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4)
764 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS), "CURLOPT_REDIRECT_PROTOCOLS"); 760 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS),
761 "CURLOPT_REDIRECT_PROTOCOLS");
765#endif 762#endif
766 763
767 /* TODO: handle the following aspects of redirection, make them 764 /* TODO: handle the following aspects of redirection, make them
768 * command line options too later: 765 * command line options too later:
769 CURLOPT_POSTREDIR: method switch 766 CURLOPT_POSTREDIR: method switch
770 CURLINFO_REDIRECT_URL: custom redirect option 767 CURLINFO_REDIRECT_URL: custom redirect option
771 CURLOPT_REDIRECT_PROTOCOLS: allow people to step outside safe protocols 768 CURLOPT_REDIRECT_PROTOCOLS: allow people to step outside safe protocols
772 CURLINFO_REDIRECT_COUNT: get the number of redirects, print it, maybe a range option here is nice like for expected page size? 769 CURLINFO_REDIRECT_COUNT: get the number of redirects, print it, maybe a range option here is nice like for expected page size?
773 */ 770 */
774 } else { 771 } else {
775 /* old style redirection is handled below */ 772 /* old style redirection is handled below */
776 } 773 }
777 } 774 }
778 775
779 /* no-body */ 776 /* no-body */
780 if (no_body) 777 if (no_body)
781 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_NOBODY, 1), "CURLOPT_NOBODY"); 778 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_NOBODY, 1), "CURLOPT_NOBODY");
782 779
783 /* IPv4 or IPv6 forced DNS resolution */ 780 /* IPv4 or IPv6 forced DNS resolution */
784 if (address_family == AF_UNSPEC) 781 if (address_family == AF_UNSPEC)
785 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)"); 782 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER),
786 else if (address_family == AF_INET) 783 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)");
787 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)"); 784 else if (address_family == AF_INET)
788#if defined (USE_IPV6) && defined (LIBCURL_FEATURE_IPV6) 785 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4),
789 else if (address_family == AF_INET6) 786 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)");
790 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)"); 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 791#endif
792 792
793 /* either send http POST data (any data, not only POST)*/ 793 /* either send http POST data (any data, not only POST)*/
794 if (!strcmp(http_method, "POST") ||!strcmp(http_method, "PUT")) { 794 if (!strcmp(http_method, "POST") || !strcmp(http_method, "PUT")) {
795 /* set content of payload for POST and PUT */ 795 /* set content of payload for POST and PUT */
796 if (http_content_type) { 796 if (http_content_type) {
797 snprintf (http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s", http_content_type); 797 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s", http_content_type);
798 header_list = curl_slist_append (header_list, http_header); 798 header_list = curl_slist_append(header_list, http_header);
799 } 799 }
800 /* NULL indicates "HTTP Continue" in libcurl, provide an empty string 800 /* NULL indicates "HTTP Continue" in libcurl, provide an empty string
801 * in case of no POST/PUT data */ 801 * in case of no POST/PUT data */
802 if (!http_post_data) 802 if (!http_post_data)
803 http_post_data = ""; 803 http_post_data = "";
804 if (!strcmp(http_method, "POST")) { 804 if (!strcmp(http_method, "POST")) {
805 /* POST method, set payload with CURLOPT_POSTFIELDS */ 805 /* POST method, set payload with CURLOPT_POSTFIELDS */
806 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_POSTFIELDS, http_post_data), "CURLOPT_POSTFIELDS"); 806 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_POSTFIELDS, http_post_data), "CURLOPT_POSTFIELDS");
807 } else if (!strcmp(http_method, "PUT")) { 807 } else if (!strcmp(http_method, "PUT")) {
808 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_READFUNCTION, (curl_read_callback)curlhelp_buffer_read_callback), "CURLOPT_READFUNCTION"); 808 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_READFUNCTION, (curl_read_callback)curlhelp_buffer_read_callback),
809 if (curlhelp_initreadbuffer (&put_buf, http_post_data, strlen (http_post_data)) < 0) 809 "CURLOPT_READFUNCTION");
810 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating read buffer for PUT\n"); 810 if (curlhelp_initreadbuffer(&put_buf, http_post_data, strlen(http_post_data)) < 0)
811 put_buf_initialized = true; 811 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating read buffer for PUT\n");
812 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_READDATA, (void *)&put_buf), "CURLOPT_READDATA"); 812 put_buf_initialized = true;
813 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_INFILESIZE, (curl_off_t)strlen (http_post_data)), "CURLOPT_INFILESIZE"); 813 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_READDATA, (void *)&put_buf), "CURLOPT_READDATA");
814 } 814 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_INFILESIZE, (curl_off_t)strlen(http_post_data)),
815 } 815 "CURLOPT_INFILESIZE");
816 816 }
817 /* cookie handling */ 817 }
818 if (cookie_jar_file != NULL) { 818
819 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_COOKIEJAR, cookie_jar_file), "CURLOPT_COOKIEJAR"); 819 /* cookie handling */
820 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_COOKIEFILE, cookie_jar_file), "CURLOPT_COOKIEFILE"); 820 if (cookie_jar_file != NULL) {
821 } 821 /* enable reading cookies from a file, and if the filename is an empty string, only enable the curl cookie engine */
822 822 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_COOKIEFILE, cookie_jar_file), "CURLOPT_COOKIEFILE");
823 /* do the request */ 823 /* now enable saving cookies to a file, but only if the filename is not an empty string, since writing it would fail */
824 res = curl_easy_perform(curl); 824 if (*cookie_jar_file)
825 825 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_COOKIEJAR, cookie_jar_file), "CURLOPT_COOKIEJAR");
826 if (verbose>=2 && http_post_data) 826 }
827 printf ("**** REQUEST CONTENT ****\n%s\n", http_post_data); 827
828 828 /* do the request */
829 /* free header and server IP resolve lists, we don't need it anymore */ 829 res = curl_easy_perform(curl);
830 curl_slist_free_all (header_list); header_list = NULL; 830
831 curl_slist_free_all (server_ips); server_ips = NULL; 831 if (verbose >= 2 && http_post_data)
832 if (host) { 832 printf("**** REQUEST CONTENT ****\n%s\n", http_post_data);
833 curl_slist_free_all (host); host = NULL; 833
834 } 834 /* free header and server IP resolve lists, we don't need it anymore */
835 835 curl_slist_free_all(header_list);
836 /* Curl errors, result in critical Nagios state */ 836 header_list = NULL;
837 if (res != CURLE_OK) { 837 curl_slist_free_all(server_ips);
838 snprintf (msg, 838 server_ips = NULL;
839 DEFAULT_BUFFER_SIZE, 839 if (host) {
840 _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"), 840 curl_slist_free_all(host);
841 server_port, 841 host = NULL;
842 res, 842 }
843 errbuf[0] ? errbuf : curl_easy_strerror(res)); 843
844 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 844 /* Curl errors, result in critical Nagios state */
845 } 845 if (res != CURLE_OK) {
846 846 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"), server_port,
847 /* certificate checks */ 847 res, errbuf[0] ? errbuf : curl_easy_strerror(res));
848 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
849 }
850
851 /* certificate checks */
848#ifdef LIBCURL_FEATURE_SSL 852#ifdef LIBCURL_FEATURE_SSL
849 if (use_ssl) { 853 if (use_ssl) {
850 if (check_cert) { 854 if (check_cert) {
851 if (is_openssl_callback) { 855 if (is_openssl_callback) {
852#ifdef USE_OPENSSL 856# ifdef USE_OPENSSL
853 /* check certificate with OpenSSL functions, curl has been built against OpenSSL 857 /* check certificate with OpenSSL functions, curl has been built against OpenSSL
854 * and we actually have OpenSSL in the monitoring tools 858 * and we actually have OpenSSL in the monitoring tools
855 */ 859 */
856 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit); 860 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
857 if (!continue_after_check_cert) { 861 if (!continue_after_check_cert) {
858 return result_ssl; 862 return result_ssl;
859 } 863 }
860#else /* USE_OPENSSL */ 864# else /* USE_OPENSSL */
861 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL callback used and not linked against OpenSSL\n"); 865 die(STATE_CRITICAL,
862#endif /* USE_OPENSSL */ 866 "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL callback used and not linked against OpenSSL\n");
863 } else { 867# endif /* USE_OPENSSL */
864 int i; 868 } else {
865 struct curl_slist *slist; 869 int i;
866 870 struct curl_slist *slist;
867 cert_ptr.to_info = NULL; 871
868 res = curl_easy_getinfo (curl, CURLINFO_CERTINFO, &cert_ptr.to_info); 872 cert_ptr.to_info = NULL;
869 if (!res && cert_ptr.to_info) { 873 res = curl_easy_getinfo(curl, CURLINFO_CERTINFO, &cert_ptr.to_info);
870#ifdef USE_OPENSSL 874 if (!res && cert_ptr.to_info) {
871 /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert parsing 875# ifdef USE_OPENSSL
872 * We only check the first certificate and assume it's the one of the server 876 /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert parsing
873 */ 877 * We only check the first certificate and assume it's the one of the server
874 const char* raw_cert = NULL; 878 */
875 for (i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) { 879 const char *raw_cert = NULL;
876 for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) { 880 for (i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) {
877 if (verbose >= 2) 881 for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) {
878 printf ("%d ** %s\n", i, slist->data); 882 if (verbose >= 2)
879 if (strncmp (slist->data, "Cert:", 5) == 0) { 883 printf("%d ** %s\n", i, slist->data);
880 raw_cert = &slist->data[5]; 884 if (strncmp(slist->data, "Cert:", 5) == 0) {
881 goto GOT_FIRST_CERT; 885 raw_cert = &slist->data[5];
882 } 886 goto GOT_FIRST_CERT;
883 } 887 }
884 } 888 }
885GOT_FIRST_CERT: 889 }
886 if (!raw_cert) { 890 GOT_FIRST_CERT:
887 snprintf (msg, 891 if (!raw_cert) {
888 DEFAULT_BUFFER_SIZE, 892 snprintf(msg, DEFAULT_BUFFER_SIZE,
889 _("Cannot retrieve certificates from CERTINFO information - certificate data was empty")); 893 _("Cannot retrieve certificates from CERTINFO information - certificate data was empty"));
890 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 894 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
891 } 895 }
892 BIO* cert_BIO = BIO_new (BIO_s_mem()); 896 BIO *cert_BIO = BIO_new(BIO_s_mem());
893 BIO_write (cert_BIO, raw_cert, strlen(raw_cert)); 897 BIO_write(cert_BIO, raw_cert, strlen(raw_cert));
894 cert = PEM_read_bio_X509 (cert_BIO, NULL, NULL, NULL); 898 cert = PEM_read_bio_X509(cert_BIO, NULL, NULL, NULL);
895 if (!cert) { 899 if (!cert) {
896 snprintf (msg, 900 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Cannot read certificate from CERTINFO information - BIO error"));
897 DEFAULT_BUFFER_SIZE, 901 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
898 _("Cannot read certificate from CERTINFO information - BIO error")); 902 }
899 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 903 BIO_free(cert_BIO);
900 } 904 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
901 BIO_free (cert_BIO); 905 if (!continue_after_check_cert) {
902 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit); 906 return result_ssl;
903 if (!continue_after_check_cert) { 907 }
904 return result_ssl; 908# else /* USE_OPENSSL */
905 } 909 /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our disposal,
906#else /* USE_OPENSSL */ 910 * so we use the libcurl CURLINFO data
907 /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our disposal, 911 */
908 * so we use the libcurl CURLINFO data 912 result_ssl = net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn, days_till_exp_crit);
909 */ 913 if (!continue_after_check_cert) {
910 result_ssl = net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn, days_till_exp_crit); 914 return result_ssl;
911 if (!continue_after_check_cert) { 915 }
912 return result_ssl; 916# endif /* USE_OPENSSL */
913 } 917 } else {
914#endif /* USE_OPENSSL */ 918 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Cannot retrieve certificates - cURL returned %d - %s"), res,
915 } else { 919 curl_easy_strerror(res));
916 snprintf (msg, 920 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
917 DEFAULT_BUFFER_SIZE, 921 }
918 _("Cannot retrieve certificates - cURL returned %d - %s"), 922 }
919 res, 923 }
920 curl_easy_strerror(res)); 924 }
921 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
922 }
923 }
924 }
925 }
926#endif /* LIBCURL_FEATURE_SSL */ 925#endif /* LIBCURL_FEATURE_SSL */
927 926
928 /* we got the data and we executed the request in a given time, so we can append 927 /* we got the data and we executed the request in a given time, so we can append
929 * performance data to the answer always 928 * performance data to the answer always
930 */ 929 */
931 handle_curl_option_return_code (curl_easy_getinfo (curl, CURLINFO_TOTAL_TIME, &total_time), "CURLINFO_TOTAL_TIME"); 930 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time), "CURLINFO_TOTAL_TIME");
932 page_len = get_content_length(&header_buf, &body_buf); 931 page_len = get_content_length(&header_buf, &body_buf);
933 if(show_extended_perfdata) { 932 if (show_extended_perfdata) {
934 handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &time_connect), "CURLINFO_CONNECT_TIME"); 933 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &time_connect), "CURLINFO_CONNECT_TIME");
935 handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &time_appconnect), "CURLINFO_APPCONNECT_TIME"); 934 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &time_appconnect), "CURLINFO_APPCONNECT_TIME");
936 handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &time_headers), "CURLINFO_PRETRANSFER_TIME"); 935 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &time_headers), "CURLINFO_PRETRANSFER_TIME");
937 handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte), "CURLINFO_STARTTRANSFER_TIME"); 936 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte),
938 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s", 937 "CURLINFO_STARTTRANSFER_TIME");
939 perfd_time(total_time), 938 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s", perfd_time(total_time), perfd_size(page_len),
940 perfd_size(page_len), 939 perfd_time_connect(time_connect), use_ssl ? perfd_time_ssl(time_appconnect - time_connect) : "",
941 perfd_time_connect(time_connect), 940 perfd_time_headers(time_headers - time_appconnect), perfd_time_firstbyte(time_firstbyte - time_headers),
942 use_ssl ? perfd_time_ssl (time_appconnect-time_connect) : "", 941 perfd_time_transfer(total_time - time_firstbyte));
943 perfd_time_headers(time_headers - time_appconnect), 942 } else {
944 perfd_time_firstbyte(time_firstbyte - time_headers), 943 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s", perfd_time(total_time), perfd_size(page_len));
945 perfd_time_transfer(total_time-time_firstbyte) 944 }
946 );
947 } else {
948 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s",
949 perfd_time(total_time),
950 perfd_size(page_len)
951 );
952 }
953
954 /* return a CRITICAL status if we couldn't read any data */
955 if (strlen(header_buf.buf) == 0 && strlen(body_buf.buf) == 0)
956 die (STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n"));
957
958 /* get status line of answer, check sanity of HTTP code */
959 if (curlhelp_parse_statusline (header_buf.buf, &status_line) < 0) {
960 snprintf (msg,
961 DEFAULT_BUFFER_SIZE,
962 "Unparsable status line in %.3g seconds response time|%s\n",
963 total_time,
964 perfstring);
965 /* we cannot know the major/minor version here for sure as we cannot parse the first line */
966 die (STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x %ld unknown - %s", code, msg);
967 }
968 status_line_initialized = true;
969
970 /* get result code from cURL */
971 handle_curl_option_return_code (curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &code), "CURLINFO_RESPONSE_CODE");
972 if (verbose>=2)
973 printf ("* curl CURLINFO_RESPONSE_CODE is %ld\n", code);
974
975 /* print status line, header, body if verbose */
976 if (verbose >= 2) {
977 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header_buf.buf,
978 (no_body ? " [[ skipped ]]" : body_buf.buf));
979 }
980
981 /* make sure the status line matches the response we are looking for */
982 if (!expected_statuscode(status_line.first_line, server_expect)) {
983 if (server_port == HTTP_PORT)
984 snprintf(msg,
985 DEFAULT_BUFFER_SIZE,
986 _("Invalid HTTP response received from host: %s\n"),
987 status_line.first_line);
988 else
989 snprintf(msg,
990 DEFAULT_BUFFER_SIZE,
991 _("Invalid HTTP response received from host on port %d: %s\n"),
992 server_port,
993 status_line.first_line);
994 die (STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg,
995 show_body ? "\n" : "",
996 show_body ? body_buf.buf : "");
997 }
998
999 if( server_expect_yn ) {
1000 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Status line output matched \"%s\" - "), server_expect);
1001 if (verbose)
1002 printf ("%s\n",msg);
1003 result = STATE_OK;
1004 }
1005 else {
1006 /* illegal return codes result in a critical state */
1007 if (code >= 600 || code < 100) {
1008 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"), status_line.http_code, status_line.msg);
1009 /* server errors result in a critical state */
1010 } else if (code >= 500) {
1011 result = STATE_CRITICAL;
1012 /* client errors result in a warning state */
1013 } else if (code >= 400) {
1014 result = STATE_WARNING;
1015 /* check redirected page if specified */
1016 } else if (code >= 300) {
1017 if (onredirect == STATE_DEPENDENT) {
1018 if( followmethod == FOLLOW_LIBCURL ) {
1019 code = status_line.http_code;
1020 } else {
1021 /* old check_http style redirection, if we come
1022 * back here, we are in the same status as with
1023 * the libcurl method
1024 */
1025 redir (&header_buf);
1026 }
1027 } else {
1028 /* this is a specific code in the command line to
1029 * be returned when a redirection is encountered
1030 */
1031 }
1032 result = max_state_alt (onredirect, result);
1033 /* all other codes are considered ok */
1034 } else {
1035 result = STATE_OK;
1036 }
1037 }
1038
1039 /* libcurl redirection internally, handle error states here */
1040 if( followmethod == FOLLOW_LIBCURL ) {
1041 handle_curl_option_return_code (curl_easy_getinfo (curl, CURLINFO_REDIRECT_COUNT, &redir_depth), "CURLINFO_REDIRECT_COUNT");
1042 if (verbose >= 2)
1043 printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth);
1044 if (redir_depth > max_depth) {
1045 snprintf (msg, DEFAULT_BUFFER_SIZE, "maximum redirection depth %d exceeded in libcurl",
1046 max_depth);
1047 die (STATE_WARNING, "HTTP WARNING - %s", msg);
1048 }
1049 }
1050
1051 /* check status codes, set exit status accordingly */
1052 if( status_line.http_code != code ) {
1053 die (STATE_CRITICAL, _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"),
1054 string_statuscode (status_line.http_major, status_line.http_minor),
1055 status_line.http_code, status_line.msg, code);
1056 }
1057
1058 if (maximum_age >= 0) {
1059 result = max_state_alt(check_document_dates(&header_buf, &msg), result);
1060 }
1061
1062 /* Page and Header content checks go here */
1063
1064 if (strlen (header_expect)) {
1065 if (!strstr (header_buf.buf, header_expect)) {
1066
1067 strncpy(&output_header_search[0],header_expect,sizeof(output_header_search));
1068
1069 if(output_header_search[sizeof(output_header_search)-1]!='\0') {
1070 bcopy("...",&output_header_search[sizeof(output_header_search)-4],4);
1071 }
1072 945
1073 char tmp[DEFAULT_BUFFER_SIZE]; 946 /* return a CRITICAL status if we couldn't read any data */
947 if (strlen(header_buf.buf) == 0 && strlen(body_buf.buf) == 0)
948 die(STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n"));
1074 949
1075 snprintf (tmp, 950 /* get status line of answer, check sanity of HTTP code */
1076 DEFAULT_BUFFER_SIZE, 951 if (curlhelp_parse_statusline(header_buf.buf, &status_line) < 0) {
1077 _("%sheader '%s' not found on '%s://%s:%d%s', "), 952 snprintf(msg, DEFAULT_BUFFER_SIZE, "Unparsable status line in %.3g seconds response time|%s\n", total_time, perfstring);
1078 msg, 953 /* we cannot know the major/minor version here for sure as we cannot parse the first line */
1079 output_header_search, 954 die(STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x %ld unknown - %s", code, msg);
1080 use_ssl ? "https" : "http", 955 }
1081 host_name ? host_name : server_address, 956 status_line_initialized = true;
1082 server_port,
1083 server_url);
1084 957
1085 strcpy(msg, tmp); 958 /* get result code from cURL */
959 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code), "CURLINFO_RESPONSE_CODE");
960 if (verbose >= 2)
961 printf("* curl CURLINFO_RESPONSE_CODE is %ld\n", code);
1086 962
1087 result = STATE_CRITICAL; 963 /* print status line, header, body if verbose */
1088 } 964 if (verbose >= 2) {
1089 } 965 printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header_buf.buf, (no_body ? " [[ skipped ]]" : body_buf.buf));
966 }
1090 967
1091 if (strlen (string_expect)) { 968 /* make sure the status line matches the response we are looking for */
1092 if (!strstr (body_buf.buf, string_expect)) { 969 if (!expected_statuscode(status_line.first_line, server_expect)) {
970 if (server_port == HTTP_PORT)
971 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host: %s\n"), status_line.first_line);
972 else
973 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: %s\n"), server_port,
974 status_line.first_line);
975 die(STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg, show_body ? "\n" : "", show_body ? body_buf.buf : "");
976 }
1093 977
1094 strncpy(&output_string_search[0],string_expect,sizeof(output_string_search)); 978 if (server_expect_yn) {
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 */
985 if (code >= 600 || code < 100) {
986 die(STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"), status_line.http_code, status_line.msg);
987 /* server errors result in a critical state */
988 } else if (code >= 500) {
989 result = STATE_CRITICAL;
990 /* client errors result in a warning state */
991 } else if (code >= 400) {
992 result = STATE_WARNING;
993 /* check redirected page if specified */
994 } else if (code >= 300) {
995 if (onredirect == STATE_DEPENDENT) {
996 if (followmethod == FOLLOW_LIBCURL) {
997 code = status_line.http_code;
998 } else {
999 /* old check_http style redirection, if we come
1000 * back here, we are in the same status as with
1001 * the libcurl method
1002 */
1003 redir(&header_buf);
1004 }
1005 } else {
1006 /* this is a specific code in the command line to
1007 * be returned when a redirection is encountered
1008 */
1009 }
1010 result = max_state_alt(onredirect, result);
1011 /* all other codes are considered ok */
1012 } else {
1013 result = STATE_OK;
1014 }
1015 }
1095 1016
1096 if(output_string_search[sizeof(output_string_search)-1]!='\0') { 1017 /* libcurl redirection internally, handle error states here */
1097 bcopy("...",&output_string_search[sizeof(output_string_search)-4],4); 1018 if (followmethod == FOLLOW_LIBCURL) {
1098 } 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 }
1027
1028 /* check status codes, set exit status accordingly */
1029 if (status_line.http_code != code) {
1030 die(STATE_CRITICAL, _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"),
1031 string_statuscode(status_line.http_major, status_line.http_minor), status_line.http_code, status_line.msg, code);
1032 }
1033
1034 if (maximum_age >= 0) {
1035 result = max_state_alt(check_document_dates(&header_buf, &msg), result);
1036 }
1037
1038 /* Page and Header content checks go here */
1039
1040 if (strlen(header_expect)) {
1041 if (!strstr(header_buf.buf, header_expect)) {
1042
1043 strncpy(&output_header_search[0], header_expect, sizeof(output_header_search));
1044
1045 if (output_header_search[sizeof(output_header_search) - 1] != '\0') {
1046 bcopy("...", &output_header_search[sizeof(output_header_search) - 4], 4);
1047 }
1048
1049 char tmp[DEFAULT_BUFFER_SIZE];
1050
1051 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sheader '%s' not found on '%s://%s:%d%s', "), msg, output_header_search,
1052 use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url);
1053
1054 strcpy(msg, tmp);
1055
1056 result = STATE_CRITICAL;
1057 }
1058 }
1059
1060 if (strlen(string_expect)) {
1061 if (!strstr(body_buf.buf, string_expect)) {
1062
1063 strncpy(&output_string_search[0], string_expect, sizeof(output_string_search));
1064
1065 if (output_string_search[sizeof(output_string_search) - 1] != '\0') {
1066 bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 4);
1067 }
1099 1068
1100 char tmp[DEFAULT_BUFFER_SIZE]; 1069 char tmp[DEFAULT_BUFFER_SIZE];
1101 1070
1102 snprintf (tmp, 1071 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg, output_string_search,
1103 DEFAULT_BUFFER_SIZE, 1072 use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url);
1104 _("%sstring '%s' not found on '%s://%s:%d%s', "),
1105 msg,
1106 output_string_search,
1107 use_ssl ? "https" : "http",
1108 host_name ? host_name : server_address,
1109 server_port,
1110 server_url);
1111 1073
1112 strcpy(msg, tmp); 1074 strcpy(msg, tmp);
1113 1075
1114 result = STATE_CRITICAL; 1076 result = STATE_CRITICAL;
1115 } 1077 }
1116 } 1078 }
1117 1079
1118 if (strlen (regexp)) { 1080 if (strlen(regexp)) {
1119 errcode = regexec (&preg, body_buf.buf, REGS, pmatch, 0); 1081 errcode = regexec(&preg, body_buf.buf, REGS, pmatch, 0);
1120 if ((errcode == 0 && !invert_regex) || (errcode == REG_NOMATCH && invert_regex)) { 1082 if ((errcode == 0 && !invert_regex) || (errcode == REG_NOMATCH && invert_regex)) {
1121 /* OK - No-op to avoid changing the logic around it */ 1083 /* OK - No-op to avoid changing the logic around it */
1122 result = max_state_alt(STATE_OK, result); 1084 result = max_state_alt(STATE_OK, result);
1123 } 1085 } else if ((errcode == REG_NOMATCH && !invert_regex) || (errcode == 0 && invert_regex)) {
1124 else if ((errcode == REG_NOMATCH && !invert_regex) || (errcode == 0 && invert_regex)) {
1125 if (!invert_regex) { 1086 if (!invert_regex) {
1126 char tmp[DEFAULT_BUFFER_SIZE]; 1087 char tmp[DEFAULT_BUFFER_SIZE];
1127 1088
1128 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg); 1089 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg);
1129 strcpy(msg, tmp); 1090 strcpy(msg, tmp);
1130 1091
1131 } else { 1092 } else {
1132 char tmp[DEFAULT_BUFFER_SIZE]; 1093 char tmp[DEFAULT_BUFFER_SIZE];
1133 1094
1134 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg); 1095 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg);
1135 strcpy(msg, tmp); 1096 strcpy(msg, tmp);
1136
1137 } 1097 }
1138 result = state_regex; 1098 result = state_regex;
1139 } else { 1099 } else {
1140 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1100 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1141 1101
1142 char tmp[DEFAULT_BUFFER_SIZE]; 1102 char tmp[DEFAULT_BUFFER_SIZE];
1143 1103
1144 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sExecute Error: %s, "), msg, errbuf); 1104 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sExecute Error: %s, "), msg, errbuf);
1145 strcpy(msg, tmp); 1105 strcpy(msg, tmp);
1146 result = STATE_UNKNOWN; 1106 result = STATE_UNKNOWN;
1147 } 1107 }
1148 } 1108 }
1149 1109
1150 /* make sure the page is of an appropriate size */ 1110 /* make sure the page is of an appropriate size */
1151 if ((max_page_len > 0) && (page_len > max_page_len)) { 1111 if ((max_page_len > 0) && (page_len > max_page_len)) {
1152 char tmp[DEFAULT_BUFFER_SIZE]; 1112 char tmp[DEFAULT_BUFFER_SIZE];
1153 1113
1154 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too large, "), msg, page_len); 1114 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too large, "), msg, page_len);
1155 1115
1156 strcpy(msg, tmp); 1116 strcpy(msg, tmp);
1157 1117
@@ -1160,1281 +1120,1233 @@ GOT_FIRST_CERT:
1160 } else if ((min_page_len > 0) && (page_len < min_page_len)) { 1120 } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1161 char tmp[DEFAULT_BUFFER_SIZE]; 1121 char tmp[DEFAULT_BUFFER_SIZE];
1162 1122
1163 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too small, "), msg, page_len); 1123 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too small, "), msg, page_len);
1164 strcpy(msg, tmp); 1124 strcpy(msg, tmp);
1165 result = max_state_alt(STATE_WARNING, result); 1125 result = max_state_alt(STATE_WARNING, result);
1166 } 1126 }
1167 1127
1168 /* -w, -c: check warning and critical level */ 1128 /* -w, -c: check warning and critical level */
1169 result = max_state_alt(get_status(total_time, thlds), result); 1129 result = max_state_alt(get_status(total_time, thlds), result);
1170 1130
1171 /* Cut-off trailing characters */ 1131 /* Cut-off trailing characters */
1172 if (strlen(msg) >= 2) { 1132 if (strlen(msg) >= 2) {
1173 if(msg[strlen(msg)-2] == ',') 1133 if (msg[strlen(msg) - 2] == ',')
1174 msg[strlen(msg)-2] = '\0'; 1134 msg[strlen(msg) - 2] = '\0';
1175 else 1135 else
1176 msg[strlen(msg)-3] = '\0'; 1136 msg[strlen(msg) - 3] = '\0';
1177 } 1137 }
1178 1138
1179 /* TODO: separate _() msg and status code: die (result, "HTTP %s: %s\n", state_text(result), msg); */ 1139 /* TODO: separate _() msg and status code: die (result, "HTTP %s: %s\n", state_text(result), msg); */
1180 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", 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),
1181 state_text(result), string_statuscode (status_line.http_major, status_line.http_minor), 1141 string_statuscode(status_line.http_major, status_line.http_minor), status_line.http_code, status_line.msg,
1182 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 : ""),
1183 strlen(msg) > 0 ? " - " : "", 1143 (show_body ? "\n" : ""));
1184 msg, page_len, total_time, 1144
1185 (display_html ? "</A>" : ""), 1145 return max_state_alt(result, result_ssl);
1186 perfstring,
1187 (show_body ? body_buf.buf : ""),
1188 (show_body ? "\n" : "") );
1189
1190 return max_state_alt(result, result_ssl);
1191} 1146}
1192 1147
1193int 1148int uri_strcmp(const UriTextRangeA range, const char *s) {
1194uri_strcmp (const UriTextRangeA range, const char* s) 1149 if (!range.first)
1195{ 1150 return -1;
1196 if (!range.first) return -1; 1151 if ((size_t)(range.afterLast - range.first) < strlen(s))
1197 if ( (size_t)(range.afterLast - range.first) < strlen (s) ) return -1; 1152 return -1;
1198 return strncmp (s, range.first, min( (size_t)(range.afterLast - range.first), strlen (s))); 1153 return strncmp(s, range.first, min((size_t)(range.afterLast - range.first), strlen(s)));
1199} 1154}
1200 1155
1201char* 1156char *uri_string(const UriTextRangeA range, char *buf, size_t buflen) {
1202uri_string (const UriTextRangeA range, char* buf, size_t buflen) 1157 if (!range.first)
1203{ 1158 return "(null)";
1204 if (!range.first) return "(null)"; 1159 strncpy(buf, range.first, max(buflen - 1, (size_t)(range.afterLast - range.first)));
1205 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';
1206 buf[max (buflen-1, (size_t)(range.afterLast - range.first))] = '\0'; 1161 buf[range.afterLast - range.first] = '\0';
1207 buf[range.afterLast - range.first] = '\0'; 1162 return buf;
1208 return buf;
1209} 1163}
1210 1164
1211void 1165void redir(curlhelp_write_curlbuf *header_buf) {
1212redir (curlhelp_write_curlbuf* header_buf) 1166 char *location = NULL;
1213{ 1167 curlhelp_statusline status_line;
1214 char *location = NULL; 1168 struct phr_header headers[255];
1215 curlhelp_statusline status_line; 1169 size_t nof_headers = 255;
1216 struct phr_header headers[255]; 1170 size_t msglen;
1217 size_t nof_headers = 255; 1171 char buf[DEFAULT_BUFFER_SIZE];
1218 size_t msglen; 1172 char ipstr[INET_ADDR_MAX_SIZE];
1219 char buf[DEFAULT_BUFFER_SIZE]; 1173 int new_port;
1220 char ipstr[INET_ADDR_MAX_SIZE]; 1174 char *new_host;
1221 int new_port; 1175 char *new_url;
1222 char *new_host; 1176
1223 char *new_url; 1177 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor,
1224 1178 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0);
1225 int res = phr_parse_response (header_buf->buf, header_buf->buflen,
1226 &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
1227 headers, &nof_headers, 0);
1228 1179
1229 if (res == -1) { 1180 if (res == -1) {
1230 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 1181 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
1231 } 1182 }
1232 1183
1233 location = get_header_value (headers, nof_headers, "location"); 1184 location = get_header_value(headers, nof_headers, "location");
1234 1185
1235 if (verbose >= 2) 1186 if (verbose >= 2)
1236 printf(_("* Seen redirect location %s\n"), location); 1187 printf(_("* Seen redirect location %s\n"), location);
1237 1188
1238 if (++redir_depth > max_depth) 1189 if (++redir_depth > max_depth)
1239 die (STATE_WARNING, 1190 die(STATE_WARNING, _("HTTP WARNING - maximum redirection depth %d exceeded - %s%s\n"), max_depth, location,
1240 _("HTTP WARNING - maximum redirection depth %d exceeded - %s%s\n"), 1191 (display_html ? "</A>" : ""));
1241 max_depth, location, (display_html ? "</A>" : "")); 1192
1242 1193 UriParserStateA state;
1243 UriParserStateA state; 1194 UriUriA uri;
1244 UriUriA uri; 1195 state.uri = &uri;
1245 state.uri = &uri; 1196 if (uriParseUriA(&state, location) != URI_SUCCESS) {
1246 if (uriParseUriA (&state, location) != URI_SUCCESS) { 1197 if (state.errorCode == URI_ERROR_SYNTAX) {
1247 if (state.errorCode == URI_ERROR_SYNTAX) { 1198 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not parse redirect location '%s'%s\n"), location, (display_html ? "</A>" : ""));
1248 die (STATE_UNKNOWN, 1199 } else if (state.errorCode == URI_ERROR_MALLOC) {
1249 _("HTTP UNKNOWN - Could not parse redirect location '%s'%s\n"), 1200 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1250 location, (display_html ? "</A>" : "")); 1201 }
1251 } else if (state.errorCode == URI_ERROR_MALLOC) { 1202 }
1252 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n")); 1203
1253 } 1204 if (verbose >= 2) {
1254 } 1205 printf(_("** scheme: %s\n"), uri_string(uri.scheme, buf, DEFAULT_BUFFER_SIZE));
1255 1206 printf(_("** host: %s\n"), uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE));
1256 if (verbose >= 2) { 1207 printf(_("** port: %s\n"), uri_string(uri.portText, buf, DEFAULT_BUFFER_SIZE));
1257 printf (_("** scheme: %s\n"), 1208 if (uri.hostData.ip4) {
1258 uri_string (uri.scheme, buf, DEFAULT_BUFFER_SIZE)); 1209 inet_ntop(AF_INET, uri.hostData.ip4->data, ipstr, sizeof(ipstr));
1259 printf (_("** host: %s\n"), 1210 printf(_("** IPv4: %s\n"), ipstr);
1260 uri_string (uri.hostText, buf, DEFAULT_BUFFER_SIZE)); 1211 }
1261 printf (_("** port: %s\n"), 1212 if (uri.hostData.ip6) {
1262 uri_string (uri.portText, buf, DEFAULT_BUFFER_SIZE)); 1213 inet_ntop(AF_INET, uri.hostData.ip6->data, ipstr, sizeof(ipstr));
1263 if (uri.hostData.ip4) { 1214 printf(_("** IPv6: %s\n"), ipstr);
1264 inet_ntop (AF_INET, uri.hostData.ip4->data, ipstr, sizeof (ipstr)); 1215 }
1265 printf (_("** IPv4: %s\n"), ipstr); 1216 if (uri.pathHead) {
1266 } 1217 printf(_("** path: "));
1267 if (uri.hostData.ip6) { 1218 const UriPathSegmentA *p = uri.pathHead;
1268 inet_ntop (AF_INET, uri.hostData.ip6->data, ipstr, sizeof (ipstr)); 1219 for (; p; p = p->next) {
1269 printf (_("** IPv6: %s\n"), ipstr); 1220 printf("/%s", uri_string(p->text, buf, DEFAULT_BUFFER_SIZE));
1270 } 1221 }
1271 if (uri.pathHead) { 1222 puts("");
1272 printf (_("** path: ")); 1223 }
1273 const UriPathSegmentA* p = uri.pathHead; 1224 if (uri.query.first) {
1274 for (; p; p = p->next) { 1225 printf(_("** query: %s\n"), uri_string(uri.query, buf, DEFAULT_BUFFER_SIZE));
1275 printf ("/%s", uri_string (p->text, buf, DEFAULT_BUFFER_SIZE)); 1226 }
1276 } 1227 if (uri.fragment.first) {
1277 puts (""); 1228 printf(_("** fragment: %s\n"), uri_string(uri.fragment, buf, DEFAULT_BUFFER_SIZE));
1278 } 1229 }
1279 if (uri.query.first) { 1230 }
1280 printf (_("** query: %s\n"), 1231
1281 uri_string (uri.query, buf, DEFAULT_BUFFER_SIZE)); 1232 if (uri.scheme.first) {
1282 } 1233 if (!uri_strcmp(uri.scheme, "https"))
1283 if (uri.fragment.first) { 1234 use_ssl = true;
1284 printf (_("** fragment: %s\n"), 1235 else
1285 uri_string (uri.fragment, buf, DEFAULT_BUFFER_SIZE)); 1236 use_ssl = false;
1286 } 1237 }
1287 } 1238
1288 1239 /* we do a sloppy test here only, because uriparser would have failed
1289 if (uri.scheme.first) { 1240 * above, if the port would be invalid, we just check for MAX_PORT
1290 if (!uri_strcmp (uri.scheme, "https")) 1241 */
1291 use_ssl = true; 1242 if (uri.portText.first) {
1292 else 1243 new_port = atoi(uri_string(uri.portText, buf, DEFAULT_BUFFER_SIZE));
1293 use_ssl = false; 1244 } else {
1294 } 1245 new_port = HTTP_PORT;
1295 1246 if (use_ssl)
1296 /* we do a sloppy test here only, because uriparser would have failed 1247 new_port = HTTPS_PORT;
1297 * above, if the port would be invalid, we just check for MAX_PORT 1248 }
1298 */ 1249 if (new_port > MAX_PORT)
1299 if (uri.portText.first) { 1250 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Redirection to port above %d - %s%s\n"), MAX_PORT, location, display_html ? "</A>" : "");
1300 new_port = atoi (uri_string (uri.portText, buf, DEFAULT_BUFFER_SIZE)); 1251
1301 } else { 1252 /* by RFC 7231 relative URLs in Location should be taken relative to
1302 new_port = HTTP_PORT; 1253 * the original URL, so we try to form a new absolute URL here
1303 if (use_ssl) 1254 */
1304 new_port = HTTPS_PORT; 1255 if (!uri.scheme.first && !uri.hostText.first) {
1305 } 1256 new_host = strdup(host_name ? host_name : server_address);
1306 if (new_port > MAX_PORT) 1257 new_port = server_port;
1307 die (STATE_UNKNOWN, 1258 if (use_ssl)
1308 _("HTTP UNKNOWN - Redirection to port above %d - %s%s\n"), 1259 uri_string(uri.scheme, "https", DEFAULT_BUFFER_SIZE);
1309 MAX_PORT, location, display_html ? "</A>" : ""); 1260 } else {
1310 1261 new_host = strdup(uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE));
1311 /* by RFC 7231 relative URLs in Location should be taken relative to 1262 }
1312 * the original URL, so we try to form a new absolute URL here 1263
1313 */ 1264 /* compose new path */
1314 if (!uri.scheme.first && !uri.hostText.first) { 1265 /* TODO: handle fragments and query part of URL */
1315 new_host = strdup (host_name ? host_name : server_address); 1266 new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE);
1316 new_port = server_port; 1267 if (uri.pathHead) {
1317 if(use_ssl) 1268 const UriPathSegmentA *p = uri.pathHead;
1318 uri_string (uri.scheme, "https", DEFAULT_BUFFER_SIZE); 1269 for (; p; p = p->next) {
1319 } else { 1270 strncat(new_url, "/", DEFAULT_BUFFER_SIZE);
1320 new_host = strdup (uri_string (uri.hostText, buf, DEFAULT_BUFFER_SIZE)); 1271 strncat(new_url, uri_string(p->text, buf, DEFAULT_BUFFER_SIZE), DEFAULT_BUFFER_SIZE - 1);
1321 } 1272 }
1322 1273 }
1323 /* compose new path */ 1274
1324 /* TODO: handle fragments and query part of URL */ 1275 if (server_port == new_port && !strncmp(server_address, new_host, MAX_IPV4_HOSTLENGTH) &&
1325 new_url = (char *)calloc( 1, DEFAULT_BUFFER_SIZE); 1276 (host_name && !strncmp(host_name, new_host, MAX_IPV4_HOSTLENGTH)) && !strcmp(server_url, new_url))
1326 if (uri.pathHead) { 1277 die(STATE_CRITICAL, _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"), use_ssl ? "https" : "http",
1327 const UriPathSegmentA* p = uri.pathHead; 1278 new_host, new_port, new_url, (display_html ? "</A>" : ""));
1328 for (; p; p = p->next) { 1279
1329 strncat (new_url, "/", DEFAULT_BUFFER_SIZE); 1280 /* set new values for redirected request */
1330 strncat (new_url, uri_string (p->text, buf, DEFAULT_BUFFER_SIZE), DEFAULT_BUFFER_SIZE-1); 1281
1331 } 1282 if (!(followsticky & STICKY_HOST)) {
1332 } 1283 free(server_address);
1333 1284 server_address = strndup(new_host, MAX_IPV4_HOSTLENGTH);
1334 if (server_port==new_port && 1285 }
1335 !strncmp(server_address, new_host, MAX_IPV4_HOSTLENGTH) && 1286 if (!(followsticky & STICKY_PORT)) {
1336 (host_name && !strncmp(host_name, new_host, MAX_IPV4_HOSTLENGTH)) && 1287 server_port = (unsigned short)new_port;
1337 !strcmp(server_url, new_url)) 1288 }
1338 die (STATE_CRITICAL, 1289
1339 _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"), 1290 free(host_name);
1340 use_ssl ? "https" : "http", new_host, new_port, new_url, (display_html ? "</A>" : "")); 1291 host_name = strndup(new_host, MAX_IPV4_HOSTLENGTH);
1341 1292
1342 /* set new values for redirected request */ 1293 /* reset virtual port */
1343 1294 virtual_port = server_port;
1344 if (!(followsticky & STICKY_HOST)) { 1295
1345 free (server_address); 1296 free(new_host);
1346 server_address = strndup (new_host, MAX_IPV4_HOSTLENGTH); 1297 free(server_url);
1347 } 1298 server_url = new_url;
1348 if (!(followsticky & STICKY_PORT)) { 1299
1349 server_port = (unsigned short)new_port; 1300 uriFreeUriMembersA(&uri);
1350 } 1301
1351 1302 if (verbose)
1352 free (host_name); 1303 printf(_("Redirection to %s://%s:%d%s\n"), use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port,
1353 host_name = strndup (new_host, MAX_IPV4_HOSTLENGTH); 1304 server_url);
1354 1305
1355 /* reset virtual port */ 1306 /* TODO: the hash component MUST be taken from the original URL and
1356 virtual_port = server_port; 1307 * attached to the URL in Location
1357 1308 */
1358 free(new_host); 1309
1359 free (server_url); 1310 cleanup();
1360 server_url = new_url; 1311 check_http();
1361
1362 uriFreeUriMembersA (&uri);
1363
1364 if (verbose)
1365 printf (_("Redirection to %s://%s:%d%s\n"), use_ssl ? "https" : "http",
1366 host_name ? host_name : server_address, server_port, server_url);
1367
1368 /* TODO: the hash component MUST be taken from the original URL and
1369 * attached to the URL in Location
1370 */
1371
1372 cleanup ();
1373 check_http ();
1374} 1312}
1375 1313
1376/* check whether a file exists */ 1314/* check whether a file exists */
1377void 1315void test_file(char *path) {
1378test_file (char *path) 1316 if (access(path, R_OK) == 0)
1379{ 1317 return;
1380 if (access(path, R_OK) == 0) 1318 usage2(_("file does not exist or is not readable"), path);
1381 return;
1382 usage2 (_("file does not exist or is not readable"), path);
1383} 1319}
1384 1320
1385bool 1321bool process_arguments(int argc, char **argv) {
1386process_arguments (int argc, char **argv) 1322 char *p;
1387{ 1323 int c = 1;
1388 char *p; 1324 char *temp;
1389 int c = 1; 1325
1390 char *temp; 1326 enum {
1391 1327 INVERT_REGEX = CHAR_MAX + 1,
1392 enum { 1328 SNI_OPTION,
1393 INVERT_REGEX = CHAR_MAX + 1, 1329 MAX_REDIRS_OPTION,
1394 SNI_OPTION, 1330 CONTINUE_AFTER_CHECK_CERT,
1395 MAX_REDIRS_OPTION, 1331 CA_CERT_OPTION,
1396 CONTINUE_AFTER_CHECK_CERT, 1332 HTTP_VERSION_OPTION,
1397 CA_CERT_OPTION, 1333 AUTOMATIC_DECOMPRESSION,
1398 HTTP_VERSION_OPTION, 1334 COOKIE_JAR,
1399 AUTOMATIC_DECOMPRESSION, 1335 HAPROXY_PROTOCOL,
1400 COOKIE_JAR, 1336 STATE_REGEX
1401 HAPROXY_PROTOCOL, 1337 };
1402 STATE_REGEX 1338
1403 }; 1339 int option = 0;
1404 1340 int got_plus = 0;
1405 int option = 0; 1341 static struct option longopts[] = {STD_LONG_OPTS,
1406 int got_plus = 0; 1342 {"link", no_argument, 0, 'L'},
1407 static struct option longopts[] = { 1343 {"nohtml", no_argument, 0, 'n'},
1408 STD_LONG_OPTS, 1344 {"ssl", optional_argument, 0, 'S'},
1409 {"link", no_argument, 0, 'L'}, 1345 {"sni", no_argument, 0, SNI_OPTION},
1410 {"nohtml", no_argument, 0, 'n'}, 1346 {"post", required_argument, 0, 'P'},
1411 {"ssl", optional_argument, 0, 'S'}, 1347 {"method", required_argument, 0, 'j'},
1412 {"sni", no_argument, 0, SNI_OPTION}, 1348 {"IP-address", required_argument, 0, 'I'},
1413 {"post", required_argument, 0, 'P'}, 1349 {"url", required_argument, 0, 'u'},
1414 {"method", required_argument, 0, 'j'}, 1350 {"port", required_argument, 0, 'p'},
1415 {"IP-address", required_argument, 0, 'I'}, 1351 {"authorization", required_argument, 0, 'a'},
1416 {"url", required_argument, 0, 'u'}, 1352 {"proxy-authorization", required_argument, 0, 'b'},
1417 {"port", required_argument, 0, 'p'}, 1353 {"header-string", required_argument, 0, 'd'},
1418 {"authorization", required_argument, 0, 'a'}, 1354 {"string", required_argument, 0, 's'},
1419 {"proxy-authorization", required_argument, 0, 'b'}, 1355 {"expect", required_argument, 0, 'e'},
1420 {"header-string", required_argument, 0, 'd'}, 1356 {"regex", required_argument, 0, 'r'},
1421 {"string", required_argument, 0, 's'}, 1357 {"ereg", required_argument, 0, 'r'},
1422 {"expect", required_argument, 0, 'e'}, 1358 {"eregi", required_argument, 0, 'R'},
1423 {"regex", required_argument, 0, 'r'}, 1359 {"linespan", no_argument, 0, 'l'},
1424 {"ereg", required_argument, 0, 'r'}, 1360 {"onredirect", required_argument, 0, 'f'},
1425 {"eregi", required_argument, 0, 'R'}, 1361 {"certificate", required_argument, 0, 'C'},
1426 {"linespan", no_argument, 0, 'l'}, 1362 {"client-cert", required_argument, 0, 'J'},
1427 {"onredirect", required_argument, 0, 'f'}, 1363 {"private-key", required_argument, 0, 'K'},
1428 {"certificate", required_argument, 0, 'C'}, 1364 {"ca-cert", required_argument, 0, CA_CERT_OPTION},
1429 {"client-cert", required_argument, 0, 'J'}, 1365 {"verify-cert", no_argument, 0, 'D'},
1430 {"private-key", required_argument, 0, 'K'}, 1366 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT},
1431 {"ca-cert", required_argument, 0, CA_CERT_OPTION}, 1367 {"useragent", required_argument, 0, 'A'},
1432 {"verify-cert", no_argument, 0, 'D'}, 1368 {"header", required_argument, 0, 'k'},
1433 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT}, 1369 {"no-body", no_argument, 0, 'N'},
1434 {"useragent", required_argument, 0, 'A'}, 1370 {"max-age", required_argument, 0, 'M'},
1435 {"header", required_argument, 0, 'k'}, 1371 {"content-type", required_argument, 0, 'T'},
1436 {"no-body", no_argument, 0, 'N'}, 1372 {"pagesize", required_argument, 0, 'm'},
1437 {"max-age", required_argument, 0, 'M'}, 1373 {"invert-regex", no_argument, NULL, INVERT_REGEX},
1438 {"content-type", required_argument, 0, 'T'}, 1374 {"state-regex", required_argument, 0, STATE_REGEX},
1439 {"pagesize", required_argument, 0, 'm'}, 1375 {"use-ipv4", no_argument, 0, '4'},
1440 {"invert-regex", no_argument, NULL, INVERT_REGEX}, 1376 {"use-ipv6", no_argument, 0, '6'},
1441 {"state-regex", required_argument, 0, STATE_REGEX}, 1377 {"extended-perfdata", no_argument, 0, 'E'},
1442 {"use-ipv4", no_argument, 0, '4'}, 1378 {"show-body", no_argument, 0, 'B'},
1443 {"use-ipv6", no_argument, 0, '6'}, 1379 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION},
1444 {"extended-perfdata", no_argument, 0, 'E'}, 1380 {"http-version", required_argument, 0, HTTP_VERSION_OPTION},
1445 {"show-body", no_argument, 0, 'B'}, 1381 {"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION},
1446 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION}, 1382 {"cookie-jar", required_argument, 0, COOKIE_JAR},
1447 {"http-version", required_argument, 0, HTTP_VERSION_OPTION}, 1383 {"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL},
1448 {"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION}, 1384 {0, 0, 0, 0}};
1449 {"cookie-jar", required_argument, 0, COOKIE_JAR}, 1385
1450 {"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL}, 1386 if (argc < 2)
1451 {0, 0, 0, 0} 1387 return false;
1452 }; 1388
1453 1389 /* support check_http compatible arguments */
1454 if (argc < 2) 1390 for (c = 1; c < argc; c++) {
1455 return false; 1391 if (strcmp("-to", argv[c]) == 0)
1456 1392 strcpy(argv[c], "-t");
1457 /* support check_http compatible arguments */ 1393 if (strcmp("-hn", argv[c]) == 0)
1458 for (c = 1; c < argc; c++) { 1394 strcpy(argv[c], "-H");
1459 if (strcmp ("-to", argv[c]) == 0) 1395 if (strcmp("-wt", argv[c]) == 0)
1460 strcpy (argv[c], "-t"); 1396 strcpy(argv[c], "-w");
1461 if (strcmp ("-hn", argv[c]) == 0) 1397 if (strcmp("-ct", argv[c]) == 0)
1462 strcpy (argv[c], "-H"); 1398 strcpy(argv[c], "-c");
1463 if (strcmp ("-wt", argv[c]) == 0) 1399 if (strcmp("-nohtml", argv[c]) == 0)
1464 strcpy (argv[c], "-w"); 1400 strcpy(argv[c], "-n");
1465 if (strcmp ("-ct", argv[c]) == 0) 1401 }
1466 strcpy (argv[c], "-c"); 1402
1467 if (strcmp ("-nohtml", argv[c]) == 0) 1403 server_url = strdup(DEFAULT_SERVER_URL);
1468 strcpy (argv[c], "-n"); 1404
1469 } 1405 while (1) {
1470 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);
1471 server_url = strdup(DEFAULT_SERVER_URL); 1407 if (c == -1 || c == EOF || c == 1)
1472 1408 break;
1473 while (1) { 1409
1474 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); 1410 switch (c) {
1475 if (c == -1 || c == EOF || c == 1) 1411 case 'h':
1476 break; 1412 print_help();
1477 1413 exit(STATE_UNKNOWN);
1478 switch (c) { 1414 break;
1479 case 'h': 1415 case 'V':
1480 print_help(); 1416 print_revision(progname, NP_VERSION);
1481 exit(STATE_UNKNOWN); 1417 print_curl_version();
1482 break; 1418 exit(STATE_UNKNOWN);
1483 case 'V': 1419 break;
1484 print_revision(progname, NP_VERSION); 1420 case 'v':
1485 print_curl_version(); 1421 verbose++;
1486 exit(STATE_UNKNOWN); 1422 break;
1487 break; 1423 case 't': /* timeout period */
1488 case 'v': 1424 if (!is_intnonneg(optarg))
1489 verbose++; 1425 usage2(_("Timeout interval must be a positive integer"), optarg);
1490 break; 1426 else
1491 case 't': /* timeout period */ 1427 socket_timeout = (int)strtol(optarg, NULL, 10);
1492 if (!is_intnonneg (optarg)) 1428 break;
1493 usage2 (_("Timeout interval must be a positive integer"), optarg); 1429 case 'c': /* critical time threshold */
1494 else 1430 critical_thresholds = optarg;
1495 socket_timeout = (int)strtol (optarg, NULL, 10); 1431 break;
1496 break; 1432 case 'w': /* warning time threshold */
1497 case 'c': /* critical time threshold */ 1433 warning_thresholds = optarg;
1498 critical_thresholds = optarg; 1434 break;
1499 break; 1435 case 'H': /* virtual host */
1500 case 'w': /* warning time threshold */ 1436 host_name = strdup(optarg);
1501 warning_thresholds = optarg; 1437 if (host_name[0] == '[') {
1502 break; 1438 if ((p = strstr(host_name, "]:")) != NULL) { /* [IPv6]:port */
1503 case 'H': /* virtual host */ 1439 virtual_port = atoi(p + 2);
1504 host_name = strdup (optarg); 1440 /* cut off the port */
1505 if (host_name[0] == '[') { 1441 host_name_length = strlen(host_name) - strlen(p) - 1;
1506 if ((p = strstr (host_name, "]:")) != NULL) { /* [IPv6]:port */ 1442 free(host_name);
1507 virtual_port = atoi (p + 2); 1443 host_name = strndup(optarg, host_name_length);
1508 /* cut off the port */ 1444 }
1509 host_name_length = strlen (host_name) - strlen (p) - 1; 1445 } else if ((p = strchr(host_name, ':')) != NULL && strchr(++p, ':') == NULL) { /* IPv4:port or host:port */
1510 free (host_name); 1446 virtual_port = atoi(p);
1511 host_name = strndup (optarg, host_name_length); 1447 /* cut off the port */
1512 } 1448 host_name_length = strlen(host_name) - strlen(p) - 1;
1513 } else if ((p = strchr (host_name, ':')) != NULL 1449 free(host_name);
1514 && strchr (++p, ':') == NULL) { /* IPv4:port or host:port */ 1450 host_name = strndup(optarg, host_name_length);
1515 virtual_port = atoi (p); 1451 }
1516 /* cut off the port */ 1452 break;
1517 host_name_length = strlen (host_name) - strlen (p) - 1; 1453 case 'I': /* internet address */
1518 free (host_name); 1454 server_address = strdup(optarg);
1519 host_name = strndup (optarg, host_name_length); 1455 break;
1520 } 1456 case 'u': /* URL path */
1521 break; 1457 server_url = strdup(optarg);
1522 case 'I': /* internet address */ 1458 break;
1523 server_address = strdup (optarg); 1459 case 'p': /* Server port */
1524 break; 1460 if (!is_intnonneg(optarg))
1525 case 'u': /* URL path */ 1461 usage2(_("Invalid port number, expecting a non-negative number"), optarg);
1526 server_url = strdup (optarg); 1462 else {
1527 break; 1463 if (strtol(optarg, NULL, 10) > MAX_PORT)
1528 case 'p': /* Server port */ 1464 usage2(_("Invalid port number, supplied port number is too big"), optarg);
1529 if (!is_intnonneg (optarg)) 1465 server_port = (unsigned short)strtol(optarg, NULL, 10);
1530 usage2 (_("Invalid port number, expecting a non-negative number"), optarg); 1466 specify_port = true;
1531 else { 1467 }
1532 if( strtol(optarg, NULL, 10) > MAX_PORT) 1468 break;
1533 usage2 (_("Invalid port number, supplied port number is too big"), optarg); 1469 case 'a': /* authorization info */
1534 server_port = (unsigned short)strtol(optarg, NULL, 10); 1470 strncpy(user_auth, optarg, MAX_INPUT_BUFFER - 1);
1535 specify_port = true; 1471 user_auth[MAX_INPUT_BUFFER - 1] = 0;
1536 } 1472 break;
1537 break; 1473 case 'b': /* proxy-authorization info */
1538 case 'a': /* authorization info */ 1474 strncpy(proxy_auth, optarg, MAX_INPUT_BUFFER - 1);
1539 strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1); 1475 proxy_auth[MAX_INPUT_BUFFER - 1] = 0;
1540 user_auth[MAX_INPUT_BUFFER - 1] = 0; 1476 break;
1541 break; 1477 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
1542 case 'b': /* proxy-authorization info */ 1478 if (!http_post_data)
1543 strncpy (proxy_auth, optarg, MAX_INPUT_BUFFER - 1); 1479 http_post_data = strdup(optarg);
1544 proxy_auth[MAX_INPUT_BUFFER - 1] = 0; 1480 if (!http_method)
1545 break; 1481 http_method = strdup("POST");
1546 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */ 1482 break;
1547 if (! http_post_data) 1483 case 'j': /* Set HTTP method */
1548 http_post_data = strdup (optarg); 1484 if (http_method)
1549 if (! http_method) 1485 free(http_method);
1550 http_method = strdup("POST"); 1486 http_method = strdup(optarg);
1551 break; 1487 break;
1552 case 'j': /* Set HTTP method */ 1488 case 'A': /* useragent */
1553 if (http_method) 1489 strncpy(user_agent, optarg, DEFAULT_BUFFER_SIZE);
1554 free(http_method); 1490 user_agent[DEFAULT_BUFFER_SIZE - 1] = '\0';
1555 http_method = strdup (optarg); 1491 break;
1556 break; 1492 case 'k': /* Additional headers */
1557 case 'A': /* useragent */ 1493 if (http_opt_headers_count == 0)
1558 strncpy (user_agent, optarg, DEFAULT_BUFFER_SIZE); 1494 http_opt_headers = malloc(sizeof(char *) * (++http_opt_headers_count));
1559 user_agent[DEFAULT_BUFFER_SIZE-1] = '\0'; 1495 else
1560 break; 1496 http_opt_headers = realloc(http_opt_headers, sizeof(char *) * (++http_opt_headers_count));
1561 case 'k': /* Additional headers */ 1497 http_opt_headers[http_opt_headers_count - 1] = optarg;
1562 if (http_opt_headers_count == 0) 1498 break;
1563 http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count)); 1499 case 'L': /* show html link */
1564 else 1500 display_html = true;
1565 http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count)); 1501 break;
1566 http_opt_headers[http_opt_headers_count - 1] = optarg; 1502 case 'n': /* do not show html link */
1567 break; 1503 display_html = false;
1568 case 'L': /* show html link */ 1504 break;
1569 display_html = true; 1505 case 'C': /* Check SSL cert validity */
1570 break;
1571 case 'n': /* do not show html link */
1572 display_html = false;
1573 break;
1574 case 'C': /* Check SSL cert validity */
1575#ifdef LIBCURL_FEATURE_SSL 1506#ifdef LIBCURL_FEATURE_SSL
1576 if ((temp=strchr(optarg,','))!=NULL) { 1507 if ((temp = strchr(optarg, ',')) != NULL) {
1577 *temp='\0'; 1508 *temp = '\0';
1578 if (!is_intnonneg (optarg)) 1509 if (!is_intnonneg(optarg))
1579 usage2 (_("Invalid certificate expiration period"), optarg); 1510 usage2(_("Invalid certificate expiration period"), optarg);
1580 days_till_exp_warn = atoi(optarg); 1511 days_till_exp_warn = atoi(optarg);
1581 *temp=','; 1512 *temp = ',';
1582 temp++; 1513 temp++;
1583 if (!is_intnonneg (temp)) 1514 if (!is_intnonneg(temp))
1584 usage2 (_("Invalid certificate expiration period"), temp); 1515 usage2(_("Invalid certificate expiration period"), temp);
1585 days_till_exp_crit = atoi (temp); 1516 days_till_exp_crit = atoi(temp);
1586 } 1517 } else {
1587 else { 1518 days_till_exp_crit = 0;
1588 days_till_exp_crit=0; 1519 if (!is_intnonneg(optarg))
1589 if (!is_intnonneg (optarg)) 1520 usage2(_("Invalid certificate expiration period"), optarg);
1590 usage2 (_("Invalid certificate expiration period"), optarg); 1521 days_till_exp_warn = atoi(optarg);
1591 days_till_exp_warn = atoi (optarg); 1522 }
1592 } 1523 check_cert = true;
1593 check_cert = true; 1524 goto enable_ssl;
1594 goto enable_ssl;
1595#endif 1525#endif
1596 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */ 1526 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
1597#ifdef HAVE_SSL 1527#ifdef HAVE_SSL
1598 continue_after_check_cert = true; 1528 continue_after_check_cert = true;
1599 break; 1529 break;
1600#endif 1530#endif
1601 case 'J': /* use client certificate */ 1531 case 'J': /* use client certificate */
1602#ifdef LIBCURL_FEATURE_SSL 1532#ifdef LIBCURL_FEATURE_SSL
1603 test_file(optarg); 1533 test_file(optarg);
1604 client_cert = optarg; 1534 client_cert = optarg;
1605 goto enable_ssl; 1535 goto enable_ssl;
1606#endif 1536#endif
1607 case 'K': /* use client private key */ 1537 case 'K': /* use client private key */
1608#ifdef LIBCURL_FEATURE_SSL 1538#ifdef LIBCURL_FEATURE_SSL
1609 test_file(optarg); 1539 test_file(optarg);
1610 client_privkey = optarg; 1540 client_privkey = optarg;
1611 goto enable_ssl; 1541 goto enable_ssl;
1612#endif 1542#endif
1613#ifdef LIBCURL_FEATURE_SSL 1543#ifdef LIBCURL_FEATURE_SSL
1614 case CA_CERT_OPTION: /* use CA chain file */ 1544 case CA_CERT_OPTION: /* use CA chain file */
1615 test_file(optarg); 1545 test_file(optarg);
1616 ca_cert = optarg; 1546 ca_cert = optarg;
1617 goto enable_ssl; 1547 goto enable_ssl;
1618#endif 1548#endif
1619#ifdef LIBCURL_FEATURE_SSL 1549#ifdef LIBCURL_FEATURE_SSL
1620 case 'D': /* verify peer certificate & host */ 1550 case 'D': /* verify peer certificate & host */
1621 verify_peer_and_host = true; 1551 verify_peer_and_host = true;
1622 break; 1552 break;
1623#endif 1553#endif
1624 case 'S': /* use SSL */ 1554 case 'S': /* use SSL */
1625#ifdef LIBCURL_FEATURE_SSL 1555#ifdef LIBCURL_FEATURE_SSL
1626 enable_ssl: 1556 enable_ssl:
1627 use_ssl = true; 1557 use_ssl = true;
1628 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default. 1558 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default.
1629 * Only set if it's non-zero. This helps when we include multiple 1559 * Only set if it's non-zero. This helps when we include multiple
1630 * parameters, like -S and -C combinations */ 1560 * parameters, like -S and -C combinations */
1631 ssl_version = CURL_SSLVERSION_DEFAULT; 1561 ssl_version = CURL_SSLVERSION_DEFAULT;
1632 if (c=='S' && optarg != NULL) { 1562 if (c == 'S' && optarg != NULL) {
1633 char *plus_ptr = strchr(optarg, '+'); 1563 char *plus_ptr = strchr(optarg, '+');
1634 if (plus_ptr) { 1564 if (plus_ptr) {
1635 got_plus = 1; 1565 got_plus = 1;
1636 *plus_ptr = '\0'; 1566 *plus_ptr = '\0';
1637 } 1567 }
1638 1568
1639 if (optarg[0] == '2') 1569 if (optarg[0] == '2')
1640 ssl_version = CURL_SSLVERSION_SSLv2; 1570 ssl_version = CURL_SSLVERSION_SSLv2;
1641 else if (optarg[0] == '3') 1571 else if (optarg[0] == '3')
1642 ssl_version = CURL_SSLVERSION_SSLv3; 1572 ssl_version = CURL_SSLVERSION_SSLv3;
1643 else if (!strcmp (optarg, "1") || !strcmp (optarg, "1.0")) 1573 else if (!strcmp(optarg, "1") || !strcmp(optarg, "1.0"))
1644#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1574# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1645 ssl_version = CURL_SSLVERSION_TLSv1_0; 1575 ssl_version = CURL_SSLVERSION_TLSv1_0;
1646#else 1576# else
1647 ssl_version = CURL_SSLVERSION_DEFAULT; 1577 ssl_version = CURL_SSLVERSION_DEFAULT;
1648#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1578# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1649 else if (!strcmp (optarg, "1.1")) 1579 else if (!strcmp(optarg, "1.1"))
1650#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1580# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1651 ssl_version = CURL_SSLVERSION_TLSv1_1; 1581 ssl_version = CURL_SSLVERSION_TLSv1_1;
1652#else 1582# else
1653 ssl_version = CURL_SSLVERSION_DEFAULT; 1583 ssl_version = CURL_SSLVERSION_DEFAULT;
1654#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1584# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1655 else if (!strcmp (optarg, "1.2")) 1585 else if (!strcmp(optarg, "1.2"))
1656#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1586# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1657 ssl_version = CURL_SSLVERSION_TLSv1_2; 1587 ssl_version = CURL_SSLVERSION_TLSv1_2;
1658#else 1588# else
1659 ssl_version = CURL_SSLVERSION_DEFAULT; 1589 ssl_version = CURL_SSLVERSION_DEFAULT;
1660#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1590# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1661 else if (!strcmp (optarg, "1.3")) 1591 else if (!strcmp(optarg, "1.3"))
1662#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) 1592# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0)
1663 ssl_version = CURL_SSLVERSION_TLSv1_3; 1593 ssl_version = CURL_SSLVERSION_TLSv1_3;
1664#else 1594# else
1665 ssl_version = CURL_SSLVERSION_DEFAULT; 1595 ssl_version = CURL_SSLVERSION_DEFAULT;
1666#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */ 1596# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */
1667 else 1597 else
1668 usage4 (_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2, 1.3 (with optional '+' suffix)")); 1598 usage4(_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2, 1.3 (with optional '+' suffix)"));
1669 } 1599 }
1670#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) 1600# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0)
1671 if (got_plus) { 1601 if (got_plus) {
1672 switch (ssl_version) { 1602 switch (ssl_version) {
1673 case CURL_SSLVERSION_TLSv1_3: 1603 case CURL_SSLVERSION_TLSv1_3:
1674 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3; 1604 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1675 break; 1605 break;
1676 case CURL_SSLVERSION_TLSv1_2: 1606 case CURL_SSLVERSION_TLSv1_2:
1677 case CURL_SSLVERSION_TLSv1_1: 1607 case CURL_SSLVERSION_TLSv1_1:
1678 case CURL_SSLVERSION_TLSv1_0: 1608 case CURL_SSLVERSION_TLSv1_0:
1679 ssl_version |= CURL_SSLVERSION_MAX_DEFAULT; 1609 ssl_version |= CURL_SSLVERSION_MAX_DEFAULT;
1680 break; 1610 break;
1681 } 1611 }
1682 } else { 1612 } else {
1683 switch (ssl_version) { 1613 switch (ssl_version) {
1684 case CURL_SSLVERSION_TLSv1_3: 1614 case CURL_SSLVERSION_TLSv1_3:
1685 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3; 1615 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1686 break; 1616 break;
1687 case CURL_SSLVERSION_TLSv1_2: 1617 case CURL_SSLVERSION_TLSv1_2:
1688 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2; 1618 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2;
1689 break; 1619 break;
1690 case CURL_SSLVERSION_TLSv1_1: 1620 case CURL_SSLVERSION_TLSv1_1:
1691 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1; 1621 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1;
1692 break; 1622 break;
1693 case CURL_SSLVERSION_TLSv1_0: 1623 case CURL_SSLVERSION_TLSv1_0:
1694 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0; 1624 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0;
1695 break; 1625 break;
1696 } 1626 }
1697 } 1627 }
1698#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */ 1628# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */
1699 if (verbose >= 2) 1629 if (verbose >= 2)
1700 printf(_("* Set SSL/TLS version to %d\n"), ssl_version); 1630 printf(_("* Set SSL/TLS version to %d\n"), ssl_version);
1701 if (!specify_port) 1631 if (!specify_port)
1702 server_port = HTTPS_PORT; 1632 server_port = HTTPS_PORT;
1703 break; 1633 break;
1704#else /* LIBCURL_FEATURE_SSL */ 1634#else /* LIBCURL_FEATURE_SSL */
1705 /* -C -J and -K fall through to here without SSL */ 1635 /* -C -J and -K fall through to here without SSL */
1706 usage4 (_("Invalid option - SSL is not available")); 1636 usage4(_("Invalid option - SSL is not available"));
1707 break; 1637 break;
1708 case SNI_OPTION: /* --sni is parsed, but ignored, the default is true with libcurl */ 1638 case SNI_OPTION: /* --sni is parsed, but ignored, the default is true with libcurl */
1709 use_sni = true; 1639 use_sni = true;
1710 break; 1640 break;
1711#endif /* LIBCURL_FEATURE_SSL */ 1641#endif /* LIBCURL_FEATURE_SSL */
1712 case MAX_REDIRS_OPTION: 1642 case MAX_REDIRS_OPTION:
1713 if (!is_intnonneg (optarg)) 1643 if (!is_intnonneg(optarg))
1714 usage2 (_("Invalid max_redirs count"), optarg); 1644 usage2(_("Invalid max_redirs count"), optarg);
1715 else { 1645 else {
1716 max_depth = atoi (optarg); 1646 max_depth = atoi(optarg);
1717 } 1647 }
1718 break; 1648 break;
1719 case 'f': /* onredirect */ 1649 case 'f': /* onredirect */
1720 if (!strcmp (optarg, "ok")) 1650 if (!strcmp(optarg, "ok"))
1721 onredirect = STATE_OK; 1651 onredirect = STATE_OK;
1722 else if (!strcmp (optarg, "warning")) 1652 else if (!strcmp(optarg, "warning"))
1723 onredirect = STATE_WARNING; 1653 onredirect = STATE_WARNING;
1724 else if (!strcmp (optarg, "critical")) 1654 else if (!strcmp(optarg, "critical"))
1725 onredirect = STATE_CRITICAL; 1655 onredirect = STATE_CRITICAL;
1726 else if (!strcmp (optarg, "unknown")) 1656 else if (!strcmp(optarg, "unknown"))
1727 onredirect = STATE_UNKNOWN; 1657 onredirect = STATE_UNKNOWN;
1728 else if (!strcmp (optarg, "follow")) 1658 else if (!strcmp(optarg, "follow"))
1729 onredirect = STATE_DEPENDENT; 1659 onredirect = STATE_DEPENDENT;
1730 else if (!strcmp (optarg, "stickyport")) 1660 else if (!strcmp(optarg, "stickyport"))
1731 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST|STICKY_PORT; 1661 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST | STICKY_PORT;
1732 else if (!strcmp (optarg, "sticky")) 1662 else if (!strcmp(optarg, "sticky"))
1733 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST; 1663 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST;
1734 else if (!strcmp (optarg, "follow")) 1664 else if (!strcmp(optarg, "follow"))
1735 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_NONE; 1665 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_NONE;
1736 else if (!strcmp (optarg, "curl")) 1666 else if (!strcmp(optarg, "curl"))
1737 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_LIBCURL; 1667 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_LIBCURL;
1738 else usage2 (_("Invalid onredirect option"), optarg); 1668 else
1739 if (verbose >= 2) 1669 usage2(_("Invalid onredirect option"), optarg);
1740 printf(_("* Following redirects set to %s\n"), state_text(onredirect)); 1670 if (verbose >= 2)
1741 break; 1671 printf(_("* Following redirects set to %s\n"), state_text(onredirect));
1742 case 'd': /* string or substring */ 1672 break;
1743 strncpy (header_expect, optarg, MAX_INPUT_BUFFER - 1); 1673 case 'd': /* string or substring */
1744 header_expect[MAX_INPUT_BUFFER - 1] = 0; 1674 strncpy(header_expect, optarg, MAX_INPUT_BUFFER - 1);
1745 break; 1675 header_expect[MAX_INPUT_BUFFER - 1] = 0;
1746 case 's': /* string or substring */ 1676 break;
1747 strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1); 1677 case 's': /* string or substring */
1748 string_expect[MAX_INPUT_BUFFER - 1] = 0; 1678 strncpy(string_expect, optarg, MAX_INPUT_BUFFER - 1);
1749 break; 1679 string_expect[MAX_INPUT_BUFFER - 1] = 0;
1750 case 'e': /* string or substring */ 1680 break;
1751 strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1); 1681 case 'e': /* string or substring */
1752 server_expect[MAX_INPUT_BUFFER - 1] = 0; 1682 strncpy(server_expect, optarg, MAX_INPUT_BUFFER - 1);
1753 server_expect_yn = 1; 1683 server_expect[MAX_INPUT_BUFFER - 1] = 0;
1754 break; 1684 server_expect_yn = 1;
1755 case 'T': /* Content-type */ 1685 break;
1756 http_content_type = strdup (optarg); 1686 case 'T': /* Content-type */
1757 break; 1687 http_content_type = strdup(optarg);
1758 case 'l': /* linespan */ 1688 break;
1759 cflags &= ~REG_NEWLINE; 1689 case 'l': /* linespan */
1760 break; 1690 cflags &= ~REG_NEWLINE;
1761 case 'R': /* regex */ 1691 break;
1762 cflags |= REG_ICASE; 1692 case 'R': /* regex */
1693 cflags |= REG_ICASE;
1763 // fall through 1694 // fall through
1764 case 'r': /* regex */ 1695 case 'r': /* regex */
1765 strncpy (regexp, optarg, MAX_RE_SIZE - 1); 1696 strncpy(regexp, optarg, MAX_RE_SIZE - 1);
1766 regexp[MAX_RE_SIZE - 1] = 0; 1697 regexp[MAX_RE_SIZE - 1] = 0;
1767 errcode = regcomp (&preg, regexp, cflags); 1698 errcode = regcomp(&preg, regexp, cflags);
1768 if (errcode != 0) { 1699 if (errcode != 0) {
1769 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1700 (void)regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1770 printf (_("Could Not Compile Regular Expression: %s"), errbuf); 1701 printf(_("Could Not Compile Regular Expression: %s"), errbuf);
1771 return false; 1702 return false;
1772 } 1703 }
1773 break; 1704 break;
1774 case INVERT_REGEX: 1705 case INVERT_REGEX:
1775 invert_regex = true; 1706 invert_regex = true;
1776 break; 1707 break;
1777 case STATE_REGEX: 1708 case STATE_REGEX:
1778 if (!strcmp (optarg, "critical")) 1709 if (!strcasecmp(optarg, "critical"))
1779 state_regex = STATE_CRITICAL; 1710 state_regex = STATE_CRITICAL;
1780 else if (!strcmp (optarg, "warning")) 1711 else if (!strcasecmp(optarg, "warning"))
1781 state_regex = STATE_WARNING; 1712 state_regex = STATE_WARNING;
1782 else usage2 (_("Invalid state-regex option"), optarg); 1713 else
1783 break; 1714 usage2(_("Invalid state-regex option"), optarg);
1784 case '4': 1715 break;
1785 address_family = AF_INET; 1716 case '4':
1786 break; 1717 address_family = AF_INET;
1787 case '6': 1718 break;
1788#if defined (USE_IPV6) && defined (LIBCURL_FEATURE_IPV6) 1719 case '6':
1789 address_family = AF_INET6; 1720#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6)
1721 address_family = AF_INET6;
1790#else 1722#else
1791 usage4 (_("IPv6 support not available")); 1723 usage4(_("IPv6 support not available"));
1792#endif 1724#endif
1793 break; 1725 break;
1794 case 'm': /* min_page_length */ 1726 case 'm': /* min_page_length */
1795 { 1727 {
1796 char *tmp; 1728 char *tmp;
1797 if (strchr(optarg, ':') != (char *)NULL) { 1729 if (strchr(optarg, ':') != (char *)NULL) {
1798 /* range, so get two values, min:max */ 1730 /* range, so get two values, min:max */
1799 tmp = strtok(optarg, ":"); 1731 tmp = strtok(optarg, ":");
1800 if (tmp == NULL) { 1732 if (tmp == NULL) {
1801 printf("Bad format: try \"-m min:max\"\n"); 1733 printf("Bad format: try \"-m min:max\"\n");
1802 exit (STATE_WARNING); 1734 exit(STATE_WARNING);
1803 } else 1735 } else
1804 min_page_len = atoi(tmp); 1736 min_page_len = atoi(tmp);
1805 1737
1806 tmp = strtok(NULL, ":"); 1738 tmp = strtok(NULL, ":");
1807 if (tmp == NULL) { 1739 if (tmp == NULL) {
1808 printf("Bad format: try \"-m min:max\"\n"); 1740 printf("Bad format: try \"-m min:max\"\n");
1809 exit (STATE_WARNING); 1741 exit(STATE_WARNING);
1810 } else 1742 } else
1811 max_page_len = atoi(tmp); 1743 max_page_len = atoi(tmp);
1812 } else 1744 } else
1813 min_page_len = atoi (optarg); 1745 min_page_len = atoi(optarg);
1814 break; 1746 break;
1815 } 1747 }
1816 case 'N': /* no-body */ 1748 case 'N': /* no-body */
1817 no_body = true; 1749 no_body = true;
1818 break; 1750 break;
1819 case 'M': /* max-age */ 1751 case 'M': /* max-age */
1820 { 1752 {
1821 int L = strlen(optarg); 1753 int L = strlen(optarg);
1822 if (L && optarg[L-1] == 'm') 1754 if (L && optarg[L - 1] == 'm')
1823 maximum_age = atoi (optarg) * 60; 1755 maximum_age = atoi(optarg) * 60;
1824 else if (L && optarg[L-1] == 'h') 1756 else if (L && optarg[L - 1] == 'h')
1825 maximum_age = atoi (optarg) * 60 * 60; 1757 maximum_age = atoi(optarg) * 60 * 60;
1826 else if (L && optarg[L-1] == 'd') 1758 else if (L && optarg[L - 1] == 'd')
1827 maximum_age = atoi (optarg) * 60 * 60 * 24; 1759 maximum_age = atoi(optarg) * 60 * 60 * 24;
1828 else if (L && (optarg[L-1] == 's' || 1760 else if (L && (optarg[L - 1] == 's' || isdigit(optarg[L - 1])))
1829 isdigit (optarg[L-1]))) 1761 maximum_age = atoi(optarg);
1830 maximum_age = atoi (optarg); 1762 else {
1831 else { 1763 fprintf(stderr, "unparsable max-age: %s\n", optarg);
1832 fprintf (stderr, "unparsable max-age: %s\n", optarg); 1764 exit(STATE_WARNING);
1833 exit (STATE_WARNING); 1765 }
1834 } 1766 if (verbose >= 2)
1835 if (verbose >= 2) 1767 printf("* Maximal age of document set to %d seconds\n", maximum_age);
1836 printf ("* Maximal age of document set to %d seconds\n", maximum_age); 1768 } break;
1837 } 1769 case 'E': /* show extended perfdata */
1838 break; 1770 show_extended_perfdata = true;
1839 case 'E': /* show extended perfdata */ 1771 break;
1840 show_extended_perfdata = true; 1772 case 'B': /* print body content after status line */
1841 break; 1773 show_body = true;
1842 case 'B': /* print body content after status line */ 1774 break;
1843 show_body = true; 1775 case HTTP_VERSION_OPTION:
1844 break; 1776 curl_http_version = CURL_HTTP_VERSION_NONE;
1845 case HTTP_VERSION_OPTION: 1777 if (strcmp(optarg, "1.0") == 0) {
1846 curl_http_version = CURL_HTTP_VERSION_NONE; 1778 curl_http_version = CURL_HTTP_VERSION_1_0;
1847 if (strcmp (optarg, "1.0") == 0) { 1779 } else if (strcmp(optarg, "1.1") == 0) {
1848 curl_http_version = CURL_HTTP_VERSION_1_0; 1780 curl_http_version = CURL_HTTP_VERSION_1_1;
1849 } else if (strcmp (optarg, "1.1") == 0) { 1781 } else if ((strcmp(optarg, "2.0") == 0) || (strcmp(optarg, "2") == 0)) {
1850 curl_http_version = CURL_HTTP_VERSION_1_1;
1851 } else if ((strcmp (optarg, "2.0") == 0) || (strcmp (optarg, "2") == 0)) {
1852#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) 1782#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0)
1853 curl_http_version = CURL_HTTP_VERSION_2_0; 1783 curl_http_version = CURL_HTTP_VERSION_2_0;
1854#else 1784#else
1855 curl_http_version = CURL_HTTP_VERSION_NONE; 1785 curl_http_version = CURL_HTTP_VERSION_NONE;
1856#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */ 1786#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */
1857 } else { 1787 } else {
1858 fprintf (stderr, "unknown http-version parameter: %s\n", optarg); 1788 fprintf(stderr, "unknown http-version parameter: %s\n", optarg);
1859 exit (STATE_WARNING); 1789 exit(STATE_WARNING);
1860 } 1790 }
1861 break; 1791 break;
1862 case AUTOMATIC_DECOMPRESSION: 1792 case AUTOMATIC_DECOMPRESSION:
1863 automatic_decompression = true; 1793 automatic_decompression = true;
1864 break; 1794 break;
1865 case COOKIE_JAR: 1795 case COOKIE_JAR:
1866 cookie_jar_file = optarg; 1796 cookie_jar_file = optarg;
1867 break; 1797 break;
1868 case HAPROXY_PROTOCOL: 1798 case HAPROXY_PROTOCOL:
1869 haproxy_protocol = true; 1799 haproxy_protocol = true;
1870 break; 1800 break;
1871 case '?': 1801 case '?':
1872 /* print short usage statement if args not parsable */ 1802 /* print short usage statement if args not parsable */
1873 usage5 (); 1803 usage5();
1874 break; 1804 break;
1875 } 1805 }
1876 } 1806 }
1877 1807
1878 c = optind; 1808 c = optind;
1879 1809
1880 if (server_address == NULL && c < argc) 1810 if (server_address == NULL && c < argc)
1881 server_address = strdup (argv[c++]); 1811 server_address = strdup(argv[c++]);
1882 1812
1883 if (host_name == NULL && c < argc) 1813 if (host_name == NULL && c < argc)
1884 host_name = strdup (argv[c++]); 1814 host_name = strdup(argv[c++]);
1885 1815
1886 if (server_address == NULL) { 1816 if (server_address == NULL) {
1887 if (host_name == NULL) 1817 if (host_name == NULL)
1888 usage4 (_("You must specify a server address or host name")); 1818 usage4(_("You must specify a server address or host name"));
1889 else 1819 else
1890 server_address = strdup (host_name); 1820 server_address = strdup(host_name);
1891 } 1821 }
1892 1822
1893 set_thresholds(&thlds, warning_thresholds, critical_thresholds); 1823 set_thresholds(&thlds, warning_thresholds, critical_thresholds);
1894 1824
1895 if (critical_thresholds && thlds->critical->end>(double)socket_timeout) 1825 if (critical_thresholds && thlds->critical->end > (double)socket_timeout)
1896 socket_timeout = (int)thlds->critical->end + 1; 1826 socket_timeout = (int)thlds->critical->end + 1;
1897 if (verbose >= 2) 1827 if (verbose >= 2)
1898 printf ("* Socket timeout set to %ld seconds\n", socket_timeout); 1828 printf("* Socket timeout set to %ld seconds\n", socket_timeout);
1899 1829
1900 if (http_method == NULL) 1830 if (http_method == NULL)
1901 http_method = strdup ("GET"); 1831 http_method = strdup("GET");
1902 1832
1903 if (client_cert && !client_privkey) 1833 if (client_cert && !client_privkey)
1904 usage4 (_("If you use a client certificate you must also specify a private key file")); 1834 usage4(_("If you use a client certificate you must also specify a private key file"));
1905 1835
1906 if (virtual_port == 0) 1836 if (virtual_port == 0)
1907 virtual_port = server_port; 1837 virtual_port = server_port;
1908 else { 1838 else {
1909 if ((use_ssl && server_port == HTTPS_PORT) || (!use_ssl && server_port == HTTP_PORT)) 1839 if ((use_ssl && server_port == HTTPS_PORT) || (!use_ssl && server_port == HTTP_PORT))
1910 if(!specify_port) 1840 if (!specify_port)
1911 server_port = virtual_port; 1841 server_port = virtual_port;
1912 } 1842 }
1913 1843
1914 return true; 1844 return true;
1915} 1845}
1916 1846
1917char *perfd_time (double elapsed_time) 1847char *perfd_time(double elapsed_time) {
1918{ 1848 return fperfdata("time", elapsed_time, "s", thlds->warning ? true : false, thlds->warning ? thlds->warning->end : 0,
1919 return fperfdata ("time", elapsed_time, "s", 1849 thlds->critical ? true : false, thlds->critical ? thlds->critical->end : 0, true, 0, true, socket_timeout);
1920 thlds->warning?true:false, thlds->warning?thlds->warning->end:0,
1921 thlds->critical?true:false, thlds->critical?thlds->critical->end:0,
1922 true, 0, true, socket_timeout);
1923} 1850}
1924 1851
1925char *perfd_time_connect (double elapsed_time_connect) 1852char *perfd_time_connect(double elapsed_time_connect) {
1926{ 1853 return fperfdata("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1927 return fperfdata ("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1928} 1854}
1929 1855
1930char *perfd_time_ssl (double elapsed_time_ssl) 1856char *perfd_time_ssl(double elapsed_time_ssl) {
1931{ 1857 return fperfdata("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1932 return fperfdata ("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1933} 1858}
1934 1859
1935char *perfd_time_headers (double elapsed_time_headers) 1860char *perfd_time_headers(double elapsed_time_headers) {
1936{ 1861 return fperfdata("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1937 return fperfdata ("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1938} 1862}
1939 1863
1940char *perfd_time_firstbyte (double elapsed_time_firstbyte) 1864char *perfd_time_firstbyte(double elapsed_time_firstbyte) {
1941{ 1865 return fperfdata("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1942 return fperfdata ("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1943} 1866}
1944 1867
1945char *perfd_time_transfer (double elapsed_time_transfer) 1868char *perfd_time_transfer(double elapsed_time_transfer) {
1946{ 1869 return fperfdata("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1947 return fperfdata ("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1948} 1870}
1949 1871
1950char *perfd_size (int page_len) 1872char *perfd_size(int page_len) {
1951{ 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,
1952 return perfdata ("size", page_len, "B", 1874 false, 0);
1953 (min_page_len>0?true:false), min_page_len,
1954 (min_page_len>0?true:false), 0,
1955 true, 0, false, 0);
1956} 1875}
1957 1876
1958void 1877void print_help(void) {
1959print_help (void) 1878 print_revision(progname, NP_VERSION);
1960{
1961 print_revision (progname, NP_VERSION);
1962 1879
1963 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 1880 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1964 printf (COPYRIGHT, copyright, email); 1881 printf(COPYRIGHT, copyright, email);
1965 1882
1966 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test")); 1883 printf("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1967 printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for")); 1884 printf("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1968 printf ("%s\n", _("strings and regular expressions, check connection times, and report on")); 1885 printf("%s\n", _("strings and regular expressions, check connection times, and report on"));
1969 printf ("%s\n", _("certificate expiration times.")); 1886 printf("%s\n", _("certificate expiration times."));
1970 printf ("\n"); 1887 printf("\n");
1971 printf ("%s\n", _("It makes use of libcurl to do so. It tries to be as compatible to check_http")); 1888 printf("%s\n", _("It makes use of libcurl to do so. It tries to be as compatible to check_http"));
1972 printf ("%s\n", _("as possible.")); 1889 printf("%s\n", _("as possible."));
1973 1890
1974 printf ("\n\n"); 1891 printf("\n\n");
1975 1892
1976 print_usage (); 1893 print_usage();
1977 1894
1978 printf (_("NOTE: One or both of -H and -I must be specified")); 1895 printf(_("NOTE: One or both of -H and -I must be specified"));
1979 1896
1980 printf ("\n"); 1897 printf("\n");
1981 1898
1982 printf (UT_HELP_VRSN); 1899 printf(UT_HELP_VRSN);
1983 printf (UT_EXTRA_OPTS); 1900 printf(UT_EXTRA_OPTS);
1984 1901
1985 printf (" %s\n", "-H, --hostname=ADDRESS"); 1902 printf(" %s\n", "-H, --hostname=ADDRESS");
1986 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)")); 1903 printf(" %s\n", _("Host name argument for servers using host headers (virtual host)"));
1987 printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)")); 1904 printf(" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1988 printf (" %s\n", "-I, --IP-address=ADDRESS"); 1905 printf(" %s\n", "-I, --IP-address=ADDRESS");
1989 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup).")); 1906 printf(" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1990 printf (" %s\n", "-p, --port=INTEGER"); 1907 printf(" %s\n", "-p, --port=INTEGER");
1991 printf (" %s", _("Port number (default: ")); 1908 printf(" %s", _("Port number (default: "));
1992 printf ("%d)\n", HTTP_PORT); 1909 printf("%d)\n", HTTP_PORT);
1993 1910
1994 printf (UT_IPv46); 1911 printf(UT_IPv46);
1995 1912
1996#ifdef LIBCURL_FEATURE_SSL 1913#ifdef LIBCURL_FEATURE_SSL
1997 printf (" %s\n", "-S, --ssl=VERSION[+]"); 1914 printf(" %s\n", "-S, --ssl=VERSION[+]");
1998 printf (" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents")); 1915 printf(" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents"));
1999 printf (" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,")); 1916 printf(" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,"));
2000 printf (" %s\n", _("1.2 = TLSv1.2, 1.3 = TLSv1.3). With a '+' suffix, newer versions are also accepted.")); 1917 printf(" %s\n", _("1.2 = TLSv1.2, 1.3 = TLSv1.3). With a '+' suffix, newer versions are also accepted."));
2001 printf (" %s\n", _("Note: SSLv2 and SSLv3 are deprecated and are usually disabled in libcurl")); 1918 printf(" %s\n", _("Note: SSLv2, SSLv3, TLSv1.0 and TLSv1.1 are deprecated and are usually disabled in libcurl"));
2002 printf (" %s\n", "--sni"); 1919 printf(" %s\n", "--sni");
2003 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)")); 1920 printf(" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
2004#if LIBCURL_VERSION_NUM >= 0x071801 1921# if LIBCURL_VERSION_NUM >= 0x071801
2005 printf (" %s\n", _("Note: --sni is the default in libcurl as SSLv2 and SSLV3 are deprecated and")); 1922 printf(" %s\n", _("Note: --sni is the default in libcurl as SSLv2 and SSLV3 are deprecated and"));
2006 printf (" %s\n", _(" SNI only really works since TLSv1.0")); 1923 printf(" %s\n", _(" SNI only really works since TLSv1.0"));
2007#else 1924# else
2008 printf (" %s\n", _("Note: SNI is not supported in libcurl before 7.18.1")); 1925 printf(" %s\n", _("Note: SNI is not supported in libcurl before 7.18.1"));
2009#endif 1926# endif
2010 printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]"); 1927 printf(" %s\n", "-C, --certificate=INTEGER[,INTEGER]");
2011 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443.")); 1928 printf(" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443."));
2012 printf (" %s\n", _("A STATE_WARNING is returned if the certificate has a validity less than the")); 1929 printf(" %s\n", _("A STATE_WARNING is returned if the certificate has a validity less than the"));
2013 printf (" %s\n", _("first agument's value. If there is a second argument and the certificate's")); 1930 printf(" %s\n", _("first agument's value. If there is a second argument and the certificate's"));
2014 printf (" %s\n", _("validity is less than its value, a STATE_CRITICAL is returned.")); 1931 printf(" %s\n", _("validity is less than its value, a STATE_CRITICAL is returned."));
2015 printf (" %s\n", _("(When this option is used the URL is not checked by default. You can use")); 1932 printf(" %s\n", _("(When this option is used the URL is not checked by default. You can use"));
2016 printf (" %s\n", _(" --continue-after-certificate to override this behavior)")); 1933 printf(" %s\n", _(" --continue-after-certificate to override this behavior)"));
2017 printf (" %s\n", "--continue-after-certificate"); 1934 printf(" %s\n", "--continue-after-certificate");
2018 printf (" %s\n", _("Allows the HTTP check to continue after performing the certificate check.")); 1935 printf(" %s\n", _("Allows the HTTP check to continue after performing the certificate check."));
2019 printf (" %s\n", _("Does nothing unless -C is used.")); 1936 printf(" %s\n", _("Does nothing unless -C is used."));
2020 printf (" %s\n", "-J, --client-cert=FILE"); 1937 printf(" %s\n", "-J, --client-cert=FILE");
2021 printf (" %s\n", _("Name of file that contains the client certificate (PEM format)")); 1938 printf(" %s\n", _("Name of file that contains the client certificate (PEM format)"));
2022 printf (" %s\n", _("to be used in establishing the SSL session")); 1939 printf(" %s\n", _("to be used in establishing the SSL session"));
2023 printf (" %s\n", "-K, --private-key=FILE"); 1940 printf(" %s\n", "-K, --private-key=FILE");
2024 printf (" %s\n", _("Name of file containing the private key (PEM format)")); 1941 printf(" %s\n", _("Name of file containing the private key (PEM format)"));
2025 printf (" %s\n", _("matching the client certificate")); 1942 printf(" %s\n", _("matching the client certificate"));
2026 printf (" %s\n", "--ca-cert=FILE"); 1943 printf(" %s\n", "--ca-cert=FILE");
2027 printf (" %s\n", _("CA certificate file to verify peer against")); 1944 printf(" %s\n", _("CA certificate file to verify peer against"));
2028 printf (" %s\n", "-D, --verify-cert"); 1945 printf(" %s\n", "-D, --verify-cert");
2029 printf (" %s\n", _("Verify the peer's SSL certificate and hostname")); 1946 printf(" %s\n", _("Verify the peer's SSL certificate and hostname"));
2030#endif 1947#endif
2031 1948
2032 printf (" %s\n", "-e, --expect=STRING"); 1949 printf(" %s\n", "-e, --expect=STRING");
2033 printf (" %s\n", _("Comma-delimited list of strings, at least one of them is expected in")); 1950 printf(" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
2034 printf (" %s", _("the first (status) line of the server response (default: ")); 1951 printf(" %s", _("the first (status) line of the server response (default: "));
2035 printf ("%s)\n", HTTP_EXPECT); 1952 printf("%s)\n", HTTP_EXPECT);
2036 printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)")); 1953 printf(" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
2037 printf (" %s\n", "-d, --header-string=STRING"); 1954 printf(" %s\n", "-d, --header-string=STRING");
2038 printf (" %s\n", _("String to expect in the response headers")); 1955 printf(" %s\n", _("String to expect in the response headers"));
2039 printf (" %s\n", "-s, --string=STRING"); 1956 printf(" %s\n", "-s, --string=STRING");
2040 printf (" %s\n", _("String to expect in the content")); 1957 printf(" %s\n", _("String to expect in the content"));
2041 printf (" %s\n", "-u, --url=PATH"); 1958 printf(" %s\n", "-u, --url=PATH");
2042 printf (" %s\n", _("URL to GET or POST (default: /)")); 1959 printf(" %s\n", _("URL to GET or POST (default: /)"));
2043 printf (" %s\n", "-P, --post=STRING"); 1960 printf(" %s\n", "-P, --post=STRING");
2044 printf (" %s\n", _("URL decoded http POST data")); 1961 printf(" %s\n", _("URL decoded http POST data"));
2045 printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT)"); 1962 printf(" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT)");
2046 printf (" %s\n", _("Set HTTP method.")); 1963 printf(" %s\n", _("Set HTTP method."));
2047 printf (" %s\n", "-N, --no-body"); 1964 printf(" %s\n", "-N, --no-body");
2048 printf (" %s\n", _("Don't wait for document body: stop reading after headers.")); 1965 printf(" %s\n", _("Don't wait for document body: stop reading after headers."));
2049 printf (" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)")); 1966 printf(" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
2050 printf (" %s\n", "-M, --max-age=SECONDS"); 1967 printf(" %s\n", "-M, --max-age=SECONDS");
2051 printf (" %s\n", _("Warn if document is more than SECONDS old. the number can also be of")); 1968 printf(" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
2052 printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days.")); 1969 printf(" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
2053 printf (" %s\n", "-T, --content-type=STRING"); 1970 printf(" %s\n", "-T, --content-type=STRING");
2054 printf (" %s\n", _("specify Content-Type header media type when POSTing\n")); 1971 printf(" %s\n", _("specify Content-Type header media type when POSTing\n"));
2055 printf (" %s\n", "-l, --linespan"); 1972 printf(" %s\n", "-l, --linespan");
2056 printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)")); 1973 printf(" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
2057 printf (" %s\n", "-r, --regex, --ereg=STRING"); 1974 printf(" %s\n", "-r, --regex, --ereg=STRING");
2058 printf (" %s\n", _("Search page for regex STRING")); 1975 printf(" %s\n", _("Search page for regex STRING"));
2059 printf (" %s\n", "-R, --eregi=STRING"); 1976 printf(" %s\n", "-R, --eregi=STRING");
2060 printf (" %s\n", _("Search page for case-insensitive regex STRING")); 1977 printf(" %s\n", _("Search page for case-insensitive regex STRING"));
2061 printf (" %s\n", "--invert-regex"); 1978 printf(" %s\n", "--invert-regex");
2062 printf (" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)")); 1979 printf(" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)"));
2063 printf (" %s\n", _("can be changed with --state--regex)")); 1980 printf(" %s\n", _("can be changed with --state--regex)"));
2064 printf (" %s\n", "--regex-state=STATE"); 1981 printf(" %s\n", "--state-regex=STATE");
2065 printf (" %s\n", _("Return STATE if regex is found, OK if not\n")); 1982 printf(" %s\n", _("Return STATE if regex is found, OK if not. STATE can be one of \"critical\",\"warning\""));
2066 printf (" %s\n", "-a, --authorization=AUTH_PAIR"); 1983 printf(" %s\n", "-a, --authorization=AUTH_PAIR");
2067 printf (" %s\n", _("Username:password on sites with basic authentication")); 1984 printf(" %s\n", _("Username:password on sites with basic authentication"));
2068 printf (" %s\n", "-b, --proxy-authorization=AUTH_PAIR"); 1985 printf(" %s\n", "-b, --proxy-authorization=AUTH_PAIR");
2069 printf (" %s\n", _("Username:password on proxy-servers with basic authentication")); 1986 printf(" %s\n", _("Username:password on proxy-servers with basic authentication"));
2070 printf (" %s\n", "-A, --useragent=STRING"); 1987 printf(" %s\n", "-A, --useragent=STRING");
2071 printf (" %s\n", _("String to be sent in http header as \"User Agent\"")); 1988 printf(" %s\n", _("String to be sent in http header as \"User Agent\""));
2072 printf (" %s\n", "-k, --header=STRING"); 1989 printf(" %s\n", "-k, --header=STRING");
2073 printf (" %s\n", _("Any other tags to be sent in http header. Use multiple times for additional headers")); 1990 printf(" %s\n", _("Any other tags to be sent in http header. Use multiple times for additional headers"));
2074 printf (" %s\n", "-E, --extended-perfdata"); 1991 printf(" %s\n", "-E, --extended-perfdata");
2075 printf (" %s\n", _("Print additional performance data")); 1992 printf(" %s\n", _("Print additional performance data"));
2076 printf (" %s\n", "-B, --show-body"); 1993 printf(" %s\n", "-B, --show-body");
2077 printf (" %s\n", _("Print body content below status line")); 1994 printf(" %s\n", _("Print body content below status line"));
2078 printf (" %s\n", "-L, --link"); 1995 printf(" %s\n", "-L, --link");
2079 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)")); 1996 printf(" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
2080 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport|curl>"); 1997 printf(" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport|curl>");
2081 printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the")); 1998 printf(" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
2082 printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same.")); 1999 printf(" %s\n", _("specified IP address. stickyport also ensures port stays the same."));
2083 printf (" %s\n", _("follow uses the old redirection algorithm of check_http.")); 2000 printf(" %s\n", _("follow uses the old redirection algorithm of check_http."));
2084 printf (" %s\n", _("curl uses CURL_FOLLOWLOCATION built into libcurl.")); 2001 printf(" %s\n", _("curl uses CURL_FOLLOWLOCATION built into libcurl."));
2085 printf (" %s\n", "--max-redirs=INTEGER"); 2002 printf(" %s\n", "--max-redirs=INTEGER");
2086 printf (" %s", _("Maximal number of redirects (default: ")); 2003 printf(" %s", _("Maximal number of redirects (default: "));
2087 printf ("%d)\n", DEFAULT_MAX_REDIRS); 2004 printf("%d)\n", DEFAULT_MAX_REDIRS);
2088 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>"); 2005 printf(" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
2089 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)")); 2006 printf(" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
2090 printf ("\n"); 2007 printf("\n");
2091 printf (" %s\n", "--http-version=VERSION"); 2008 printf(" %s\n", "--http-version=VERSION");
2092 printf (" %s\n", _("Connect via specific HTTP protocol.")); 2009 printf(" %s\n", _("Connect via specific HTTP protocol."));
2093 printf (" %s\n", _("1.0 = HTTP/1.0, 1.1 = HTTP/1.1, 2.0 = HTTP/2 (HTTP/2 will fail without -S)")); 2010 printf(" %s\n", _("1.0 = HTTP/1.0, 1.1 = HTTP/1.1, 2.0 = HTTP/2 (HTTP/2 will fail without -S)"));
2094 printf (" %s\n", "--enable-automatic-decompression"); 2011 printf(" %s\n", "--enable-automatic-decompression");
2095 printf (" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING).")); 2012 printf(" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING)."));
2096 printf(" %s\n", "--haproxy-protocol"); 2013 printf(" %s\n", "--haproxy-protocol");
2097 printf(" %s\n", _("Send HAProxy proxy protocol v1 header (CURLOPT_HAPROXYPROTOCOL).")); 2014 printf(" %s\n", _("Send HAProxy proxy protocol v1 header (CURLOPT_HAPROXYPROTOCOL)."));
2098 printf (" %s\n", "--cookie-jar=FILE"); 2015 printf(" %s\n", "--cookie-jar=FILE");
2099 printf (" %s\n", _("Store cookies in the cookie jar and send them out when requested.")); 2016 printf(" %s\n", _("Store cookies in the cookie jar and send them out when requested."));
2100 printf ("\n"); 2017 printf(" %s\n", _("Specify an empty string as FILE to enable curl's cookie engine without saving"));
2101 2018 printf(" %s\n", _("the cookies to disk. Only enabling the engine without saving to disk requires"));
2102 printf (UT_WARN_CRIT); 2019 printf(" %s\n", _("handling multiple requests internally to curl, so use it with --onredirect=curl"));
2103 2020 printf("\n");
2104 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 2021
2105 2022 printf(UT_WARN_CRIT);
2106 printf (UT_VERBOSE); 2023
2107 2024 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
2108 printf ("\n"); 2025
2109 printf ("%s\n", _("Notes:")); 2026 printf(UT_VERBOSE);
2110 printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host.")); 2027
2111 printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL")); 2028 printf("\n");
2112 printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response")); 2029 printf("%s\n", _("Notes:"));
2113 printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are")); 2030 printf(" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
2114 printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN")); 2031 printf(" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
2115 printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument.")); 2032 printf(" %s\n", _("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"));
2034 printf(" %s\n", _("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."));
2116 2036
2117#ifdef LIBCURL_FEATURE_SSL 2037#ifdef LIBCURL_FEATURE_SSL
2118 printf ("\n"); 2038 printf("\n");
2119 printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to")); 2039 printf(" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
2120 printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 ")); 2040 printf(" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
2121 printf (" %s\n", _("certificate is still valid for the specified number of days.")); 2041 printf(" %s\n", _("certificate is still valid for the specified number of days."));
2122 printf ("\n"); 2042 printf("\n");
2123 printf (" %s\n", _("Please note that this plugin does not check if the presented server")); 2043 printf(" %s\n", _("Please note that this plugin does not check if the presented server"));
2124 printf (" %s\n", _("certificate matches the hostname of the server, or if the certificate")); 2044 printf(" %s\n", _("certificate matches the hostname of the server, or if the certificate"));
2125 printf (" %s\n", _("has a valid chain of trust to one of the locally installed CAs.")); 2045 printf(" %s\n", _("has a valid chain of trust to one of the locally installed CAs."));
2126 printf ("\n"); 2046 printf("\n");
2127 printf ("%s\n", _("Examples:")); 2047 printf("%s\n", _("Examples:"));
2128 printf (" %s\n\n", "CHECK CONTENT: check_curl -w 5 -c 10 --ssl -H www.verisign.com"); 2048 printf(" %s\n\n", "CHECK CONTENT: check_curl -w 5 -c 10 --ssl -H www.verisign.com");
2129 printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,")); 2049 printf(" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
2130 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds")); 2050 printf(" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
2131 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,")); 2051 printf(" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
2132 printf (" %s\n", _("a STATE_CRITICAL will be returned.")); 2052 printf(" %s\n", _("a STATE_CRITICAL will be returned."));
2133 printf ("\n"); 2053 printf("\n");
2134 printf (" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 14"); 2054 printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 14");
2135 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,")); 2055 printf(" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
2136 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than")); 2056 printf(" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
2137 printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when")); 2057 printf(" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
2138 printf (" %s\n\n", _("the certificate is expired.")); 2058 printf(" %s\n\n", _("the certificate is expired."));
2139 printf ("\n"); 2059 printf("\n");
2140 printf (" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 30,14"); 2060 printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 30,14");
2141 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 30 days,")); 2061 printf(" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 30 days,"));
2142 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than")); 2062 printf(" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
2143 printf (" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned.")); 2063 printf(" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned."));
2144 printf (" %s\n", _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days")); 2064 printf(" %s\n", _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days"));
2145#endif 2065#endif
2146 2066
2147 printf ("\n %s\n", "CHECK WEBSERVER CONTENT VIA PROXY:"); 2067 printf("\n %s\n", "CHECK WEBSERVER CONTENT VIA PROXY:");
2148 printf (" %s\n", _("It is recommended to use an environment proxy like:")); 2068 printf(" %s\n", _("It is recommended to use an environment proxy like:"));
2149 printf (" %s\n", _("http_proxy=http://192.168.100.35:3128 ./check_curl -H www.monitoring-plugins.org")); 2069 printf(" %s\n", _("http_proxy=http://192.168.100.35:3128 ./check_curl -H www.monitoring-plugins.org"));
2150 printf (" %s\n", _("legacy proxy requests in check_http style still work:")); 2070 printf(" %s\n", _("legacy proxy requests in check_http style still work:"));
2151 printf (" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u http://www.monitoring-plugins.org/ -H www.monitoring-plugins.org")); 2071 printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u http://www.monitoring-plugins.org/ -H www.monitoring-plugins.org"));
2152 2072
2153#ifdef LIBCURL_FEATURE_SSL 2073#ifdef LIBCURL_FEATURE_SSL
2154 printf ("\n %s\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: "); 2074 printf("\n %s\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: ");
2155 printf (" %s\n", _("It is recommended to use an environment proxy like:")); 2075 printf(" %s\n", _("It is recommended to use an environment proxy like:"));
2156 printf (" %s\n", _("https_proxy=http://192.168.100.35:3128 ./check_curl -H www.verisign.com -S")); 2076 printf(" %s\n", _("https_proxy=http://192.168.100.35:3128 ./check_curl -H www.verisign.com -S"));
2157 printf (" %s\n", _("legacy proxy requests in check_http style still work:")); 2077 printf(" %s\n", _("legacy proxy requests in check_http style still work:"));
2158 printf (" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u https://www.verisign.com/ -S -j CONNECT -H www.verisign.com ")); 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 "));
2159 printf (" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> -S(sl) -j CONNECT -H <webserver>")); 2079 printf(" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> -S(sl) -j CONNECT -H <webserver>"));
2160 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds")); 2080 printf(" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
2161 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,")); 2081 printf(" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
2162 printf (" %s\n", _("a STATE_CRITICAL will be returned.")); 2082 printf(" %s\n", _("a STATE_CRITICAL will be returned."));
2163 2083
2164#endif 2084#endif
2165 2085
2166 printf (UT_SUPPORT); 2086 printf(UT_SUPPORT);
2167
2168} 2087}
2169 2088
2170 2089void print_usage(void) {
2171 2090 printf("%s\n", _("Usage:"));
2172void 2091 printf(" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n", progname);
2173print_usage (void) 2092 printf(" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate file>] [-D]\n");
2174{ 2093 printf(" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n");
2175 printf ("%s\n", _("Usage:")); 2094 printf(" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport|curl>]\n");
2176 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname); 2095 printf(" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n");
2177 printf (" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate file>] [-D]\n"); 2096 printf(" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
2178 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n"); 2097 printf(" [-A string] [-k string] [-S <version>] [--sni] [--haproxy-protocol]\n");
2179 printf (" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport|curl>]\n"); 2098 printf(" [-T <content-type>] [-j method]\n");
2180 printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n"); 2099 printf(" [--http-version=<version>] [--enable-automatic-decompression]\n");
2181 printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n"); 2100 printf(" [--cookie-jar=<cookie jar file>\n");
2182 printf (" [-A string] [-k string] [-S <version>] [--sni] [--haproxy-protocol]\n"); 2101 printf(" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n", progname);
2183 printf (" [-T <content-type>] [-j method]\n"); 2102 printf(" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n");
2184 printf (" [--http-version=<version>] [--enable-automatic-decompression]\n"); 2103 printf("\n");
2185 printf (" [--cookie-jar=<cookie jar file>\n");
2186 printf (" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n",progname);
2187 printf (" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n");
2188 printf ("\n");
2189#ifdef LIBCURL_FEATURE_SSL 2104#ifdef LIBCURL_FEATURE_SSL
2190 printf ("%s\n", _("In the first form, make an HTTP request.")); 2105 printf("%s\n", _("In the first form, make an HTTP request."));
2191 printf ("%s\n\n", _("In the second form, connect to the server and check the TLS certificate.")); 2106 printf("%s\n\n", _("In the second form, connect to the server and check the TLS certificate."));
2192#endif 2107#endif
2193} 2108}
2194 2109
2195void 2110void print_curl_version(void) { printf("%s\n", curl_version()); }
2196print_curl_version (void)
2197{
2198 printf( "%s\n", curl_version());
2199}
2200 2111
2201int 2112int curlhelp_initwritebuffer(curlhelp_write_curlbuf *buf) {
2202curlhelp_initwritebuffer (curlhelp_write_curlbuf *buf) 2113 buf->bufsize = DEFAULT_BUFFER_SIZE;
2203{ 2114 buf->buflen = 0;
2204 buf->bufsize = DEFAULT_BUFFER_SIZE; 2115 buf->buf = (char *)malloc((size_t)buf->bufsize);
2205 buf->buflen = 0; 2116 if (buf->buf == NULL)
2206 buf->buf = (char *)malloc ((size_t)buf->bufsize); 2117 return -1;
2207 if (buf->buf == NULL) return -1; 2118 return 0;
2208 return 0;
2209} 2119}
2210 2120
2211size_t curlhelp_buffer_write_callback (void *buffer, size_t size, size_t nmemb, void *stream) 2121size_t curlhelp_buffer_write_callback(void *buffer, size_t size, size_t nmemb, void *stream) {
2212{ 2122 curlhelp_write_curlbuf *buf = (curlhelp_write_curlbuf *)stream;
2213 curlhelp_write_curlbuf *buf = (curlhelp_write_curlbuf *)stream;
2214 2123
2215 while (buf->bufsize < buf->buflen + size * nmemb + 1) { 2124 while (buf->bufsize < buf->buflen + size * nmemb + 1) {
2216 buf->bufsize = buf->bufsize * 2; 2125 buf->bufsize = buf->bufsize * 2;
2217 buf->buf = (char *)realloc (buf->buf, buf->bufsize); 2126 buf->buf = (char *)realloc(buf->buf, buf->bufsize);
2218 if (buf->buf == NULL) { 2127 if (buf->buf == NULL) {
2219 fprintf(stderr, "malloc failed (%d) %s\n", errno, strerror(errno)); 2128 fprintf(stderr, "malloc failed (%d) %s\n", errno, strerror(errno));
2220 return -1; 2129 return -1;
2221 } 2130 }
2222 } 2131 }
2223 2132
2224 memcpy (buf->buf + buf->buflen, buffer, size * nmemb); 2133 memcpy(buf->buf + buf->buflen, buffer, size * nmemb);
2225 buf->buflen += size * nmemb; 2134 buf->buflen += size * nmemb;
2226 buf->buf[buf->buflen] = '\0'; 2135 buf->buf[buf->buflen] = '\0';
2227 2136
2228 return (int)(size * nmemb); 2137 return (int)(size * nmemb);
2229} 2138}
2230 2139
2231size_t curlhelp_buffer_read_callback(void *buffer, size_t size, size_t nmemb, void *stream) 2140size_t curlhelp_buffer_read_callback(void *buffer, size_t size, size_t nmemb, void *stream) {
2232{ 2141 curlhelp_read_curlbuf *buf = (curlhelp_read_curlbuf *)stream;
2233 curlhelp_read_curlbuf *buf = (curlhelp_read_curlbuf *)stream;
2234 2142
2235 size_t n = min (nmemb * size, buf->buflen - buf->pos); 2143 size_t n = min(nmemb * size, buf->buflen - buf->pos);
2236 2144
2237 memcpy (buffer, buf->buf + buf->pos, n); 2145 memcpy(buffer, buf->buf + buf->pos, n);
2238 buf->pos += n; 2146 buf->pos += n;
2239 2147
2240 return (int)n; 2148 return (int)n;
2241} 2149}
2242 2150
2243void 2151void curlhelp_freewritebuffer(curlhelp_write_curlbuf *buf) {
2244curlhelp_freewritebuffer (curlhelp_write_curlbuf *buf) 2152 free(buf->buf);
2245{ 2153 buf->buf = NULL;
2246 free (buf->buf);
2247 buf->buf = NULL;
2248} 2154}
2249 2155
2250int 2156int curlhelp_initreadbuffer(curlhelp_read_curlbuf *buf, const char *data, size_t datalen) {
2251curlhelp_initreadbuffer (curlhelp_read_curlbuf *buf, const char *data, size_t datalen) 2157 buf->buflen = datalen;
2252{ 2158 buf->buf = (char *)malloc((size_t)buf->buflen);
2253 buf->buflen = datalen; 2159 if (buf->buf == NULL)
2254 buf->buf = (char *)malloc ((size_t)buf->buflen); 2160 return -1;
2255 if (buf->buf == NULL) return -1; 2161 memcpy(buf->buf, data, datalen);
2256 memcpy (buf->buf, data, datalen); 2162 buf->pos = 0;
2257 buf->pos = 0; 2163 return 0;
2258 return 0;
2259} 2164}
2260 2165
2261void 2166void curlhelp_freereadbuffer(curlhelp_read_curlbuf *buf) {
2262curlhelp_freereadbuffer (curlhelp_read_curlbuf *buf) 2167 free(buf->buf);
2263{ 2168 buf->buf = NULL;
2264 free (buf->buf);
2265 buf->buf = NULL;
2266} 2169}
2267 2170
2268/* TODO: where to put this, it's actually part of sstrings2 (logically)? 2171/* TODO: where to put this, it's actually part of sstrings2 (logically)?
2269 */ 2172 */
2270const char* 2173const char *strrstr2(const char *haystack, const char *needle) {
2271strrstr2(const char *haystack, const char *needle) 2174 int counter;
2272{ 2175 size_t len;
2273 int counter; 2176 const char *prev_pos;
2274 size_t len; 2177 const char *pos;
2275 const char *prev_pos; 2178
2276 const char *pos; 2179 if (haystack == NULL || needle == NULL)
2277 2180 return NULL;
2278 if (haystack == NULL || needle == NULL) 2181
2279 return NULL; 2182 if (haystack[0] == '\0' || needle[0] == '\0')
2280 2183 return NULL;
2281 if (haystack[0] == '\0' || needle[0] == '\0') 2184
2282 return NULL; 2185 counter = 0;
2283 2186 prev_pos = NULL;
2284 counter = 0; 2187 pos = haystack;
2285 prev_pos = NULL; 2188 len = strlen(needle);
2286 pos = haystack; 2189 for (;;) {
2287 len = strlen (needle); 2190 pos = strstr(pos, needle);
2288 for (;;) { 2191 if (pos == NULL) {
2289 pos = strstr (pos, needle); 2192 if (counter == 0)
2290 if (pos == NULL) { 2193 return NULL;
2291 if (counter == 0) 2194 return prev_pos;
2292 return NULL; 2195 }
2293 else 2196 counter++;
2294 return prev_pos; 2197 prev_pos = pos;
2295 } 2198 pos += len;
2296 counter++; 2199 if (*pos == '\0')
2297 prev_pos = pos; 2200 return prev_pos;
2298 pos += len; 2201 }
2299 if (*pos == '\0') return prev_pos;
2300 }
2301} 2202}
2302 2203
2303int 2204int curlhelp_parse_statusline(const char *buf, curlhelp_statusline *status_line) {
2304curlhelp_parse_statusline (const char *buf, curlhelp_statusline *status_line) 2205 char *first_line_end;
2305{ 2206 char *p;
2306 char *first_line_end; 2207 size_t first_line_len;
2307 char *p; 2208 char *pp;
2308 size_t first_line_len; 2209 const char *start;
2309 char *pp; 2210 char *first_line_buf;
2310 const char *start; 2211
2311 char *first_line_buf; 2212 /* find last start of a new header */
2312 2213 start = strrstr2(buf, "\r\nHTTP/");
2313 /* find last start of a new header */ 2214 if (start != NULL) {
2314 start = strrstr2 (buf, "\r\nHTTP/"); 2215 start += 2;
2315 if (start != NULL) { 2216 buf = start;
2316 start += 2; 2217 }
2317 buf = start;
2318 }
2319
2320 first_line_end = strstr(buf, "\r\n");
2321 if (first_line_end == NULL) return -1;
2322
2323 first_line_len = (size_t)(first_line_end - buf);
2324 status_line->first_line = (char *)malloc (first_line_len + 1);
2325 if (status_line->first_line == NULL) return -1;
2326 memcpy (status_line->first_line, buf, first_line_len);
2327 status_line->first_line[first_line_len] = '\0';
2328 first_line_buf = strdup( status_line->first_line );
2329
2330 /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */
2331
2332 p = strtok(first_line_buf, "/");
2333 if( p == NULL ) { free( first_line_buf ); return -1; }
2334 if( strcmp( p, "HTTP" ) != 0 ) { free( first_line_buf ); return -1; }
2335
2336 p = strtok( NULL, " " );
2337 if( p == NULL ) { free( first_line_buf ); return -1; }
2338 if( strchr( p, '.' ) != NULL ) {
2339
2340 /* HTTP 1.x case */
2341 strtok( p, "." );
2342 status_line->http_major = (int)strtol( p, &pp, 10 );
2343 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2344 strtok( NULL, " " );
2345 status_line->http_minor = (int)strtol( p, &pp, 10 );
2346 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2347 p += 4; /* 1.x SP */
2348 } else {
2349 /* HTTP 2 case */
2350 status_line->http_major = (int)strtol( p, &pp, 10 );
2351 status_line->http_minor = 0;
2352 p += 2; /* 2 SP */
2353 }
2354
2355 /* status code: "404" or "404.1", then SP */
2356
2357 p = strtok( p, " " );
2358 if( p == NULL ) { free( first_line_buf ); return -1; }
2359 if( strchr( p, '.' ) != NULL ) {
2360 char *ppp;
2361 ppp = strtok( p, "." );
2362 status_line->http_code = (int)strtol( ppp, &pp, 10 );
2363 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2364 ppp = strtok( NULL, "" );
2365 status_line->http_subcode = (int)strtol( ppp, &pp, 10 );
2366 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2367 p += 6; /* 400.1 SP */
2368 } else {
2369 status_line->http_code = (int)strtol( p, &pp, 10 );
2370 status_line->http_subcode = -1;
2371 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2372 p += 4; /* 400 SP */
2373 }
2374
2375 /* Human readable message: "Not Found" CRLF */
2376
2377 p = strtok( p, "" );
2378 if( p == NULL ) { status_line->msg = ""; return 0; }
2379 status_line->msg = status_line->first_line + ( p - first_line_buf );
2380 free( first_line_buf );
2381
2382 return 0;
2383}
2384 2218
2385void 2219 first_line_end = strstr(buf, "\r\n");
2386curlhelp_free_statusline (curlhelp_statusline *status_line) 2220 if (first_line_end == NULL)
2387{ 2221 return -1;
2388 free (status_line->first_line); 2222
2389} 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 }
2390 2270
2391void 2271 /* status code: "404" or "404.1", then SP */
2392remove_newlines (char *s)
2393{
2394 char *p;
2395 2272
2396 for (p = s; *p != '\0'; p++) 2273 p = strtok(p, " ");
2397 if (*p == '\r' || *p == '\n') 2274 if (p == NULL) {
2398 *p = ' '; 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;
2399} 2314}
2400 2315
2401char * 2316void curlhelp_free_statusline(curlhelp_statusline *status_line) { free(status_line->first_line); }
2402get_header_value (const struct phr_header* headers, const size_t nof_headers, const char* header) 2317
2403{ 2318char *get_header_value(const struct phr_header *headers, const size_t nof_headers, const char *header) {
2404 for(size_t i = 0; i < nof_headers; i++ ) { 2319 for (size_t i = 0; i < nof_headers; i++) {
2405 if(headers[i].name != NULL && strncasecmp( header, headers[i].name, max( headers[i].name_len, 4 ) ) == 0 ) { 2320 if (headers[i].name != NULL && strncasecmp(header, headers[i].name, max(headers[i].name_len, 4)) == 0) {
2406 return strndup( headers[i].value, headers[i].value_len ); 2321 return strndup(headers[i].value, headers[i].value_len);
2407 } 2322 }
2408 } 2323 }
2409 return NULL; 2324 return NULL;
2410} 2325}
2411 2326
2412int 2327int check_document_dates(const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFAULT_BUFFER_SIZE]) {
2413check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFAULT_BUFFER_SIZE]) 2328 char *server_date = NULL;
2414{ 2329 char *document_date = NULL;
2415 char *server_date = NULL; 2330 int date_result = STATE_OK;
2416 char *document_date = NULL; 2331 curlhelp_statusline status_line;
2417 int date_result = STATE_OK; 2332 struct phr_header headers[255];
2418 curlhelp_statusline status_line; 2333 size_t nof_headers = 255;
2419 struct phr_header headers[255]; 2334 size_t msglen;
2420 size_t nof_headers = 255; 2335
2421 size_t msglen; 2336 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor,
2422 2337 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0);
2423 int res = phr_parse_response (header_buf->buf, header_buf->buflen,
2424 &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
2425 headers, &nof_headers, 0);
2426 2338
2427 if (res == -1) { 2339 if (res == -1) {
2428 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 2340 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
2429 } 2341 }
2430 2342
2431 server_date = get_header_value (headers, nof_headers, "date"); 2343 server_date = get_header_value(headers, nof_headers, "date");
2432 document_date = get_header_value (headers, nof_headers, "last-modified"); 2344 document_date = get_header_value(headers, nof_headers, "last-modified");
2433 2345
2434 if (!server_date || !*server_date) { 2346 if (!server_date || !*server_date) {
2435 char tmp[DEFAULT_BUFFER_SIZE]; 2347 char tmp[DEFAULT_BUFFER_SIZE];
2436 2348
2437 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sServer date unknown, "), *msg); 2349 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sServer date unknown, "), *msg);
2438 strcpy(*msg, tmp); 2350 strcpy(*msg, tmp);
2439 2351
2440 date_result = max_state_alt(STATE_UNKNOWN, date_result); 2352 date_result = max_state_alt(STATE_UNKNOWN, date_result);
@@ -2442,34 +2354,34 @@ check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFA
2442 } else if (!document_date || !*document_date) { 2354 } else if (!document_date || !*document_date) {
2443 char tmp[DEFAULT_BUFFER_SIZE]; 2355 char tmp[DEFAULT_BUFFER_SIZE];
2444 2356
2445 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument modification date unknown, "), *msg); 2357 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument modification date unknown, "), *msg);
2446 strcpy(*msg, tmp); 2358 strcpy(*msg, tmp);
2447 2359
2448 date_result = max_state_alt(STATE_CRITICAL, date_result); 2360 date_result = max_state_alt(STATE_CRITICAL, date_result);
2449 2361
2450 } else { 2362 } else {
2451 time_t srv_data = curl_getdate (server_date, NULL); 2363 time_t srv_data = curl_getdate(server_date, NULL);
2452 time_t doc_data = curl_getdate (document_date, NULL); 2364 time_t doc_data = curl_getdate(document_date, NULL);
2453 if (verbose >= 2) 2365 if (verbose >= 2)
2454 printf ("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data, document_date, (int)doc_data); 2366 printf("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data, document_date, (int)doc_data);
2455 if (srv_data <= 0) { 2367 if (srv_data <= 0) {
2456 char tmp[DEFAULT_BUFFER_SIZE]; 2368 char tmp[DEFAULT_BUFFER_SIZE];
2457 2369
2458 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sServer date \"%100s\" unparsable, "), *msg, server_date); 2370 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sServer date \"%100s\" unparsable, "), *msg, server_date);
2459 strcpy(*msg, tmp); 2371 strcpy(*msg, tmp);
2460 2372
2461 date_result = max_state_alt(STATE_CRITICAL, date_result); 2373 date_result = max_state_alt(STATE_CRITICAL, date_result);
2462 } else if (doc_data <= 0) { 2374 } else if (doc_data <= 0) {
2463 char tmp[DEFAULT_BUFFER_SIZE]; 2375 char tmp[DEFAULT_BUFFER_SIZE];
2464 2376
2465 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date); 2377 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date);
2466 strcpy(*msg, tmp); 2378 strcpy(*msg, tmp);
2467 2379
2468 date_result = max_state_alt(STATE_CRITICAL, date_result); 2380 date_result = max_state_alt(STATE_CRITICAL, date_result);
2469 } else if (doc_data > srv_data + 30) { 2381 } else if (doc_data > srv_data + 30) {
2470 char tmp[DEFAULT_BUFFER_SIZE]; 2382 char tmp[DEFAULT_BUFFER_SIZE];
2471 2383
2472 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data); 2384 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data);
2473 strcpy(*msg, tmp); 2385 strcpy(*msg, tmp);
2474 2386
2475 date_result = max_state_alt(STATE_CRITICAL, date_result); 2387 date_result = max_state_alt(STATE_CRITICAL, date_result);
@@ -2478,14 +2390,14 @@ check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFA
2478 if (n > (60 * 60 * 24 * 2)) { 2390 if (n > (60 * 60 * 24 * 2)) {
2479 char tmp[DEFAULT_BUFFER_SIZE]; 2391 char tmp[DEFAULT_BUFFER_SIZE];
2480 2392
2481 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %.1f days ago, "), *msg, ((float) n) / (60 * 60 * 24)); 2393 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %.1f days ago, "), *msg, ((float)n) / (60 * 60 * 24));
2482 strcpy(*msg, tmp); 2394 strcpy(*msg, tmp);
2483 2395
2484 date_result = max_state_alt(STATE_CRITICAL, date_result); 2396 date_result = max_state_alt(STATE_CRITICAL, date_result);
2485 } else { 2397 } else {
2486 char tmp[DEFAULT_BUFFER_SIZE]; 2398 char tmp[DEFAULT_BUFFER_SIZE];
2487 2399
2488 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60); 2400 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60);
2489 strcpy(*msg, tmp); 2401 strcpy(*msg, tmp);
2490 2402
2491 date_result = max_state_alt(STATE_CRITICAL, date_result); 2403 date_result = max_state_alt(STATE_CRITICAL, date_result);
@@ -2493,132 +2405,128 @@ check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFA
2493 } 2405 }
2494 } 2406 }
2495 2407
2496 if (server_date) free (server_date); 2408 if (server_date)
2497 if (document_date) free (document_date); 2409 free(server_date);
2410 if (document_date)
2411 free(document_date);
2498 2412
2499 return date_result; 2413 return date_result;
2500} 2414}
2501 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;
2502 2423
2503int 2424 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor,
2504get_content_length (const curlhelp_write_curlbuf* header_buf, const curlhelp_write_curlbuf* body_buf) 2425 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0);
2505{
2506 size_t content_length = 0;
2507 struct phr_header headers[255];
2508 size_t nof_headers = 255;
2509 size_t msglen;
2510 char *content_length_s = NULL;
2511 curlhelp_statusline status_line;
2512
2513 int res = phr_parse_response (header_buf->buf, header_buf->buflen,
2514 &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
2515 headers, &nof_headers, 0);
2516 2426
2517 if (res == -1) { 2427 if (res == -1) {
2518 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 2428 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
2519 } 2429 }
2520 2430
2521 content_length_s = get_header_value (headers, nof_headers, "content-length"); 2431 content_length_s = get_header_value(headers, nof_headers, "content-length");
2522 if (!content_length_s) { 2432 if (!content_length_s) {
2523 return header_buf->buflen + body_buf->buflen; 2433 return header_buf->buflen + body_buf->buflen;
2524 } 2434 }
2525 content_length_s += strspn (content_length_s, " \t"); 2435 content_length_s += strspn(content_length_s, " \t");
2526 content_length = atoi (content_length_s); 2436 content_length = atoi(content_length_s);
2527 if (content_length != body_buf->buflen) { 2437 if (content_length != body_buf->buflen) {
2528 /* TODO: should we warn if the actual and the reported body length don't match? */ 2438 /* TODO: should we warn if the actual and the reported body length don't match? */
2529 } 2439 }
2530 2440
2531 if (content_length_s) free (content_length_s); 2441 if (content_length_s)
2442 free(content_length_s);
2532 2443
2533 return header_buf->buflen + body_buf->buflen; 2444 return header_buf->buflen + body_buf->buflen;
2534} 2445}
2535 2446
2536/* TODO: is there a better way in libcurl to check for the SSL library? */ 2447/* TODO: is there a better way in libcurl to check for the SSL library? */
2537curlhelp_ssl_library 2448curlhelp_ssl_library curlhelp_get_ssl_library(void) {
2538curlhelp_get_ssl_library () 2449 curl_version_info_data *version_data;
2539{ 2450 char *ssl_version;
2540 curl_version_info_data* version_data; 2451 char *library;
2541 char *ssl_version; 2452 curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
2542 char *library; 2453
2543 curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN; 2454 version_data = curl_version_info(CURLVERSION_NOW);
2544 2455 if (version_data == NULL)
2545 version_data = curl_version_info (CURLVERSION_NOW); 2456 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2546 if (version_data == NULL) return CURLHELP_SSL_LIBRARY_UNKNOWN; 2457
2547 2458 ssl_version = strdup(version_data->ssl_version);
2548 ssl_version = strdup (version_data->ssl_version); 2459 if (ssl_version == NULL)
2549 if (ssl_version == NULL ) return CURLHELP_SSL_LIBRARY_UNKNOWN; 2460 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2550 2461
2551 library = strtok (ssl_version, "/"); 2462 library = strtok(ssl_version, "/");
2552 if (library == NULL) return CURLHELP_SSL_LIBRARY_UNKNOWN; 2463 if (library == NULL)
2553 2464 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2554 if (strcmp (library, "OpenSSL") == 0) 2465
2555 ssl_library = CURLHELP_SSL_LIBRARY_OPENSSL; 2466 if (strcmp(library, "OpenSSL") == 0)
2556 else if (strcmp (library, "LibreSSL") == 0) 2467 ssl_library = CURLHELP_SSL_LIBRARY_OPENSSL;
2557 ssl_library = CURLHELP_SSL_LIBRARY_LIBRESSL; 2468 else if (strcmp(library, "LibreSSL") == 0)
2558 else if (strcmp (library, "GnuTLS") == 0) 2469 ssl_library = CURLHELP_SSL_LIBRARY_LIBRESSL;
2559 ssl_library = CURLHELP_SSL_LIBRARY_GNUTLS; 2470 else if (strcmp(library, "GnuTLS") == 0)
2560 else if (strcmp (library, "NSS") == 0) 2471 ssl_library = CURLHELP_SSL_LIBRARY_GNUTLS;
2561 ssl_library = CURLHELP_SSL_LIBRARY_NSS; 2472 else if (strcmp(library, "NSS") == 0)
2562 2473 ssl_library = CURLHELP_SSL_LIBRARY_NSS;
2563 if (verbose >= 2) 2474
2564 printf ("* SSL library string is : %s %s (%d)\n", version_data->ssl_version, library, ssl_library); 2475 if (verbose >= 2)
2565 2476 printf("* SSL library string is : %s %s (%d)\n", version_data->ssl_version, library, ssl_library);
2566 free (ssl_version); 2477
2567 2478 free(ssl_version);
2568 return ssl_library; 2479
2480 return ssl_library;
2569} 2481}
2570 2482
2571const char* 2483const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library ssl_library) {
2572curlhelp_get_ssl_library_string (curlhelp_ssl_library ssl_library) 2484 switch (ssl_library) {
2573{ 2485 case CURLHELP_SSL_LIBRARY_OPENSSL:
2574 switch (ssl_library) { 2486 return "OpenSSL";
2575 case CURLHELP_SSL_LIBRARY_OPENSSL: 2487 case CURLHELP_SSL_LIBRARY_LIBRESSL:
2576 return "OpenSSL"; 2488 return "LibreSSL";
2577 case CURLHELP_SSL_LIBRARY_LIBRESSL: 2489 case CURLHELP_SSL_LIBRARY_GNUTLS:
2578 return "LibreSSL"; 2490 return "GnuTLS";
2579 case CURLHELP_SSL_LIBRARY_GNUTLS: 2491 case CURLHELP_SSL_LIBRARY_NSS:
2580 return "GnuTLS"; 2492 return "NSS";
2581 case CURLHELP_SSL_LIBRARY_NSS: 2493 case CURLHELP_SSL_LIBRARY_UNKNOWN:
2582 return "NSS"; 2494 default:
2583 case CURLHELP_SSL_LIBRARY_UNKNOWN: 2495 return "unknown";
2584 default: 2496 }
2585 return "unknown";
2586 }
2587} 2497}
2588 2498
2589#ifdef LIBCURL_FEATURE_SSL 2499#ifdef LIBCURL_FEATURE_SSL
2590#ifndef USE_OPENSSL 2500# ifndef USE_OPENSSL
2591time_t 2501time_t parse_cert_date(const char *s) {
2592parse_cert_date (const char *s) 2502 struct tm tm;
2593{ 2503 time_t date;
2594 struct tm tm; 2504 char *res;
2595 time_t date; 2505
2596 char *res; 2506 if (!s)
2597 2507 return -1;
2598 if (!s) return -1; 2508
2599 2509 /* Jan 17 14:25:12 2020 GMT */
2600 /* Jan 17 14:25:12 2020 GMT */ 2510 res = strptime(s, "%Y-%m-%d %H:%M:%S GMT", &tm);
2601 res = strptime (s, "%Y-%m-%d %H:%M:%S GMT", &tm); 2511 /* Sep 11 12:00:00 2020 GMT */
2602 /* Sep 11 12:00:00 2020 GMT */ 2512 if (res == NULL)
2603 if (res == NULL) strptime (s, "%Y %m %d %H:%M:%S GMT", &tm); 2513 strptime(s, "%Y %m %d %H:%M:%S GMT", &tm);
2604 date = mktime (&tm); 2514 date = mktime(&tm);
2605 2515
2606 return date; 2516 return date;
2607} 2517}
2608 2518
2609/* TODO: this needs cleanup in the sslutils.c, maybe we the #else case to 2519/* TODO: this needs cleanup in the sslutils.c, maybe we the #else case to
2610 * OpenSSL could be this function 2520 * OpenSSL could be this function
2611 */ 2521 */
2612int 2522int net_noopenssl_check_certificate(cert_ptr_union *cert_ptr, int days_till_exp_warn, int days_till_exp_crit) {
2613net_noopenssl_check_certificate (cert_ptr_union* cert_ptr, int days_till_exp_warn, int days_till_exp_crit) 2523 int i;
2614{ 2524 struct curl_slist *slist;
2615 int i; 2525 int cname_found = 0;
2616 struct curl_slist* slist; 2526 char *start_date_str = NULL;
2617 int cname_found = 0; 2527 char *end_date_str = NULL;
2618 char* start_date_str = NULL; 2528 time_t start_date;
2619 char* end_date_str = NULL; 2529 time_t end_date;
2620 time_t start_date;
2621 time_t end_date;
2622 char *tz; 2530 char *tz;
2623 float time_left; 2531 float time_left;
2624 int days_left; 2532 int days_left;
@@ -2626,66 +2534,64 @@ net_noopenssl_check_certificate (cert_ptr_union* cert_ptr, int days_till_exp_war
2626 char timestamp[50] = ""; 2534 char timestamp[50] = "";
2627 int status = STATE_UNKNOWN; 2535 int status = STATE_UNKNOWN;
2628 2536
2629 if (verbose >= 2) 2537 if (verbose >= 2)
2630 printf ("**** REQUEST CERTIFICATES ****\n"); 2538 printf("**** REQUEST CERTIFICATES ****\n");
2631 2539
2632 for (i = 0; i < cert_ptr->to_certinfo->num_of_certs; i++) { 2540 for (i = 0; i < cert_ptr->to_certinfo->num_of_certs; i++) {
2633 for (slist = cert_ptr->to_certinfo->certinfo[i]; slist; slist = slist->next) { 2541 for (slist = cert_ptr->to_certinfo->certinfo[i]; slist; slist = slist->next) {
2634 /* find first common name in subject, 2542 /* find first common name in subject,
2635 * TODO: check alternative subjects for 2543 * TODO: check alternative subjects for
2636 * TODO: have a decent parser here and not a hack 2544 * TODO: have a decent parser here and not a hack
2637 * multi-host certificate, check wildcards 2545 * multi-host certificate, check wildcards
2638 */ 2546 */
2639 if (strncasecmp (slist->data, "Subject:", 8) == 0) { 2547 if (strncasecmp(slist->data, "Subject:", 8) == 0) {
2640 int d = 3; 2548 int d = 3;
2641 char* p = strstr (slist->data, "CN="); 2549 char *p = strstr(slist->data, "CN=");
2642 if (p == NULL) { 2550 if (p == NULL) {
2643 d = 5; 2551 d = 5;
2644 p = strstr (slist->data, "CN = "); 2552 p = strstr(slist->data, "CN = ");
2645 } 2553 }
2646 if (p != NULL) { 2554 if (p != NULL) {
2647 if (strncmp (host_name, p+d, strlen (host_name)) == 0) { 2555 if (strncmp(host_name, p + d, strlen(host_name)) == 0) {
2648 cname_found = 1; 2556 cname_found = 1;
2649 } 2557 }
2650 } 2558 }
2651 } else if (strncasecmp (slist->data, "Start Date:", 11) == 0) { 2559 } else if (strncasecmp(slist->data, "Start Date:", 11) == 0) {
2652 start_date_str = &slist->data[11]; 2560 start_date_str = &slist->data[11];
2653 } else if (strncasecmp (slist->data, "Expire Date:", 12) == 0) { 2561 } else if (strncasecmp(slist->data, "Expire Date:", 12) == 0) {
2654 end_date_str = &slist->data[12]; 2562 end_date_str = &slist->data[12];
2655 } else if (strncasecmp (slist->data, "Cert:", 5) == 0) { 2563 } else if (strncasecmp(slist->data, "Cert:", 5) == 0) {
2656 goto HAVE_FIRST_CERT; 2564 goto HAVE_FIRST_CERT;
2657 } 2565 }
2658 if (verbose >= 2) 2566 if (verbose >= 2)
2659 printf ("%d ** %s\n", i, slist->data); 2567 printf("%d ** %s\n", i, slist->data);
2660 } 2568 }
2661 } 2569 }
2662HAVE_FIRST_CERT: 2570HAVE_FIRST_CERT:
2663 2571
2664 if (verbose >= 2) 2572 if (verbose >= 2)
2665 printf ("**** REQUEST CERTIFICATES ****\n"); 2573 printf("**** REQUEST CERTIFICATES ****\n");
2666 2574
2667 if (!cname_found) { 2575 if (!cname_found) {
2668 printf("%s\n",_("CRITICAL - Cannot retrieve certificate subject.")); 2576 printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject."));
2669 return STATE_CRITICAL; 2577 return STATE_CRITICAL;
2670 } 2578 }
2671 2579
2672 start_date = parse_cert_date (start_date_str); 2580 start_date = parse_cert_date(start_date_str);
2673 if (start_date <= 0) { 2581 if (start_date <= 0) {
2674 snprintf (msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Start Date' in certificate: '%s'"), 2582 snprintf(msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Start Date' in certificate: '%s'"), start_date_str);
2675 start_date_str); 2583 puts(msg);
2676 puts (msg); 2584 return STATE_WARNING;
2677 return STATE_WARNING; 2585 }
2678 } 2586
2679 2587 end_date = parse_cert_date(end_date_str);
2680 end_date = parse_cert_date (end_date_str); 2588 if (end_date <= 0) {
2681 if (end_date <= 0) { 2589 snprintf(msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Expire Date' in certificate: '%s'"), start_date_str);
2682 snprintf (msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Expire Date' in certificate: '%s'"), 2590 puts(msg);
2683 start_date_str); 2591 return STATE_WARNING;
2684 puts (msg); 2592 }
2685 return STATE_WARNING; 2593
2686 } 2594 time_left = difftime(end_date, time(NULL));
2687
2688 time_left = difftime (end_date, time(NULL));
2689 days_left = time_left / 86400; 2595 days_left = time_left / 86400;
2690 tz = getenv("TZ"); 2596 tz = getenv("TZ");
2691 setenv("TZ", "GMT", 1); 2597 setenv("TZ", "GMT", 1);
@@ -2698,30 +2604,31 @@ HAVE_FIRST_CERT:
2698 tzset(); 2604 tzset();
2699 2605
2700 if (days_left > 0 && days_left <= days_till_exp_warn) { 2606 if (days_left > 0 && days_left <= days_till_exp_warn) {
2701 printf (_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", host_name, days_left, timestamp); 2607 printf(_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL",
2608 host_name, days_left, timestamp);
2702 if (days_left > days_till_exp_crit) 2609 if (days_left > days_till_exp_crit)
2703 status = STATE_WARNING; 2610 status = STATE_WARNING;
2704 else 2611 else
2705 status = STATE_CRITICAL; 2612 status = STATE_CRITICAL;
2706 } else if (days_left == 0 && time_left > 0) { 2613 } else if (days_left == 0 && time_left > 0) {
2707 if (time_left >= 3600) 2614 if (time_left >= 3600)
2708 time_remaining = (int) time_left / 3600; 2615 time_remaining = (int)time_left / 3600;
2709 else 2616 else
2710 time_remaining = (int) time_left / 60; 2617 time_remaining = (int)time_left / 60;
2711 2618
2712 printf (_("%s - Certificate '%s' expires in %u %s (%s)\n"), 2619 printf(_("%s - Certificate '%s' expires in %u %s (%s)\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name,
2713 (days_left>days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, time_remaining, 2620 time_remaining, time_left >= 3600 ? "hours" : "minutes", timestamp);
2714 time_left >= 3600 ? "hours" : "minutes", timestamp);
2715 2621
2716 if ( days_left > days_till_exp_crit) 2622 if (days_left > days_till_exp_crit)
2717 status = STATE_WARNING; 2623 status = STATE_WARNING;
2718 else 2624 else
2719 status = STATE_CRITICAL; 2625 status = STATE_CRITICAL;
2720 } else if (time_left < 0) { 2626 } else if (time_left < 0) {
2721 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), host_name, timestamp); 2627 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), host_name, timestamp);
2722 status=STATE_CRITICAL; 2628 status = STATE_CRITICAL;
2723 } else if (days_left == 0) { 2629 } else if (days_left == 0) {
2724 printf (_("%s - Certificate '%s' just expired (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", host_name, timestamp); 2630 printf(_("%s - Certificate '%s' just expired (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name,
2631 timestamp);
2725 if (days_left > days_till_exp_crit) 2632 if (days_left > days_till_exp_crit)
2726 status = STATE_WARNING; 2633 status = STATE_WARNING;
2727 else 2634 else
@@ -2732,5 +2639,5 @@ HAVE_FIRST_CERT:
2732 } 2639 }
2733 return status; 2640 return status;
2734} 2641}
2735#endif /* USE_OPENSSL */ 2642# endif /* USE_OPENSSL */
2736#endif /* LIBCURL_FEATURE_SSL */ 2643#endif /* LIBCURL_FEATURE_SSL */
diff --git a/plugins/check_dbi.c b/plugins/check_dbi.c
index 29c85206..9efcd1cb 100644
--- a/plugins/check_dbi.c
+++ b/plugins/check_dbi.c
@@ -1,38 +1,40 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_dbi plugin 3 * Monitoring check_dbi plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2011 Monitoring Plugins Development Team 6 * Copyright (c) 2011-2024 Monitoring Plugins Development Team
7* Author: Sebastian 'tokkee' Harl <sh@teamix.net> 7 * Original Author: Sebastian 'tokkee' Harl <sh@teamix.net>
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains the check_dbi plugin 11 * This file contains the check_dbi plugin
12* 12 *
13* Runs an arbitrary (SQL) command and checks the result. 13 * Runs an arbitrary (SQL) command and checks the result.
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 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 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 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 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/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_dbi"; 32const char *progname = "check_dbi";
33const char *copyright = "2011"; 33const 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"
37#include "check_dbi.d/config.h"
36#include "common.h" 38#include "common.h"
37#include "utils.h" 39#include "utils.h"
38#include "utils_cmd.h" 40#include "utils_cmd.h"
@@ -43,7 +45,7 @@ const char *email = "devel@monitoring-plugins.org";
43 45
44/* required for NAN */ 46/* required for NAN */
45#ifndef _ISOC99_SOURCE 47#ifndef _ISOC99_SOURCE
46#define _ISOC99_SOURCE 48# define _ISOC99_SOURCE
47#endif 49#endif
48 50
49#include <assert.h> 51#include <assert.h>
@@ -53,59 +55,26 @@ const char *email = "devel@monitoring-plugins.org";
53 55
54#include <stdarg.h> 56#include <stdarg.h>
55 57
56typedef enum { 58static int verbose = 0;
57 METRIC_CONN_TIME,
58 METRIC_SERVER_VERSION,
59 METRIC_QUERY_RESULT,
60 METRIC_QUERY_TIME,
61} np_dbi_metric_t;
62
63typedef enum {
64 TYPE_NUMERIC,
65 TYPE_STRING,
66} np_dbi_type_t;
67 59
68typedef struct { 60typedef struct {
69 char *key; 61 int errorcode;
70 char *value; 62 check_dbi_config config;
71} driver_option_t; 63} check_dbi_config_wrapper;
72
73char *host = NULL;
74int verbose = 0;
75
76char *warning_range = NULL;
77char *critical_range = NULL;
78thresholds *dbi_thresholds = NULL;
79
80char *expect = NULL;
81
82regex_t expect_re;
83char *expect_re_str = NULL;
84int expect_re_cflags = 0;
85
86np_dbi_metric_t metric = METRIC_QUERY_RESULT;
87np_dbi_type_t type = TYPE_NUMERIC;
88 64
89char *np_dbi_driver = NULL; 65static check_dbi_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
90driver_option_t *np_dbi_options = NULL; 66static check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper /*config_wrapper*/);
91int np_dbi_options_num = 0; 67void print_usage(void);
92char *np_dbi_database = NULL; 68static void print_help(void);
93char *np_dbi_query = NULL;
94 69
95int process_arguments (int, char **); 70static double timediff(struct timeval /*start*/, struct timeval /*end*/);
96int validate_arguments (void);
97void print_usage (void);
98void print_help (void);
99 71
100double timediff (struct timeval, struct timeval); 72static void np_dbi_print_error(dbi_conn /*conn*/, char * /*fmt*/, ...);
101 73
102void np_dbi_print_error (dbi_conn, char *, ...); 74static mp_state_enum do_query(dbi_conn /*conn*/, const char ** /*res_val_str*/, double * /*res_val*/, double * /*res_time*/, mp_dbi_metric /*metric*/,
75 mp_dbi_type /*type*/, char * /*np_dbi_query*/);
103 76
104int do_query (dbi_conn, const char **, double *, double *); 77int main(int argc, char **argv) {
105
106int
107main (int argc, char **argv)
108{
109 int status = STATE_UNKNOWN; 78 int status = STATE_UNKNOWN;
110 79
111 dbi_driver driver; 80 dbi_driver driver;
@@ -113,714 +82,725 @@ main (int argc, char **argv)
113 82
114 unsigned int server_version; 83 unsigned int server_version;
115 84
116 struct timeval start_timeval, end_timeval; 85 struct timeval start_timeval;
86 struct timeval end_timeval;
117 double conn_time = 0.0; 87 double conn_time = 0.0;
118 double query_time = 0.0; 88 double query_time = 0.0;
119 89
120 const char *query_val_str = NULL; 90 const char *query_val_str = NULL;
121 double query_val = 0.0; 91 double query_val = 0.0;
122 92
123 int i; 93 setlocale(LC_ALL, "");
124 94 bindtextdomain(PACKAGE, LOCALEDIR);
125 setlocale (LC_ALL, ""); 95 textdomain(PACKAGE);
126 bindtextdomain (PACKAGE, LOCALEDIR);
127 textdomain (PACKAGE);
128 96
129 /* Parse extra opts if any */ 97 /* Parse extra opts if any */
130 argv = np_extra_opts (&argc, argv, progname); 98 argv = np_extra_opts(&argc, argv, progname);
99
100 check_dbi_config_wrapper tmp = process_arguments(argc, argv);
101
102 if (tmp.errorcode == ERROR) {
103 usage4(_("Could not parse arguments"));
104 }
131 105
132 if (process_arguments (argc, argv) == ERROR) 106 const check_dbi_config config = tmp.config;
133 usage4 (_("Could not parse arguments"));
134 107
135 /* Set signal handling and alarm */ 108 /* Set signal handling and alarm */
136 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 109 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
137 usage4 (_("Cannot catch SIGALRM")); 110 usage4(_("Cannot catch SIGALRM"));
138 } 111 }
139 alarm (timeout_interval); 112 alarm(timeout_interval);
140 113
141 if (verbose > 2) 114 if (verbose > 2) {
142 printf ("Initializing DBI\n"); 115 printf("Initializing DBI\n");
116 }
143 117
144 dbi_inst *instance_p = { 0 }; 118 dbi_inst *instance_p = {0};
145 119
146 if (dbi_initialize_r(NULL, instance_p) < 0) { 120 if (dbi_initialize_r(NULL, instance_p) < 0) {
147 printf ("UNKNOWN - 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");
148 return STATE_UNKNOWN; 122 return STATE_UNKNOWN;
149 } 123 }
150 124
151 if (instance_p == NULL) { 125 if (instance_p == NULL) {
152 printf ("UNKNOWN - failed to initialize DBI.\n"); 126 printf("UNKNOWN - failed to initialize DBI.\n");
153 return STATE_UNKNOWN; 127 return STATE_UNKNOWN;
154 } 128 }
155 129
156 if (verbose) 130 if (verbose) {
157 printf ("Opening DBI driver '%s'\n", np_dbi_driver); 131 printf("Opening DBI driver '%s'\n", config.dbi_driver);
132 }
158 133
159 driver = dbi_driver_open_r(np_dbi_driver, instance_p); 134 driver = dbi_driver_open_r(config.dbi_driver, instance_p);
160 if (! driver) { 135 if (!driver) {
161 printf ("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", 136 printf("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", config.dbi_driver);
162 np_dbi_driver);
163 137
164 printf ("Known drivers:\n"); 138 printf("Known drivers:\n");
165 for (driver = dbi_driver_list_r(NULL, instance_p); driver; driver = dbi_driver_list_r(driver, instance_p)) { 139 for (driver = dbi_driver_list_r(NULL, instance_p); driver; driver = dbi_driver_list_r(driver, instance_p)) {
166 printf (" - %s\n", dbi_driver_get_name (driver)); 140 printf(" - %s\n", dbi_driver_get_name(driver));
167 } 141 }
168 return STATE_UNKNOWN; 142 return STATE_UNKNOWN;
169 } 143 }
170 144
171 /* make a connection to the database */ 145 /* make a connection to the database */
172 gettimeofday (&start_timeval, NULL); 146 gettimeofday(&start_timeval, NULL);
173 147
174 conn = dbi_conn_open (driver); 148 conn = dbi_conn_open(driver);
175 if (! conn) { 149 if (!conn) {
176 printf ("UNKNOWN - failed top open connection object.\n"); 150 printf("UNKNOWN - failed top open connection object.\n");
177 dbi_conn_close (conn); 151 dbi_conn_close(conn);
178 return STATE_UNKNOWN; 152 return STATE_UNKNOWN;
179 } 153 }
180 154
181 for (i = 0; i < np_dbi_options_num; ++i) { 155 for (size_t i = 0; i < config.dbi_options_num; ++i) {
182 const char *opt; 156 const char *opt;
183 157
184 if (verbose > 1) 158 if (verbose > 1) {
185 printf ("Setting DBI driver option '%s' to '%s'\n", 159 printf("Setting DBI driver option '%s' to '%s'\n", config.dbi_options[i].key, config.dbi_options[i].value);
186 np_dbi_options[i].key, np_dbi_options[i].value); 160 }
187 161
188 if (! dbi_conn_set_option (conn, np_dbi_options[i].key, np_dbi_options[i].value)) 162 if (!dbi_conn_set_option(conn, config.dbi_options[i].key, config.dbi_options[i].value)) {
189 continue; 163 continue;
164 }
190 /* else: status != 0 */ 165 /* else: status != 0 */
191 166
192 np_dbi_print_error (conn, "UNKNOWN - failed to set option '%s' to '%s'", 167 np_dbi_print_error(conn, "UNKNOWN - failed to set option '%s' to '%s'", config.dbi_options[i].key, config.dbi_options[i].value);
193 np_dbi_options[i].key, np_dbi_options[i].value); 168 printf("Known driver options:\n");
194 printf ("Known driver options:\n");
195 169
196 for (opt = dbi_conn_get_option_list (conn, NULL); opt; 170 for (opt = dbi_conn_get_option_list(conn, NULL); opt; opt = dbi_conn_get_option_list(conn, opt)) {
197 opt = dbi_conn_get_option_list (conn, opt)) { 171 printf(" - %s\n", opt);
198 printf (" - %s\n", opt);
199 } 172 }
200 dbi_conn_close (conn); 173 dbi_conn_close(conn);
201 return STATE_UNKNOWN; 174 return STATE_UNKNOWN;
202 } 175 }
203 176
204 if (host) { 177 if (config.host) {
205 if (verbose > 1) 178 if (verbose > 1) {
206 printf ("Setting DBI driver option 'host' to '%s'\n", host); 179 printf("Setting DBI driver option 'host' to '%s'\n", config.host);
207 dbi_conn_set_option (conn, "host", host); 180 }
181 dbi_conn_set_option(conn, "host", config.host);
208 } 182 }
209 183
210 if (verbose) { 184 if (verbose) {
211 const char *dbname, *host; 185 const char *dbname;
186 const char *host;
212 187
213 dbname = dbi_conn_get_option (conn, "dbname"); 188 dbname = dbi_conn_get_option(conn, "dbname");
214 host = dbi_conn_get_option (conn, "host"); 189 host = dbi_conn_get_option(conn, "host");
215 190
216 if (! dbname) 191 if (!dbname) {
217 dbname = "<unspecified>"; 192 dbname = "<unspecified>";
218 if (! host) 193 }
194 if (!host) {
219 host = "<unspecified>"; 195 host = "<unspecified>";
196 }
220 197
221 printf ("Connecting to database '%s' at host '%s'\n", 198 printf("Connecting to database '%s' at host '%s'\n", dbname, host);
222 dbname, host);
223 } 199 }
224 200
225 if (dbi_conn_connect (conn) < 0) { 201 if (dbi_conn_connect(conn) < 0) {
226 np_dbi_print_error (conn, "UNKNOWN - failed to connect to database"); 202 np_dbi_print_error(conn, "UNKNOWN - failed to connect to database");
227 return STATE_UNKNOWN; 203 return STATE_UNKNOWN;
228 } 204 }
229 205
230 gettimeofday (&end_timeval, NULL); 206 gettimeofday(&end_timeval, NULL);
231 conn_time = timediff (start_timeval, end_timeval); 207 conn_time = timediff(start_timeval, end_timeval);
232 208
233 server_version = dbi_conn_get_engine_version (conn); 209 server_version = dbi_conn_get_engine_version(conn);
234 if (verbose) 210 if (verbose) {
235 printf ("Connected to server version %u\n", server_version); 211 printf("Connected to server version %u\n", server_version);
212 }
236 213
237 if (metric == METRIC_SERVER_VERSION) 214 if (config.metric == METRIC_SERVER_VERSION) {
238 status = get_status (server_version, dbi_thresholds); 215 status = get_status(server_version, config.dbi_thresholds);
216 }
239 217
240 if (verbose) 218 if (verbose) {
241 printf ("Time elapsed: %f\n", conn_time); 219 printf("Time elapsed: %f\n", conn_time);
220 }
242 221
243 if (metric == METRIC_CONN_TIME) 222 if (config.metric == METRIC_CONN_TIME) {
244 status = get_status (conn_time, dbi_thresholds); 223 status = get_status(conn_time, config.dbi_thresholds);
224 }
245 225
246 /* select a database */ 226 /* select a database */
247 if (np_dbi_database) { 227 if (config.dbi_database) {
248 if (verbose > 1) 228 if (verbose > 1) {
249 printf ("Selecting database '%s'\n", np_dbi_database); 229 printf("Selecting database '%s'\n", config.dbi_database);
230 }
250 231
251 if (dbi_conn_select_db (conn, np_dbi_database)) { 232 if (dbi_conn_select_db(conn, config.dbi_database)) {
252 np_dbi_print_error (conn, "UNKNOWN - failed to select database '%s'", 233 np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'", config.dbi_database);
253 np_dbi_database);
254 return STATE_UNKNOWN; 234 return STATE_UNKNOWN;
255 } 235 }
256 } 236 }
257 237
258 if (np_dbi_query) { 238 if (config.dbi_query) {
259 /* execute query */ 239 /* execute query */
260 status = do_query (conn, &query_val_str, &query_val, &query_time); 240 status = do_query(conn, &query_val_str, &query_val, &query_time, config.metric, config.type, config.dbi_query);
261 if (status != STATE_OK) 241 if (status != STATE_OK) {
262 /* do_query prints an error message in this case */ 242 /* do_query prints an error message in this case */
263 return status; 243 return status;
244 }
264 245
265 if (metric == METRIC_QUERY_RESULT) { 246 if (config.metric == METRIC_QUERY_RESULT) {
266 if (expect) { 247 if (config.expect) {
267 if ((! query_val_str) || strcmp (query_val_str, expect)) 248 if ((!query_val_str) || strcmp(query_val_str, config.expect)) {
268 status = STATE_CRITICAL; 249 status = STATE_CRITICAL;
269 else 250 } else {
270 status = STATE_OK; 251 status = STATE_OK;
271 } 252 }
272 else if (expect_re_str) { 253 } else if (config.expect_re_str) {
273 int err; 254 int err;
274 255
275 err = regexec (&expect_re, query_val_str, 0, NULL, /* flags = */ 0); 256 regex_t expect_re = {};
276 if (! err) 257 err = regexec(&expect_re, query_val_str, 0, NULL, /* flags = */ 0);
258 if (!err) {
277 status = STATE_OK; 259 status = STATE_OK;
278 else if (err == REG_NOMATCH) 260 } else if (err == REG_NOMATCH) {
279 status = STATE_CRITICAL; 261 status = STATE_CRITICAL;
280 else { 262 } else {
281 char errmsg[1024]; 263 char errmsg[1024];
282 regerror (err, &expect_re, errmsg, sizeof (errmsg)); 264 regerror(err, &expect_re, errmsg, sizeof(errmsg));
283 printf ("ERROR - failed to execute regular expression: %s\n", 265 printf("ERROR - failed to execute regular expression: %s\n", errmsg);
284 errmsg);
285 status = STATE_CRITICAL; 266 status = STATE_CRITICAL;
286 } 267 }
268 } else {
269 status = get_status(query_val, config.dbi_thresholds);
287 } 270 }
288 else 271 } else if (config.metric == METRIC_QUERY_TIME) {
289 status = get_status (query_val, dbi_thresholds); 272 status = get_status(query_time, config.dbi_thresholds);
290 } 273 }
291 else if (metric == METRIC_QUERY_TIME)
292 status = get_status (query_time, dbi_thresholds);
293 } 274 }
294 275
295 if (verbose) 276 if (verbose) {
296 printf("Closing connection\n"); 277 printf("Closing connection\n");
297 dbi_conn_close (conn); 278 }
279 dbi_conn_close(conn);
298 280
299 /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error 281 /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error
300 * which should have been reported and handled (abort) before 282 * which should have been reported and handled (abort) before
301 * ... unless we expected a string to be returned */ 283 * ... unless we expected a string to be returned */
302 assert ((metric != METRIC_QUERY_RESULT) || (! isnan (query_val)) 284 assert((config.metric != METRIC_QUERY_RESULT) || (!isnan(query_val)) || (config.type == TYPE_STRING));
303 || (type == TYPE_STRING));
304 285
305 assert ((type != TYPE_STRING) || (expect || expect_re_str)); 286 assert((config.type != TYPE_STRING) || (config.expect || config.expect_re_str));
306 287
307 printf ("%s - connection time: %fs", state_text (status), conn_time); 288 printf("%s - connection time: %fs", state_text(status), conn_time);
308 if (np_dbi_query) { 289 if (config.dbi_query) {
309 if (type == TYPE_STRING) { 290 if (config.type == TYPE_STRING) {
310 assert (expect || expect_re_str); 291 assert(config.expect || config.expect_re_str);
311 printf (", '%s' returned '%s' in %fs", np_dbi_query, 292 printf(", '%s' returned '%s' in %fs", config.dbi_query, query_val_str ? query_val_str : "<nothing>", query_time);
312 query_val_str ? query_val_str : "<nothing>", query_time);
313 if (status != STATE_OK) { 293 if (status != STATE_OK) {
314 if (expect) 294 if (config.expect) {
315 printf (" (expected '%s')", expect); 295 printf(" (expected '%s')", config.expect);
316 else if (expect_re_str) 296 } else if (config.expect_re_str) {
317 printf (" (expected regex /%s/%s)", expect_re_str, 297 printf(" (expected regex /%s/%s)", config.expect_re_str, ((config.expect_re_cflags & REG_ICASE) ? "i" : ""));
318 ((expect_re_cflags & REG_ICASE) ? "i" : "")); 298 }
319 } 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);
320 } 304 }
321 else if (isnan (query_val)) 305 }
322 printf (", '%s' query execution time: %fs", np_dbi_query, query_time); 306
323 else 307 printf(" | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time,
324 printf (", '%s' returned %f in %fs", np_dbi_query, query_val, query_time); 308 ((config.metric == METRIC_CONN_TIME) && config.warning_range) ? config.warning_range : "",
325 } 309 ((config.metric == METRIC_CONN_TIME) && config.critical_range) ? config.critical_range : "", server_version,
326 310 ((config.metric == METRIC_SERVER_VERSION) && config.warning_range) ? config.warning_range : "",
327 printf (" | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time, 311 ((config.metric == METRIC_SERVER_VERSION) && config.critical_range) ? config.critical_range : "");
328 ((metric == METRIC_CONN_TIME) && warning_range) ? warning_range : "", 312 if (config.dbi_query) {
329 ((metric == METRIC_CONN_TIME) && critical_range) ? critical_range : "", 313 if (!isnan(query_val)) { /* this is also true when -e is used */
330 server_version, 314 printf(" query=%f;%s;%s;;", query_val, ((config.metric == METRIC_QUERY_RESULT) && config.warning_range) ? config.warning_range : "",
331 ((metric == METRIC_SERVER_VERSION) && warning_range) ? warning_range : "", 315 ((config.metric == METRIC_QUERY_RESULT) && config.critical_range) ? config.critical_range : "");
332 ((metric == METRIC_SERVER_VERSION) && critical_range) ? critical_range : ""); 316 }
333 if (np_dbi_query) { 317 printf(" querytime=%fs;%s;%s;0;", query_time, ((config.metric == METRIC_QUERY_TIME) && config.warning_range) ? config.warning_range : "",
334 if (! isnan (query_val)) /* this is also true when -e is used */ 318 ((config.metric == METRIC_QUERY_TIME) && config.critical_range) ? config.critical_range : "");
335 printf (" query=%f;%s;%s;;", query_val, 319 }
336 ((metric == METRIC_QUERY_RESULT) && warning_range) ? warning_range : "", 320 printf("\n");
337 ((metric == METRIC_QUERY_RESULT) && critical_range) ? critical_range : "");
338 printf (" querytime=%fs;%s;%s;0;", query_time,
339 ((metric == METRIC_QUERY_TIME) && warning_range) ? warning_range : "",
340 ((metric == METRIC_QUERY_TIME) && critical_range) ? critical_range : "");
341 }
342 printf ("\n");
343 return status; 321 return status;
344} 322}
345 323
346/* process command-line arguments */ 324/* process command-line arguments */
347int 325check_dbi_config_wrapper process_arguments(int argc, char **argv) {
348process_arguments (int argc, char **argv)
349{
350 int c;
351 326
352 int option = 0; 327 int option = 0;
353 static struct option longopts[] = { 328 static struct option longopts[] = {STD_LONG_OPTS,
354 STD_LONG_OPTS, 329
355 330 {"expect", required_argument, 0, 'e'},
356 {"expect", required_argument, 0, 'e'}, 331 {"regex", required_argument, 0, 'r'},
357 {"regex", required_argument, 0, 'r'}, 332 {"regexi", required_argument, 0, 'R'},
358 {"regexi", required_argument, 0, 'R'}, 333 {"metric", required_argument, 0, 'm'},
359 {"metric", required_argument, 0, 'm'}, 334 {"driver", required_argument, 0, 'd'},
360 {"driver", required_argument, 0, 'd'}, 335 {"option", required_argument, 0, 'o'},
361 {"option", required_argument, 0, 'o'}, 336 {"query", required_argument, 0, 'q'},
362 {"query", required_argument, 0, 'q'}, 337 {"database", required_argument, 0, 'D'},
363 {"database", required_argument, 0, 'D'}, 338 {0, 0, 0, 0}};
364 {0, 0, 0, 0} 339
340 check_dbi_config_wrapper result = {
341 .config = check_dbi_config_init(),
342 .errorcode = OK,
365 }; 343 };
344 int option_char;
345 while (true) {
346 option_char = getopt_long(argc, argv, "Vvht:c:w:e:r:R:m:H:d:o:q:D:", longopts, &option);
366 347
367 while (1) { 348 if (option_char == EOF) {
368 c = getopt_long (argc, argv, "Vvht:c:w:e:r:R:m:H:d:o:q:D:",
369 longopts, &option);
370
371 if (c == EOF)
372 break; 349 break;
350 }
373 351
374 switch (c) { 352 switch (option_char) {
375 case '?': /* usage */ 353 case '?': /* usage */
376 usage5 (); 354 usage5();
377 case 'h': /* help */ 355 case 'h': /* help */
378 print_help (); 356 print_help();
379 exit (STATE_UNKNOWN); 357 exit(STATE_UNKNOWN);
380 case 'V': /* version */ 358 case 'V': /* version */
381 print_revision (progname, NP_VERSION); 359 print_revision(progname, NP_VERSION);
382 exit (STATE_UNKNOWN); 360 exit(STATE_UNKNOWN);
383 361
384 case 'c': /* critical range */ 362 case 'c': /* critical range */
385 critical_range = optarg; 363 result.config.critical_range = optarg;
386 type = TYPE_NUMERIC; 364 result.config.type = TYPE_NUMERIC;
387 break; 365 break;
388 case 'w': /* warning range */ 366 case 'w': /* warning range */
389 warning_range = optarg; 367 result.config.warning_range = optarg;
390 type = TYPE_NUMERIC; 368 result.config.type = TYPE_NUMERIC;
391 break; 369 break;
392 case 'e': 370 case 'e':
393 expect = optarg; 371 result.config.expect = optarg;
394 type = TYPE_STRING; 372 result.config.type = TYPE_STRING;
395 break; 373 break;
396 case 'R': 374 case 'R':
397 expect_re_cflags = REG_ICASE; 375 result.config.expect_re_cflags = REG_ICASE;
398 /* fall through */ 376 /* fall through */
399 case 'r': 377 case 'r': {
400 { 378 int err;
401 int err; 379
402 380 result.config.expect_re_cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
403 expect_re_cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 381 result.config.expect_re_str = optarg;
404 expect_re_str = optarg; 382 result.config.type = TYPE_STRING;
405 type = TYPE_STRING; 383
406 384 regex_t expect_re = {};
407 err = regcomp (&expect_re, expect_re_str, expect_re_cflags); 385 err = regcomp(&expect_re, result.config.expect_re_str, result.config.expect_re_cflags);
408 if (err) { 386 if (err) {
409 char errmsg[1024]; 387 char errmsg[1024];
410 regerror (err, &expect_re, errmsg, sizeof (errmsg)); 388 regerror(err, &expect_re, errmsg, sizeof(errmsg));
411 printf ("ERROR - failed to compile regular expression: %s\n", 389 printf("ERROR - failed to compile regular expression: %s\n", errmsg);
412 errmsg); 390
413 return ERROR; 391 result.errorcode = ERROR;
414 } 392 return result;
415 break;
416 } 393 }
394 break;
395 }
417 396
418 case 'm': 397 case 'm':
419 if (! strcasecmp (optarg, "CONN_TIME")) 398 if (!strcasecmp(optarg, "CONN_TIME")) {
420 metric = METRIC_CONN_TIME; 399 result.config.metric = METRIC_CONN_TIME;
421 else if (! strcasecmp (optarg, "SERVER_VERSION")) 400 } else if (!strcasecmp(optarg, "SERVER_VERSION")) {
422 metric = METRIC_SERVER_VERSION; 401 result.config.metric = METRIC_SERVER_VERSION;
423 else if (! strcasecmp (optarg, "QUERY_RESULT")) 402 } else if (!strcasecmp(optarg, "QUERY_RESULT")) {
424 metric = METRIC_QUERY_RESULT; 403 result.config.metric = METRIC_QUERY_RESULT;
425 else if (! strcasecmp (optarg, "QUERY_TIME")) 404 } else if (!strcasecmp(optarg, "QUERY_TIME")) {
426 metric = METRIC_QUERY_TIME; 405 result.config.metric = METRIC_QUERY_TIME;
427 else 406 } else {
428 usage2 (_("Invalid metric"), optarg); 407 usage2(_("Invalid metric"), optarg);
408 }
429 break; 409 break;
430 case 't': /* timeout */ 410 case 't': /* timeout */
431 if (!is_intnonneg (optarg)) 411 if (!is_intnonneg(optarg)) {
432 usage2 (_("Timeout interval must be a positive integer"), optarg); 412 usage2(_("Timeout interval must be a positive integer"), optarg);
433 else 413 } else {
434 timeout_interval = atoi (optarg); 414 timeout_interval = atoi(optarg);
415 }
435 416
436 break; 417 break;
437 case 'H': /* host */ 418 case 'H': /* host */
438 if (!is_host (optarg)) 419 if (!is_host(optarg)) {
439 usage2 (_("Invalid hostname/address"), optarg); 420 usage2(_("Invalid hostname/address"), optarg);
440 else 421 } else {
441 host = optarg; 422 result.config.host = optarg;
423 }
442 break; 424 break;
443 case 'v': 425 case 'v':
444 verbose++; 426 verbose++;
445 break; 427 break;
446 428
447 case 'd': 429 case 'd':
448 np_dbi_driver = optarg; 430 result.config.dbi_driver = optarg;
449 break; 431 break;
450 case 'o': 432 case 'o': {
451 { 433 driver_option_t *new = NULL;
452 driver_option_t *new;
453
454 char *k, *v;
455 434
456 k = optarg; 435 char *key = optarg;
457 v = strchr (k, (int)'='); 436 char *value = strchr(key, '=');
458 437
459 if (! v) 438 if (!value) {
460 usage2 (_("Option must be '<key>=<value>'"), optarg); 439 usage2(_("Option must be '<key>=<value>'"), optarg);
440 }
461 441
462 *v = '\0'; 442 *value = '\0';
463 ++v; 443 ++value;
464 444
465 new = realloc (np_dbi_options, 445 new = realloc(result.config.dbi_options, (result.config.dbi_options_num + 1) * sizeof(*new));
466 (np_dbi_options_num + 1) * sizeof (*new)); 446 if (!new) {
467 if (! new) { 447 printf("UNKNOWN - failed to reallocate memory\n");
468 printf ("UNKNOWN - failed to reallocate memory\n"); 448 exit(STATE_UNKNOWN);
469 exit (STATE_UNKNOWN); 449 }
470 }
471 450
472 np_dbi_options = new; 451 result.config.dbi_options = new;
473 new = np_dbi_options + np_dbi_options_num; 452 new = result.config.dbi_options + result.config.dbi_options_num;
474 ++np_dbi_options_num; 453 result.config.dbi_options_num++;
475 454
476 new->key = k; 455 new->key = key;
477 new->value = v; 456 new->value = value;
478 } 457 } break;
479 break;
480 case 'q': 458 case 'q':
481 np_dbi_query = optarg; 459 result.config.dbi_query = optarg;
482 break; 460 break;
483 case 'D': 461 case 'D':
484 np_dbi_database = optarg; 462 result.config.dbi_database = optarg;
485 break; 463 break;
486 } 464 }
487 } 465 }
488 466
489 set_thresholds (&dbi_thresholds, warning_range, critical_range); 467 set_thresholds(&result.config.dbi_thresholds, result.config.warning_range, result.config.critical_range);
490 468
491 return validate_arguments (); 469 return validate_arguments(result);
492} 470}
493 471
494int 472check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper config_wrapper) {
495validate_arguments () 473 if (!config_wrapper.config.dbi_driver) {
496{ 474 usage("Must specify a DBI driver");
497 if (! np_dbi_driver) 475 }
498 usage ("Must specify a DBI driver");
499 476
500 if (((metric == METRIC_QUERY_RESULT) || (metric == METRIC_QUERY_TIME)) 477 if (((config_wrapper.config.metric == METRIC_QUERY_RESULT) || (config_wrapper.config.metric == METRIC_QUERY_TIME)) &&
501 && (! np_dbi_query)) 478 (!config_wrapper.config.dbi_query)) {
502 usage ("Must specify a query to execute (metric == QUERY_RESULT)"); 479 usage("Must specify a query to execute (metric == QUERY_RESULT)");
480 }
503 481
504 if ((metric != METRIC_CONN_TIME) 482 if ((config_wrapper.config.metric != METRIC_CONN_TIME) && (config_wrapper.config.metric != METRIC_SERVER_VERSION) &&
505 && (metric != METRIC_SERVER_VERSION) 483 (config_wrapper.config.metric != METRIC_QUERY_RESULT) && (config_wrapper.config.metric != METRIC_QUERY_TIME)) {
506 && (metric != METRIC_QUERY_RESULT) 484 usage("Invalid metric specified");
507 && (metric != METRIC_QUERY_TIME)) 485 }
508 usage ("Invalid metric specified");
509 486
510 if (expect && (warning_range || critical_range || expect_re_str)) 487 if (config_wrapper.config.expect && (config_wrapper.config.warning_range || config_wrapper.config.critical_range || config_wrapper.config.expect_re_str)) {
511 usage ("Do not mix -e and -w/-c/-r/-R"); 488 usage("Do not mix -e and -w/-c/-r/-R");
489 }
512 490
513 if (expect_re_str && (warning_range || critical_range || expect)) 491 if (config_wrapper.config.expect_re_str && (config_wrapper.config.warning_range || config_wrapper.config.critical_range || config_wrapper.config.expect)) {
514 usage ("Do not mix -r/-R and -w/-c/-e"); 492 usage("Do not mix -r/-R and -w/-c/-e");
493 }
515 494
516 if (expect && (metric != METRIC_QUERY_RESULT)) 495 if (config_wrapper.config.expect && (config_wrapper.config.metric != METRIC_QUERY_RESULT)) {
517 usage ("Option -e requires metric QUERY_RESULT"); 496 usage("Option -e requires metric QUERY_RESULT");
497 }
518 498
519 if (expect_re_str && (metric != METRIC_QUERY_RESULT)) 499 if (config_wrapper.config.expect_re_str && (config_wrapper.config.metric != METRIC_QUERY_RESULT)) {
520 usage ("Options -r/-R require metric QUERY_RESULT"); 500 usage("Options -r/-R require metric QUERY_RESULT");
501 }
521 502
522 return OK; 503 config_wrapper.errorcode = OK;
504 return config_wrapper;
523} 505}
524 506
525void 507void print_help(void) {
526print_help (void) 508 print_revision(progname, NP_VERSION);
527{
528 print_revision (progname, NP_VERSION);
529 509
530 printf (COPYRIGHT, copyright, email); 510 printf(COPYRIGHT, copyright, email);
531 511
532 printf (_("This program connects to an (SQL) database using DBI and checks the\n" 512 printf(_("This program connects to an (SQL) database using DBI and checks the\n"
533 "specified metric against threshold levels. The default metric is\n" 513 "specified metric against threshold levels. The default metric is\n"
534 "the result of the specified query.\n")); 514 "the result of the specified query.\n"));
535 515
536 printf ("\n\n"); 516 printf("\n\n");
537 517
538 print_usage (); 518 print_usage();
539 519
540 printf (UT_HELP_VRSN); 520 printf(UT_HELP_VRSN);
541/* include this conditionally to avoid 'zero-length printf format string' 521/* include this conditionally to avoid 'zero-length printf format string'
542 * compiler warnings */ 522 * compiler warnings */
543#ifdef NP_EXTRA_OPTS 523#ifdef NP_EXTRA_OPTS
544 printf (UT_EXTRA_OPTS); 524 printf(UT_EXTRA_OPTS);
545#endif 525#endif
546 printf ("\n"); 526 printf("\n");
547 527
548 printf (" %s\n", "-d, --driver=STRING"); 528 printf(" %s\n", "-d, --driver=STRING");
549 printf (" %s\n", _("DBI driver to use")); 529 printf(" %s\n", _("DBI driver to use"));
550 printf (" %s\n", "-o, --option=STRING"); 530 printf(" %s\n", "-o, --option=STRING");
551 printf (" %s\n", _("DBI driver options")); 531 printf(" %s\n", _("DBI driver options"));
552 printf (" %s\n", "-q, --query=STRING"); 532 printf(" %s\n", "-q, --query=STRING");
553 printf (" %s\n", _("query to execute")); 533 printf(" %s\n", _("query to execute"));
554 printf ("\n"); 534 printf(" %s\n", "-H STRING");
555 535 printf(" %s\n", _("target database host"));
556 printf (UT_WARN_CRIT_RANGE); 536 printf("\n");
557 printf (" %s\n", "-e, --expect=STRING"); 537
558 printf (" %s\n", _("String to expect as query result")); 538 printf(UT_WARN_CRIT_RANGE);
559 printf (" %s\n", _("Do not mix with -w, -c, -r, or -R!")); 539 printf(" %s\n", "-e, --expect=STRING");
560 printf (" %s\n", "-r, --regex=REGEX"); 540 printf(" %s\n", _("String to expect as query result"));
561 printf (" %s\n", _("Extended POSIX regular expression to check query result against")); 541 printf(" %s\n", _("Do not mix with -w, -c, -r, or -R!"));
562 printf (" %s\n", _("Do not mix with -w, -c, -e, or -R!")); 542 printf(" %s\n", "-r, --regex=REGEX");
563 printf (" %s\n", "-R, --regexi=REGEX"); 543 printf(" %s\n", _("Extended POSIX regular expression to check query result against"));
564 printf (" %s\n", _("Case-insensitive extended POSIX regex to check query result against")); 544 printf(" %s\n", _("Do not mix with -w, -c, -e, or -R!"));
565 printf (" %s\n", _("Do not mix with -w, -c, -e, or -r!")); 545 printf(" %s\n", "-R, --regexi=REGEX");
566 printf (" %s\n", "-m, --metric=METRIC"); 546 printf(" %s\n", _("Case-insensitive extended POSIX regex to check query result against"));
567 printf (" %s\n", _("Metric to check thresholds against. Available metrics:")); 547 printf(" %s\n", _("Do not mix with -w, -c, -e, or -r!"));
568 printf (" CONN_TIME - %s\n", _("time used for setting up the database connection")); 548 printf(" %s\n", "-m, --metric=METRIC");
569 printf (" QUERY_RESULT - %s\n", _("result (first column of first row) of the query")); 549 printf(" %s\n", _("Metric to check thresholds against. Available metrics:"));
570 printf (" QUERY_TIME - %s\n", _("time used to execute the query")); 550 printf(" CONN_TIME - %s\n", _("time used for setting up the database connection"));
571 printf (" %s\n", _("(ignore the query result)")); 551 printf(" QUERY_RESULT - %s\n", _("result (first column of first row) of the query"));
572 printf ("\n"); 552 printf(" QUERY_TIME - %s\n", _("time used to execute the query"));
573 553 printf(" %s\n", _("(ignore the query result)"));
574 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 554 printf("\n");
575 555
576 printf (UT_VERBOSE); 556 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
577 557
578 printf ("\n"); 558 printf(UT_VERBOSE);
579 printf (" %s\n", _("A DBI driver (-d option) is required. If the specified metric operates")); 559
580 printf (" %s\n\n", _("on a query, one has to be specified (-q option).")); 560 printf("\n");
581 561 printf(" %s\n", _("A DBI driver (-d option) is required. If the specified metric operates"));
582 printf (" %s\n", _("This plugin connects to an (SQL) database using libdbi and, optionally,")); 562 printf(" %s\n\n", _("on a query, one has to be specified (-q option)."));
583 printf (" %s\n", _("executes the specified query. The first column of the first row of the")); 563
584 printf (" %s\n", _("result will be parsed and, in QUERY_RESULT mode, compared with the")); 564 printf(" %s\n", _("This plugin connects to an (SQL) database using libdbi and, optionally,"));
585 printf (" %s\n", _("warning and critical ranges. The result from the query has to be numeric")); 565 printf(" %s\n", _("executes the specified query. The first column of the first row of the"));
586 printf (" %s\n\n", _("(strings representing numbers are fine).")); 566 printf(" %s\n", _("result will be parsed and, in QUERY_RESULT mode, compared with the"));
587 567 printf(" %s\n", _("warning and critical ranges. The result from the query has to be numeric"));
588 printf (" %s\n", _("The number and type of required DBI driver options depends on the actual")); 568 printf(" %s\n\n", _("(strings representing numbers are fine)."));
589 printf (" %s\n", _("driver. See its documentation at http://libdbi-drivers.sourceforge.net/")); 569
590 printf (" %s\n\n", _("for details.")); 570 printf(" %s\n", _("The number and type of required DBI driver options depends on the actual"));
591 571 printf(" %s\n", _("driver. See its documentation at http://libdbi-drivers.sourceforge.net/"));
592 printf (" %s\n", _("Examples:")); 572 printf(" %s\n\n", _("for details."));
593 printf (" check_dbi -d pgsql -o username=postgres -m QUERY_RESULT \\\n"); 573
594 printf (" -q 'SELECT COUNT(*) FROM pg_stat_activity' -w 5 -c 10\n"); 574 printf(" %s\n", _("Examples:"));
595 printf (" Warning if more than five connections; critical if more than ten.\n\n"); 575 printf(" check_dbi -d pgsql -o username=postgres -m QUERY_RESULT \\\n");
596 576 printf(" -q 'SELECT COUNT(*) FROM pg_stat_activity' -w 5 -c 10\n");
597 printf (" check_dbi -d mysql -H localhost -o username=user -o password=secret \\\n"); 577 printf(" Warning if more than five connections; critical if more than ten.\n\n");
598 printf (" -q 'SELECT COUNT(*) FROM logged_in_users -w 5:20 -c 0:50\n"); 578
599 printf (" Warning if less than 5 or more than 20 users are logged in; critical\n"); 579 printf(" check_dbi -d mysql -H localhost -o username=user -o password=secret \\\n");
600 printf (" if more than 50 users.\n\n"); 580 printf(" -q 'SELECT COUNT(*) FROM logged_in_users -w 5:20 -c 0:50\n");
601 581 printf(" Warning if less than 5 or more than 20 users are logged in; critical\n");
602 printf (" check_dbi -d firebird -o username=user -o password=secret -o dbname=foo \\\n"); 582 printf(" if more than 50 users.\n\n");
603 printf (" -m CONN_TIME -w 0.5 -c 2\n"); 583
604 printf (" Warning if connecting to the database takes more than half of a second;\n"); 584 printf(" check_dbi -d firebird -o username=user -o password=secret -o dbname=foo \\\n");
605 printf (" critical if it takes more than 2 seconds.\n\n"); 585 printf(" -m CONN_TIME -w 0.5 -c 2\n");
606 586 printf(" Warning if connecting to the database takes more than half of a second;\n");
607 printf (" check_dbi -d mysql -H localhost -o username=user \\\n"); 587 printf(" critical if it takes more than 2 seconds.\n\n");
608 printf (" -q 'SELECT concat(@@version, \" \", @@version_comment)' \\\n"); 588
609 printf (" -r '^5\\.[01].*MySQL Enterprise Server'\n"); 589 printf(" check_dbi -d mysql -H localhost -o username=user \\\n");
610 printf (" Critical if the database server is not a MySQL enterprise server in either\n"); 590 printf(" -q 'SELECT concat(@@version, \" \", @@version_comment)' \\\n");
611 printf (" version 5.0.x or 5.1.x.\n\n"); 591 printf(" -r '^5\\.[01].*MySQL Enterprise Server'\n");
612 592 printf(" Critical if the database server is not a MySQL enterprise server in either\n");
613 printf (" check_dbi -d pgsql -u username=user -m SERVER_VERSION \\\n"); 593 printf(" version 5.0.x or 5.1.x.\n\n");
614 printf (" -w 090000:090099 -c 090000:090199\n"); 594
615 printf (" Warn if the PostgreSQL server version is not 9.0.x; critical if the version\n"); 595 printf(" check_dbi -d pgsql -u username=user -m SERVER_VERSION \\\n");
616 printf (" is less than 9.x or higher than 9.1.x.\n"); 596 printf(" -w 090000:090099 -c 090000:090199\n");
617 597 printf(" Warn if the PostgreSQL server version is not 9.0.x; critical if the version\n");
618 printf (UT_SUPPORT); 598 printf(" is less than 9.x or higher than 9.1.x.\n");
599
600 printf(UT_SUPPORT);
619} 601}
620 602
621void 603void print_usage(void) {
622print_usage (void) 604 printf("%s\n", _("Usage:"));
623{ 605 printf("%s -d <DBI driver> [-o <DBI driver option> [...]] [-q <query>]\n", progname);
624 printf ("%s\n", _("Usage:")); 606 printf(" [-H <host>] [-c <critical range>] [-w <warning range>] [-m <metric>]\n");
625 printf ("%s -d <DBI driver> [-o <DBI driver option> [...]] [-q <query>]\n", progname); 607 printf(" [-e <string>] [-r|-R <regex>]\n");
626 printf (" [-H <host>] [-c <critical range>] [-w <warning range>] [-m <metric>]\n");
627 printf (" [-e <string>] [-r|-R <regex>]\n");
628} 608}
629 609
630#define CHECK_IGNORE_ERROR(s) \ 610const char *get_field_str(dbi_conn conn, dbi_result res, unsigned short field_type, mp_dbi_metric metric, mp_dbi_type type) {
631 do { \
632 if (metric != METRIC_QUERY_RESULT) \
633 return (s); \
634 } while (0)
635
636const char *
637get_field_str (dbi_conn conn, dbi_result res, unsigned short field_type)
638{
639 const char *str; 611 const char *str;
640 612
641 if (field_type != DBI_TYPE_STRING) { 613 if (field_type != DBI_TYPE_STRING) {
642 printf ("CRITICAL - result value is not a string\n"); 614 printf("CRITICAL - result value is not a string\n");
643 return NULL; 615 return NULL;
644 } 616 }
645 617
646 str = dbi_result_get_string_idx (res, 1); 618 str = dbi_result_get_string_idx(res, 1);
647 if ((! str) || (strcmp (str, "ERROR") == 0)) { 619 if ((!str) || (strcmp(str, "ERROR") == 0)) {
648 CHECK_IGNORE_ERROR (NULL); 620 if (metric != METRIC_QUERY_RESULT) {
649 np_dbi_print_error (conn, "CRITICAL - failed to fetch string value"); 621 return NULL;
622 }
623 np_dbi_print_error(conn, "CRITICAL - failed to fetch string value");
650 return NULL; 624 return NULL;
651 } 625 }
652 626
653 if ((verbose && (type == TYPE_STRING)) || (verbose > 2)) 627 if ((verbose && (type == TYPE_STRING)) || (verbose > 2)) {
654 printf ("Query returned string '%s'\n", str); 628 printf("Query returned string '%s'\n", str);
629 }
655 return str; 630 return str;
656} 631}
657 632
658double 633double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type, mp_dbi_metric metric, mp_dbi_type type) {
659get_field (dbi_conn conn, dbi_result res, unsigned short *field_type)
660{
661 double val = NAN; 634 double val = NAN;
662 635
663 if (*field_type == DBI_TYPE_INTEGER) { 636 if (*field_type == DBI_TYPE_INTEGER) {
664 val = (double)dbi_result_get_longlong_idx (res, 1); 637 val = (double)dbi_result_get_longlong_idx(res, 1);
665 } 638 } else if (*field_type == DBI_TYPE_DECIMAL) {
666 else if (*field_type == DBI_TYPE_DECIMAL) { 639 val = dbi_result_get_double_idx(res, 1);
667 val = dbi_result_get_double_idx (res, 1); 640 } else if (*field_type == DBI_TYPE_STRING) {
668 }
669 else if (*field_type == DBI_TYPE_STRING) {
670 const char *val_str; 641 const char *val_str;
671 char *endptr = NULL; 642 char *endptr = NULL;
672 643
673 val_str = get_field_str (conn, res, *field_type); 644 val_str = get_field_str(conn, res, *field_type, metric, type);
674 if (! val_str) { 645 if (!val_str) {
675 CHECK_IGNORE_ERROR (NAN); 646 if (metric != METRIC_QUERY_RESULT) {
647 return NAN;
648 }
676 *field_type = DBI_TYPE_ERROR; 649 *field_type = DBI_TYPE_ERROR;
677 return NAN; 650 return NAN;
678 } 651 }
679 652
680 val = strtod (val_str, &endptr); 653 val = strtod(val_str, &endptr);
681 if (endptr == val_str) { 654 if (endptr == val_str) {
682 CHECK_IGNORE_ERROR (NAN); 655 if (metric != METRIC_QUERY_RESULT) {
683 printf ("CRITICAL - result value is not a numeric: %s\n", val_str); 656 return NAN;
657 }
658 printf("CRITICAL - result value is not a numeric: %s\n", val_str);
684 *field_type = DBI_TYPE_ERROR; 659 *field_type = DBI_TYPE_ERROR;
685 return NAN; 660 return NAN;
686 } 661 }
687 else if ((endptr != NULL) && (*endptr != '\0')) { 662 if ((endptr != NULL) && (*endptr != '\0')) {
688 if (verbose) 663 if (verbose) {
689 printf ("Garbage after value: %s\n", endptr); 664 printf("Garbage after value: %s\n", endptr);
665 }
690 } 666 }
691 } 667 } else {
692 else { 668 if (metric != METRIC_QUERY_RESULT) {
693 CHECK_IGNORE_ERROR (NAN); 669 return NAN;
694 printf ("CRITICAL - cannot parse value of type %s (%i)\n", 670 }
695 (*field_type == DBI_TYPE_BINARY) 671 printf("CRITICAL - cannot parse value of type %s (%i)\n",
696 ? "BINARY" 672 (*field_type == DBI_TYPE_BINARY) ? "BINARY"
697 : (*field_type == DBI_TYPE_DATETIME) 673 : (*field_type == DBI_TYPE_DATETIME) ? "DATETIME"
698 ? "DATETIME" 674 : "<unknown>",
699 : "<unknown>", 675 *field_type);
700 *field_type);
701 *field_type = DBI_TYPE_ERROR; 676 *field_type = DBI_TYPE_ERROR;
702 return NAN; 677 return NAN;
703 } 678 }
704 return val; 679 return val;
705} 680}
706 681
707double 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) {
708get_query_result (dbi_conn conn, dbi_result res, const char **res_val_str, double *res_val)
709{
710 unsigned short field_type; 683 unsigned short field_type;
711 double val = NAN; 684 double val = NAN;
712 685
713 if (dbi_result_get_numrows (res) == DBI_ROW_ERROR) { 686 if (dbi_result_get_numrows(res) == DBI_ROW_ERROR) {
714 CHECK_IGNORE_ERROR (STATE_OK); 687 if (metric != METRIC_QUERY_RESULT) {
715 np_dbi_print_error (conn, "CRITICAL - failed to fetch rows"); 688 return STATE_OK;
689 }
690 np_dbi_print_error(conn, "CRITICAL - failed to fetch rows");
716 return STATE_CRITICAL; 691 return STATE_CRITICAL;
717 } 692 }
718 693
719 if (dbi_result_get_numrows (res) < 1) { 694 if (dbi_result_get_numrows(res) < 1) {
720 CHECK_IGNORE_ERROR (STATE_OK); 695 if (metric != METRIC_QUERY_RESULT) {
721 printf ("WARNING - no rows returned\n"); 696 return STATE_OK;
697 }
698 printf("WARNING - no rows returned\n");
722 return STATE_WARNING; 699 return STATE_WARNING;
723 } 700 }
724 701
725 if (dbi_result_get_numfields (res) == DBI_FIELD_ERROR) { 702 if (dbi_result_get_numfields(res) == DBI_FIELD_ERROR) {
726 CHECK_IGNORE_ERROR (STATE_OK); 703 if (metric != METRIC_QUERY_RESULT) {
727 np_dbi_print_error (conn, "CRITICAL - failed to fetch fields"); 704 return STATE_OK;
705 }
706 np_dbi_print_error(conn, "CRITICAL - failed to fetch fields");
728 return STATE_CRITICAL; 707 return STATE_CRITICAL;
729 } 708 }
730 709
731 if (dbi_result_get_numfields (res) < 1) { 710 if (dbi_result_get_numfields(res) < 1) {
732 CHECK_IGNORE_ERROR (STATE_OK); 711 if (metric != METRIC_QUERY_RESULT) {
733 printf ("WARNING - no fields returned\n"); 712 return STATE_OK;
713 }
714 printf("WARNING - no fields returned\n");
734 return STATE_WARNING; 715 return STATE_WARNING;
735 } 716 }
736 717
737 if (dbi_result_first_row (res) != 1) { 718 if (dbi_result_first_row(res) != 1) {
738 CHECK_IGNORE_ERROR (STATE_OK); 719 if (metric != METRIC_QUERY_RESULT) {
739 np_dbi_print_error (conn, "CRITICAL - failed to fetch first row"); 720 return STATE_OK;
721 }
722 np_dbi_print_error(conn, "CRITICAL - failed to fetch first row");
740 return STATE_CRITICAL; 723 return STATE_CRITICAL;
741 } 724 }
742 725
743 field_type = dbi_result_get_field_type_idx (res, 1); 726 field_type = dbi_result_get_field_type_idx(res, 1);
744 if (field_type != DBI_TYPE_ERROR) { 727 if (field_type != DBI_TYPE_ERROR) {
745 if (type == TYPE_STRING) 728 if (type == TYPE_STRING) {
746 /* the value will be freed in dbi_result_free */ 729 /* the value will be freed in dbi_result_free */
747 *res_val_str = strdup (get_field_str (conn, res, field_type)); 730 *res_val_str = strdup(get_field_str(conn, res, field_type, metric, type));
748 else 731 } else {
749 val = get_field (conn, res, &field_type); 732 val = get_field(conn, res, &field_type, metric, type);
733 }
750 } 734 }
751 735
752 *res_val = val; 736 *res_val = val;
753 737
754 if (field_type == DBI_TYPE_ERROR) { 738 if (field_type == DBI_TYPE_ERROR) {
755 CHECK_IGNORE_ERROR (STATE_OK); 739 if (metric != METRIC_QUERY_RESULT) {
756 np_dbi_print_error (conn, "CRITICAL - failed to fetch data"); 740 return STATE_OK;
741 }
742 np_dbi_print_error(conn, "CRITICAL - failed to fetch data");
757 return STATE_CRITICAL; 743 return STATE_CRITICAL;
758 } 744 }
759 745
760 dbi_result_free (res); 746 dbi_result_free(res);
761 return STATE_OK; 747 return STATE_OK;
762} 748}
763 749
764#undef CHECK_IGNORE_ERROR 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,
765 751 char *np_dbi_query) {
766int
767do_query (dbi_conn conn, const char **res_val_str, double *res_val, double *res_time)
768{
769 dbi_result res; 752 dbi_result res;
770 753
771 struct timeval timeval_start, timeval_end; 754 struct timeval timeval_start;
772 int status = STATE_OK; 755 struct timeval timeval_end;
756 mp_state_enum status = STATE_OK;
773 757
774 assert (np_dbi_query); 758 assert(np_dbi_query);
775 759
776 if (verbose) 760 if (verbose) {
777 printf ("Executing query '%s'\n", np_dbi_query); 761 printf("Executing query '%s'\n", np_dbi_query);
762 }
778 763
779 gettimeofday (&timeval_start, NULL); 764 gettimeofday(&timeval_start, NULL);
780 765
781 res = dbi_conn_query (conn, np_dbi_query); 766 res = dbi_conn_query(conn, np_dbi_query);
782 if (! res) { 767 if (!res) {
783 np_dbi_print_error (conn, "CRITICAL - failed to execute query '%s'", np_dbi_query); 768 np_dbi_print_error(conn, "CRITICAL - failed to execute query '%s'", np_dbi_query);
784 return STATE_CRITICAL; 769 return STATE_CRITICAL;
785 } 770 }
786 771
787 status = get_query_result (conn, res, res_val_str, res_val); 772 status = get_query_result(conn, res, res_val_str, res_val, metric, type);
788 773
789 gettimeofday (&timeval_end, NULL); 774 gettimeofday(&timeval_end, NULL);
790 *res_time = timediff (timeval_start, timeval_end); 775 *res_time = timediff(timeval_start, timeval_end);
791 776
792 if (verbose) 777 if (verbose) {
793 printf ("Time elapsed: %f\n", *res_time); 778 printf("Time elapsed: %f\n", *res_time);
779 }
794 780
795 return status; 781 return status;
796} 782}
797 783
798double 784double timediff(struct timeval start, struct timeval end) {
799timediff (struct timeval start, struct timeval end)
800{
801 double diff; 785 double diff;
802 786
803 while (start.tv_usec > end.tv_usec) { 787 while (start.tv_usec > end.tv_usec) {
804 --end.tv_sec; 788 --end.tv_sec;
805 end.tv_usec += 1000000; 789 end.tv_usec += 1000000;
806 } 790 }
807 diff = (double)(end.tv_sec - start.tv_sec) 791 diff = (double)(end.tv_sec - start.tv_sec) + (double)(end.tv_usec - start.tv_usec) / 1000000.0;
808 + (double)(end.tv_usec - start.tv_usec) / 1000000.0;
809 return diff; 792 return diff;
810} 793}
811 794
812void 795void np_dbi_print_error(dbi_conn conn, char *fmt, ...) {
813np_dbi_print_error (dbi_conn conn, char *fmt, ...)
814{
815 const char *errmsg = NULL; 796 const char *errmsg = NULL;
816 va_list ap; 797 va_list ap;
817 798
818 va_start (ap, fmt); 799 va_start(ap, fmt);
819 800
820 dbi_conn_error (conn, &errmsg); 801 dbi_conn_error(conn, &errmsg);
821 vprintf (fmt, ap); 802 vprintf(fmt, ap);
822 printf (": %s\n", errmsg); 803 printf(": %s\n", errmsg);
823 804
824 va_end (ap); 805 va_end(ap);
825} 806}
826
diff --git a/plugins/check_dbi.d/config.h b/plugins/check_dbi.d/config.h
new file mode 100644
index 00000000..f6f0d7b3
--- /dev/null
+++ b/plugins/check_dbi.d/config.h
@@ -0,0 +1,63 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5#include "../../lib/monitoringplug.h"
6
7typedef enum {
8 METRIC_CONN_TIME,
9 METRIC_SERVER_VERSION,
10 METRIC_QUERY_RESULT,
11 METRIC_QUERY_TIME,
12} mp_dbi_metric;
13
14typedef enum {
15 TYPE_NUMERIC,
16 TYPE_STRING,
17} mp_dbi_type;
18
19typedef struct {
20 char *key;
21 char *value;
22} driver_option_t;
23
24typedef struct {
25 char *dbi_driver;
26 char *host;
27 driver_option_t *dbi_options;
28 size_t dbi_options_num;
29 char *dbi_database;
30 char *dbi_query;
31
32 char *expect;
33 char *expect_re_str;
34 int expect_re_cflags;
35 mp_dbi_metric metric;
36 mp_dbi_type type;
37 char *warning_range;
38 char *critical_range;
39 thresholds *dbi_thresholds;
40
41} check_dbi_config;
42
43check_dbi_config check_dbi_config_init() {
44 check_dbi_config tmp = {
45 .dbi_driver = NULL,
46 .host = NULL,
47 .dbi_options = NULL,
48 .dbi_options_num = 0,
49 .dbi_database = NULL,
50 .dbi_query = NULL,
51
52 .expect = NULL,
53 .expect_re_str = NULL,
54 .expect_re_cflags = 0,
55 .metric = METRIC_QUERY_RESULT,
56 .type = TYPE_NUMERIC,
57
58 .warning_range = NULL,
59 .critical_range = NULL,
60 .dbi_thresholds = NULL,
61 };
62 return tmp;
63}
diff --git a/plugins/check_dig.c b/plugins/check_dig.c
index be7a6101..d0903be2 100644
--- a/plugins/check_dig.c
+++ b/plugins/check_dig.c
@@ -1,30 +1,30 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_dig plugin 3 * Monitoring check_dig plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2002-2008 Monitoring Plugins Development Team 6 * Copyright (c) 2002-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_dig plugin 10 * This file contains the check_dig plugin
11* 11 *
12* 12 *
13* This program is free software: you can redistribute it and/or modify 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 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 15 * the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16 * (at your option) any later version.
17* 17 *
18* This program is distributed in the hope that it will be useful, 18 * This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21 * GNU General Public License for more details.
22* 22 *
23* You should have received a copy of the GNU General Public License 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/>. 24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25 *
26* 26 *
27*****************************************************************************/ 27 *****************************************************************************/
28 28
29/* Hackers note: 29/* Hackers note:
30 * There are typecasts to (char *) from _("foo bar") in this file. 30 * There are typecasts to (char *) from _("foo bar") in this file.
@@ -33,7 +33,7 @@
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-2008"; 36const char *copyright = "2002-2024";
37const char *email = "devel@monitoring-plugins.org"; 37const char *email = "devel@monitoring-plugins.org";
38 38
39#include "common.h" 39#include "common.h"
@@ -41,340 +41,319 @@ const char *email = "devel@monitoring-plugins.org";
41#include "utils.h" 41#include "utils.h"
42#include "runcmd.h" 42#include "runcmd.h"
43 43
44int process_arguments (int, char **); 44#include "check_dig.d/config.h"
45int validate_arguments (void); 45#include "states.h"
46void print_help (void); 46
47void print_usage (void); 47typedef struct {
48 48 int errorcode;
49#define UNDEFINED 0 49 check_dig_config config;
50#define DEFAULT_PORT 53 50} check_dig_config_wrapper;
51#define DEFAULT_TRIES 2 51static check_dig_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
52 52static check_dig_config_wrapper validate_arguments(check_dig_config_wrapper /*config_wrapper*/);
53char *query_address = NULL; 53
54char *record_type = "A"; 54static void print_help(void);
55char *expected_address = NULL; 55void print_usage(void);
56char *dns_server = NULL; 56
57char *dig_args = ""; 57static int verbose = 0;
58char *query_transport = ""; 58
59bool verbose = false; 59int main(int argc, char **argv) {
60int server_port = DEFAULT_PORT; 60 setlocale(LC_ALL, "");
61int number_tries = DEFAULT_TRIES; 61 bindtextdomain(PACKAGE, LOCALEDIR);
62double warning_interval = UNDEFINED; 62 textdomain(PACKAGE);
63double critical_interval = UNDEFINED; 63
64struct timeval tv; 64 /* Set signal handling and alarm */
65 65 if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
66int 66 usage_va(_("Cannot catch SIGALRM"));
67main (int argc, char **argv) 67 }
68{ 68
69 char *command_line; 69 /* Parse extra opts if any */
70 output chld_out, chld_err; 70 argv = np_extra_opts(&argc, argv, progname);
71 char *msg = NULL; 71
72 size_t i; 72 check_dig_config_wrapper tmp_config = process_arguments(argc, argv);
73 char *t; 73 if (tmp_config.errorcode == ERROR) {
74 long microsec; 74 usage_va(_("Could not parse arguments"));
75 double elapsed_time; 75 }
76 int result = STATE_UNKNOWN; 76
77 int timeout_interval_dig; 77 const check_dig_config config = tmp_config.config;
78 78
79 setlocale (LC_ALL, ""); 79 /* dig applies the timeout to each try, so we need to work around this */
80 bindtextdomain (PACKAGE, LOCALEDIR); 80 int timeout_interval_dig = ((int)timeout_interval / config.number_tries) + config.number_tries;
81 textdomain (PACKAGE); 81
82 82 char *command_line;
83 /* Set signal handling and alarm */ 83 /* get the command to run */
84 if (signal (SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) 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,
85 usage_va(_("Cannot catch SIGALRM")); 85 config.server_port, config.dns_server, config.query_address, config.record_type, config.number_tries, timeout_interval_dig);
86 86
87 /* Parse extra opts if any */ 87 alarm(timeout_interval);
88 argv=np_extra_opts (&argc, argv, progname); 88 struct timeval start_time;
89 89 gettimeofday(&start_time, NULL);
90 if (process_arguments (argc, argv) == ERROR) 90
91 usage_va(_("Could not parse arguments")); 91 if (verbose) {
92 92 printf("%s\n", command_line);
93 /* dig applies the timeout to each try, so we need to work around this */ 93 if (config.expected_address != NULL) {
94 timeout_interval_dig = timeout_interval / number_tries + number_tries; 94 printf(_("Looking for: '%s'\n"), config.expected_address);
95 95 } else {
96 /* get the command to run */ 96 printf(_("Looking for: '%s'\n"), config.query_address);
97 xasprintf (&command_line, "%s %s %s -p %d @%s %s %s +retry=%d +time=%d", 97 }
98 PATH_TO_DIG, dig_args, query_transport, server_port, dns_server, query_address, record_type, number_tries, timeout_interval_dig); 98 }
99 99
100 alarm (timeout_interval); 100 output chld_out;
101 gettimeofday (&tv, NULL); 101 output chld_err;
102 102 char *msg = NULL;
103 if (verbose) { 103 mp_state_enum result = STATE_UNKNOWN;
104 printf ("%s\n", command_line); 104 /* run the command */
105 if(expected_address != NULL) { 105 if (np_runcmd(command_line, &chld_out, &chld_err, 0) != 0) {
106 printf (_("Looking for: '%s'\n"), expected_address); 106 result = STATE_WARNING;
107 } else { 107 msg = (char *)_("dig returned an error status");
108 printf (_("Looking for: '%s'\n"), query_address); 108 }
109 } 109
110 } 110 for (size_t i = 0; i < chld_out.lines; i++) {
111 111 /* the server is responding, we just got the host name... */
112 /* run the command */ 112 if (strstr(chld_out.line[i], ";; ANSWER SECTION:")) {
113 if(np_runcmd(command_line, &chld_out, &chld_err, 0) != 0) { 113
114 result = STATE_WARNING; 114 /* loop through the whole 'ANSWER SECTION' */
115 msg = (char *)_("dig returned an error status"); 115 for (; i < chld_out.lines; i++) {
116 } 116 /* get the host address */
117 117 if (verbose) {
118 for(i = 0; i < chld_out.lines; i++) { 118 printf("%s\n", chld_out.line[i]);
119 /* the server is responding, we just got the host name... */ 119 }
120 if (strstr (chld_out.line[i], ";; ANSWER SECTION:")) { 120
121 121 if (strcasestr(chld_out.line[i], (config.expected_address == NULL ? config.query_address : config.expected_address)) !=
122 /* loop through the whole 'ANSWER SECTION' */ 122 NULL) {
123 for(; i < chld_out.lines; i++) { 123 msg = chld_out.line[i];
124 /* get the host address */ 124 result = STATE_OK;
125 if (verbose) 125
126 printf ("%s\n", chld_out.line[i]); 126 /* Translate output TAB -> SPACE */
127 127 char *temp = msg;
128 if (strcasestr (chld_out.line[i], (expected_address == NULL ? query_address : expected_address)) != NULL) { 128 while ((temp = strchr(temp, '\t')) != NULL) {
129 msg = chld_out.line[i]; 129 *temp = ' ';
130 result = STATE_OK; 130 }
131 131 break;
132 /* Translate output TAB -> SPACE */ 132 }
133 t = msg; 133 }
134 while ((t = strchr(t, '\t')) != NULL) *t = ' '; 134
135 break; 135 if (result == STATE_UNKNOWN) {
136 } 136 msg = (char *)_("Server not found in ANSWER SECTION");
137 } 137 result = STATE_WARNING;
138 138 }
139 if (result == STATE_UNKNOWN) { 139
140 msg = (char *)_("Server not found in ANSWER SECTION"); 140 /* we found the answer section, so break out of the loop */
141 result = STATE_WARNING; 141 break;
142 } 142 }
143 143 }
144 /* we found the answer section, so break out of the loop */ 144
145 break; 145 if (result == STATE_UNKNOWN) {
146 } 146 msg = (char *)_("No ANSWER SECTION found");
147 } 147 result = STATE_CRITICAL;
148 148 }
149 if (result == STATE_UNKNOWN) { 149
150 msg = (char *)_("No ANSWER SECTION found"); 150 /* If we get anything on STDERR, at least set warning */
151 result = STATE_CRITICAL; 151 if (chld_err.buflen > 0) {
152 } 152 result = max_state(result, STATE_WARNING);
153 153 if (!msg) {
154 /* If we get anything on STDERR, at least set warning */ 154 for (size_t i = 0; i < chld_err.lines; i++) {
155 if(chld_err.buflen > 0) { 155 msg = strchr(chld_err.line[0], ':');
156 result = max_state(result, STATE_WARNING); 156 if (msg) {
157 if(!msg) for(i = 0; i < chld_err.lines; i++) { 157 msg++;
158 msg = strchr(chld_err.line[0], ':'); 158 break;
159 if(msg) { 159 }
160 msg++; 160 }
161 break; 161 }
162 } 162 }
163 } 163
164 } 164 long microsec = deltime(start_time);
165 165 double elapsed_time = (double)microsec / 1.0e6;
166 microsec = deltime (tv); 166
167 elapsed_time = (double)microsec / 1.0e6; 167 if (config.critical_interval > UNDEFINED && elapsed_time > config.critical_interval) {
168 168 result = STATE_CRITICAL;
169 if (critical_interval > UNDEFINED && elapsed_time > critical_interval) 169 }
170 result = STATE_CRITICAL; 170
171 171 else if (config.warning_interval > UNDEFINED && elapsed_time > config.warning_interval) {
172 else if (warning_interval > UNDEFINED && elapsed_time > warning_interval) 172 result = STATE_WARNING;
173 result = STATE_WARNING; 173 }
174 174
175 printf ("DNS %s - %.3f seconds response time (%s)|%s\n", 175 printf("DNS %s - %.3f seconds response time (%s)|%s\n", state_text(result), elapsed_time,
176 state_text (result), elapsed_time, 176 msg ? msg : _("Probably a non-existent host/domain"),
177 msg ? msg : _("Probably a non-existent host/domain"), 177 fperfdata("time", elapsed_time, "s", (config.warning_interval > UNDEFINED), config.warning_interval,
178 fperfdata("time", elapsed_time, "s", 178 (config.critical_interval > UNDEFINED), config.critical_interval, true, 0, false, 0));
179 (warning_interval>UNDEFINED ? true:false), 179 exit(result);
180 warning_interval,
181 (critical_interval>UNDEFINED ? true:false),
182 critical_interval,
183 true, 0, false, 0));
184 return result;
185} 180}
186 181
187
188
189/* process command-line arguments */ 182/* process command-line arguments */
190int 183check_dig_config_wrapper process_arguments(int argc, char **argv) {
191process_arguments (int argc, char **argv) 184 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
192{ 185 {"query_address", required_argument, 0, 'l'},
193 int c; 186 {"warning", required_argument, 0, 'w'},
194 187 {"critical", required_argument, 0, 'c'},
195 int option = 0; 188 {"timeout", required_argument, 0, 't'},
196 static struct option longopts[] = { 189 {"dig-arguments", required_argument, 0, 'A'},
197 {"hostname", required_argument, 0, 'H'}, 190 {"verbose", no_argument, 0, 'v'},
198 {"query_address", required_argument, 0, 'l'}, 191 {"version", no_argument, 0, 'V'},
199 {"warning", required_argument, 0, 'w'}, 192 {"help", no_argument, 0, 'h'},
200 {"critical", required_argument, 0, 'c'}, 193 {"record_type", required_argument, 0, 'T'},
201 {"timeout", required_argument, 0, 't'}, 194 {"expected_address", required_argument, 0, 'a'},
202 {"dig-arguments", required_argument, 0, 'A'}, 195 {"port", required_argument, 0, 'p'},
203 {"verbose", no_argument, 0, 'v'}, 196 {"use-ipv4", no_argument, 0, '4'},
204 {"version", no_argument, 0, 'V'}, 197 {"use-ipv6", no_argument, 0, '6'},
205 {"help", no_argument, 0, 'h'}, 198 {0, 0, 0, 0}};
206 {"record_type", required_argument, 0, 'T'}, 199
207 {"expected_address", required_argument, 0, 'a'}, 200 check_dig_config_wrapper result = {
208 {"port", required_argument, 0, 'p'}, 201 .errorcode = OK,
209 {"use-ipv4", no_argument, 0, '4'}, 202 .config = check_dig_config_init(),
210 {"use-ipv6", no_argument, 0, '6'}, 203 };
211 {0, 0, 0, 0} 204
212 }; 205 if (argc < 2) {
213 206 result.errorcode = ERROR;
214 if (argc < 2) 207 return result;
215 return ERROR; 208 }
216 209
217 while (1) { 210 int option = 0;
218 c = getopt_long (argc, argv, "hVvt:l:H:w:c:T:p:a:A:46", longopts, &option); 211 while (true) {
219 212 int option_index = getopt_long(argc, argv, "hVvt:l:H:w:c:T:p:a:A:46", longopts, &option);
220 if (c == -1 || c == EOF) 213
221 break; 214 if (option_index == -1 || option_index == EOF) {
222 215 break;
223 switch (c) { 216 }
224 case 'h': /* help */ 217
225 print_help (); 218 switch (option_index) {
226 exit (STATE_UNKNOWN); 219 case 'h': /* help */
227 case 'V': /* version */ 220 print_help();
228 print_revision (progname, NP_VERSION); 221 exit(STATE_UNKNOWN);
229 exit (STATE_UNKNOWN); 222 case 'V': /* version */
230 case 'H': /* hostname */ 223 print_revision(progname, NP_VERSION);
231 host_or_die(optarg); 224 exit(STATE_UNKNOWN);
232 dns_server = optarg; 225 case 'H': /* hostname */
233 break; 226 host_or_die(optarg);
234 case 'p': /* server port */ 227 result.config.dns_server = optarg;
235 if (is_intpos (optarg)) { 228 break;
236 server_port = atoi (optarg); 229 case 'p': /* server port */
237 } 230 if (is_intpos(optarg)) {
238 else { 231 result.config.server_port = atoi(optarg);
239 usage_va(_("Port must be a positive integer - %s"), optarg); 232 } else {
240 } 233 usage_va(_("Port must be a positive integer - %s"), optarg);
241 break; 234 }
242 case 'l': /* address to lookup */ 235 break;
243 query_address = optarg; 236 case 'l': /* address to lookup */
244 break; 237 result.config.query_address = optarg;
245 case 'w': /* warning */ 238 break;
246 if (is_nonnegative (optarg)) { 239 case 'w': /* warning */
247 warning_interval = strtod (optarg, NULL); 240 if (is_nonnegative(optarg)) {
248 } 241 result.config.warning_interval = strtod(optarg, NULL);
249 else { 242 } else {
250 usage_va(_("Warning interval must be a positive integer - %s"), optarg); 243 usage_va(_("Warning interval must be a positive integer - %s"), optarg);
251 } 244 }
252 break; 245 break;
253 case 'c': /* critical */ 246 case 'c': /* critical */
254 if (is_nonnegative (optarg)) { 247 if (is_nonnegative(optarg)) {
255 critical_interval = strtod (optarg, NULL); 248 result.config.critical_interval = strtod(optarg, NULL);
256 } 249 } else {
257 else { 250 usage_va(_("Critical interval must be a positive integer - %s"), optarg);
258 usage_va(_("Critical interval must be a positive integer - %s"), optarg); 251 }
259 } 252 break;
260 break; 253 case 't': /* timeout */
261 case 't': /* timeout */ 254 if (is_intnonneg(optarg)) {
262 if (is_intnonneg (optarg)) { 255 timeout_interval = atoi(optarg);
263 timeout_interval = atoi (optarg); 256 } else {
264 } 257 usage_va(_("Timeout interval must be a positive integer - %s"), optarg);
265 else { 258 }
266 usage_va(_("Timeout interval must be a positive integer - %s"), optarg); 259 break;
267 } 260 case 'A': /* dig arguments */
268 break; 261 result.config.dig_args = strdup(optarg);
269 case 'A': /* dig arguments */ 262 break;
270 dig_args = strdup(optarg); 263 case 'v': /* verbose */
271 break; 264 verbose++;
272 case 'v': /* verbose */ 265 break;
273 verbose = true; 266 case 'T':
274 break; 267 result.config.record_type = optarg;
275 case 'T': 268 break;
276 record_type = optarg; 269 case 'a':
277 break; 270 result.config.expected_address = optarg;
278 case 'a': 271 break;
279 expected_address = optarg; 272 case '4':
280 break; 273 result.config.query_transport = "-4";
281 case '4': 274 break;
282 query_transport = "-4"; 275 case '6':
283 break; 276 result.config.query_transport = "-6";
284 case '6': 277 break;
285 query_transport = "-6"; 278 default: /* usage5 */
286 break; 279 usage5();
287 default: /* usage5 */ 280 }
288 usage5(); 281 }
289 } 282
290 } 283 int index = optind;
291 284 if (result.config.dns_server == NULL) {
292 c = optind; 285 if (index < argc) {
293 if (dns_server == NULL) { 286 host_or_die(argv[index]);
294 if (c < argc) { 287 result.config.dns_server = argv[index];
295 host_or_die(argv[c]); 288 } else {
296 dns_server = argv[c]; 289 if (strcmp(result.config.query_transport, "-6") == 0) {
297 } 290 result.config.dns_server = strdup("::1");
298 else { 291 } else {
299 if (strcmp(query_transport,"-6") == 0) 292 result.config.dns_server = strdup("127.0.0.1");
300 dns_server = strdup("::1"); 293 }
301 else 294 }
302 dns_server = strdup ("127.0.0.1"); 295 }
303 } 296
304 } 297 return validate_arguments(result);
305
306 return validate_arguments ();
307} 298}
308 299
309 300check_dig_config_wrapper validate_arguments(check_dig_config_wrapper config_wrapper) {
310 301 if (config_wrapper.config.query_address == NULL) {
311int 302 config_wrapper.errorcode = ERROR;
312validate_arguments (void) 303 }
313{ 304 return config_wrapper;
314 if (query_address != NULL)
315 return OK;
316 else
317 return ERROR;
318} 305}
319 306
307void print_help(void) {
308 char *myport;
320 309
310 xasprintf(&myport, "%d", DEFAULT_PORT);
321 311
322void 312 print_revision(progname, NP_VERSION);
323print_help (void)
324{
325 char *myport;
326 313
327 xasprintf (&myport, "%d", DEFAULT_PORT); 314 printf("Copyright (c) 2000 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n");
315 printf(COPYRIGHT, copyright, email);
328 316
329 print_revision (progname, NP_VERSION); 317 printf(_("This plugin tests the DNS service on the specified host using dig"));
330 318
331 printf ("Copyright (c) 2000 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n"); 319 printf("\n\n");
332 printf (COPYRIGHT, copyright, email);
333 320
334 printf (_("This plugin tests the DNS service on the specified host using dig")); 321 print_usage();
335 322
336 printf ("\n\n"); 323 printf(UT_HELP_VRSN);
337 324
338 print_usage (); 325 printf(UT_EXTRA_OPTS);
339 326
340 printf (UT_HELP_VRSN); 327 printf(UT_HOST_PORT, 'p', myport);
341 328
342 printf (UT_EXTRA_OPTS); 329 printf(" %s\n", "-4, --use-ipv4");
330 printf(" %s\n", _("Force dig to only use IPv4 query transport"));
331 printf(" %s\n", "-6, --use-ipv6");
332 printf(" %s\n", _("Force dig to only use IPv6 query transport"));
333 printf(" %s\n", "-l, --query_address=STRING");
334 printf(" %s\n", _("Machine name to lookup"));
335 printf(" %s\n", "-T, --record_type=STRING");
336 printf(" %s\n", _("Record type to lookup (default: A)"));
337 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"));
339 printf(" %s\n", _("was in -l"));
340 printf(" %s\n", "-A, --dig-arguments=STRING");
341 printf(" %s\n", _("Pass STRING as argument(s) to dig"));
342 printf(UT_WARN_CRIT);
343 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
344 printf(UT_VERBOSE);
343 345
344 printf (UT_HOST_PORT, 'p', myport); 346 printf("\n");
347 printf("%s\n", _("Examples:"));
348 printf(" %s\n", "check_dig -H DNSSERVER -l www.example.com -A \"+tcp\"");
349 printf(" %s\n", "This will send a tcp query to DNSSERVER for www.example.com");
345 350
346 printf (" %s\n","-4, --use-ipv4"); 351 printf(UT_SUPPORT);
347 printf (" %s\n",_("Force dig to only use IPv4 query transport"));
348 printf (" %s\n","-6, --use-ipv6");
349 printf (" %s\n",_("Force dig to only use IPv6 query transport"));
350 printf (" %s\n","-l, --query_address=STRING");
351 printf (" %s\n",_("Machine name to lookup"));
352 printf (" %s\n","-T, --record_type=STRING");
353 printf (" %s\n",_("Record type to lookup (default: A)"));
354 printf (" %s\n","-a, --expected_address=STRING");
355 printf (" %s\n",_("An address expected to be in the answer section. If not set, uses whatever"));
356 printf (" %s\n",_("was in -l"));
357 printf (" %s\n","-A, --dig-arguments=STRING");
358 printf (" %s\n",_("Pass STRING as argument(s) to dig"));
359 printf (UT_WARN_CRIT);
360 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
361 printf (UT_VERBOSE);
362
363 printf ("\n");
364 printf ("%s\n", _("Examples:"));
365 printf (" %s\n", "check_dig -H DNSSERVER -l www.example.com -A \"+tcp\"");
366 printf (" %s\n", "This will send a tcp query to DNSSERVER for www.example.com");
367
368 printf (UT_SUPPORT);
369} 352}
370 353
371 354void print_usage(void) {
372 355 printf("%s\n", _("Usage:"));
373void 356 printf("%s -l <query_address> [-H <host>] [-p <server port>]\n", progname);
374print_usage (void) 357 printf(" [-T <query type>] [-w <warning interval>] [-c <critical interval>]\n");
375{ 358 printf(" [-t <timeout>] [-a <expected answer address>] [-v]\n");
376 printf ("%s\n", _("Usage:"));
377 printf ("%s -l <query_address> [-H <host>] [-p <server port>]\n", progname);
378 printf (" [-T <query type>] [-w <warning interval>] [-c <critical interval>]\n");
379 printf (" [-t <timeout>] [-a <expected answer address>] [-v]\n");
380} 359}
diff --git a/plugins/check_dig.d/config.h b/plugins/check_dig.d/config.h
new file mode 100644
index 00000000..a570b633
--- /dev/null
+++ b/plugins/check_dig.d/config.h
@@ -0,0 +1,40 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6#define UNDEFINED 0
7#define DEFAULT_PORT 53
8#define DEFAULT_TRIES 2
9
10typedef struct {
11 char *query_address;
12 char *record_type;
13 char *expected_address;
14 char *dns_server;
15 char *query_transport;
16 int server_port;
17 char *dig_args;
18 int number_tries;
19
20 double warning_interval;
21 double critical_interval;
22} check_dig_config;
23
24check_dig_config check_dig_config_init() {
25 check_dig_config tmp = {
26 .query_address = NULL,
27 .record_type = "A",
28 .expected_address = NULL,
29 .dns_server = NULL,
30 .query_transport = "",
31 .server_port = DEFAULT_PORT,
32 .dig_args = "",
33 .number_tries = DEFAULT_TRIES,
34
35 .warning_interval = UNDEFINED,
36 .critical_interval = UNDEFINED,
37
38 };
39 return tmp;
40}
diff --git a/plugins/check_disk.c b/plugins/check_disk.c
index 24de2d45..515ddff0 100644
--- a/plugins/check_disk.c
+++ b/plugins/check_disk.c
@@ -1,1161 +1,1220 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_disk plugin 3 * Monitoring check_disk plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2008 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_disk plugin 10 * This file contains the check_disk plugin
11* 11 *
12* 12 *
13* This program is free software: you can redistribute it and/or modify 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 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 15 * the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16 * (at your option) any later version.
17* 17 *
18* This program is distributed in the hope that it will be useful, 18 * This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21 * GNU General Public License for more details.
22* 22 *
23* You should have received a copy of the GNU General Public License 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/>. 24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25 *
26* 26 *
27*****************************************************************************/ 27 *****************************************************************************/
28 28
29const char *progname = "check_disk"; 29const char *progname = "check_disk";
30const char *program_name = "check_disk"; /* Required for coreutils libs */ 30const char *program_name = "check_disk"; /* Required for coreutils libs */
31const char *copyright = "1999-2008"; 31const char *copyright = "1999-2024";
32const char *email = "devel@monitoring-plugins.org"; 32const char *email = "devel@monitoring-plugins.org";
33 33
34 34#include "states.h"
35#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
36#ifdef HAVE_SYS_STAT_H 41#ifdef HAVE_SYS_STAT_H
37# include <sys/stat.h> 42# include <sys/stat.h>
38#endif 43#endif
44
39#if HAVE_INTTYPES_H 45#if HAVE_INTTYPES_H
40# include <inttypes.h> 46# include <inttypes.h>
41#endif 47#endif
48
42#include <assert.h> 49#include <assert.h>
43#include "popen.h"
44#include "utils.h"
45#include "utils_disk.h"
46#include <stdarg.h> 50#include <stdarg.h>
47#include "fsusage.h" 51#include <stdint.h>
48#include "mountlist.h"
49#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
50#if HAVE_LIMITS_H 59#if HAVE_LIMITS_H
51# include <limits.h> 60# include <limits.h>
52#endif 61#endif
62
53#include "regex.h" 63#include "regex.h"
54 64
55#ifdef __CYGWIN__ 65#ifdef __CYGWIN__
56# include <windows.h> 66# include <windows.h>
57# undef ERROR 67# undef ERROR
58# define ERROR -1 68# define ERROR -1
59#endif 69#endif
60 70
61/* If nonzero, show even filesystems with zero size or 71#ifdef _AIX
62 uninteresting types. */ 72# pragma alloca
63static int show_all_fs = 1; 73#endif
64
65/* If nonzero, show only local filesystems. */
66static int show_local_fs = 0;
67
68/* If nonzero, show only local filesystems but call stat() on remote ones. */
69static int stat_remote_fs = 0;
70
71/* If positive, the units to use when printing sizes;
72 if negative, the human-readable base. */
73/* static int output_block_size; */
74
75/* If nonzero, invoke the `sync' system call before getting any usage data.
76 Using this option can make df very slow, especially with many or very
77 busy disks. Note that this may make a difference on some systems --
78 SunOs4.1.3, for one. It is *not* necessary on Linux. */
79/* static int require_sync = 0; */
80
81/* Linked list of filesystem types to display.
82 If `fs_select_list' is NULL, list all types.
83 This table is generated dynamically from command-line options,
84 rather than hardcoding into the program what it thinks are the
85 valid filesystem types; let the user specify any filesystem type
86 they want to, and if there are any filesystems of that type, they
87 will be shown.
88
89 Some filesystem types:
90 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
91
92/* static struct parameter_list *fs_select_list; */
93
94/* Linked list of filesystem types to omit.
95 If the list is empty, don't exclude any types. */
96static struct regex_list *fs_exclude_list = NULL;
97 74
98/* Linked list of filesystem types to check. 75typedef struct {
99 If the list is empty, include all types. */ 76 int errorcode;
100static struct regex_list *fs_include_list; 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, char *crit_freespace_units,
82 char *warn_freespace_percent, char *crit_freespace_percent, char *warn_freeinodes_percent,
83 char *crit_freeinodes_percent);
84static double calculate_percent(uintmax_t /*value*/, uintmax_t /*total*/);
85static bool stat_path(parameter_list_elem * /*parameters*/, bool /*ignore_missing*/);
86
87/*
88 * Puts the values from a struct fs_usage into a parameter_list with an additional flag to control how reserved
89 * and inodes should be judged (ignored or not)
90 */
91static parameter_list_elem get_path_stats(parameter_list_elem parameters, struct fs_usage fsp, bool freespace_ignore_reserved);
92static mp_subcheck evaluate_filesystem(measurement_unit measurement_unit, bool display_inodes_perfdata, byte_unit unit);
93
94void print_usage(void);
95static void print_help(void);
96
97static int verbose = 0;
98
99// This would not be necessary in C23!!
100const byte_unit Bytes_Factor = 1;
101const byte_unit KibiBytes_factor = 1024;
102const byte_unit MebiBytes_factor = 1048576;
103const byte_unit GibiBytes_factor = 1073741824;
104const byte_unit TebiBytes_factor = 1099511627776;
105const byte_unit PebiBytes_factor = 1125899906842624;
106const byte_unit ExbiBytes_factor = 1152921504606846976;
107const byte_unit KiloBytes_factor = 1000;
108const byte_unit MegaBytes_factor = 1000000;
109const byte_unit GigaBytes_factor = 1000000000;
110const byte_unit TeraBytes_factor = 1000000000000;
111const byte_unit PetaBytes_factor = 1000000000000000;
112const byte_unit ExaBytes_factor = 1000000000000000000;
113
114
115int main(int argc, char **argv) {
116 setlocale(LC_ALL, "");
117 bindtextdomain(PACKAGE, LOCALEDIR);
118 textdomain(PACKAGE);
101 119
102static struct name_list *dp_exclude_list; 120#ifdef __CYGWIN__
121 char mountdir[32];
122#endif
103 123
104static struct parameter_list *path_select_list = NULL; 124 // Parse extra opts if any
125 argv = np_extra_opts(&argc, argv, progname);
126
127 check_disk_config_wrapper tmp_config = process_arguments(argc, argv);
128 if (tmp_config.errorcode == ERROR) {
129 usage4(_("Could not parse arguments"));
130 }
131
132 check_disk_config config = tmp_config.config;
133
134 if (config.output_format_is_set) {
135 mp_set_format(config.output_format);
136 }
137
138 if (config.erronly) {
139 mp_set_level_of_detail(MP_DETAIL_NON_OK_ONLY);
140 }
141
142 if (!config.path_ignored) {
143 mp_int_fs_list_set_best_match(config.path_select_list, config.mount_list, config.exact_match);
144 }
145
146 // Error if no match found for specified paths
147 for (parameter_list_elem *elem = config.path_select_list.first; elem;) {
148 if (!elem->best_match && config.ignore_missing) {
149 /* Delete the path from the list so that it is not stat-checked later in the code. */
150 elem = mp_int_fs_list_del(&config.path_select_list, elem);
151 continue;
152 }
153 if (!elem->best_match) {
154 /* Without --ignore-missing option, exit with Critical state. */
155 die(STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), elem->name);
156 }
157
158 elem = mp_int_fs_list_get_next(elem);
159 }
160
161 mp_check overall = mp_check_init();
162 if (config.path_select_list.length == 0) {
163 mp_subcheck none_sc = mp_subcheck_init();
164 xasprintf(&none_sc.output, "No filesystems were found for the provided parameters");
165 if (config.ignore_missing) {
166 none_sc = mp_set_subcheck_state(none_sc, STATE_OK);
167 } else {
168 none_sc = mp_set_subcheck_state(none_sc, STATE_UNKNOWN);
169 if (verbose >= 2) {
170 printf("None of the provided paths were found\n");
171 }
172 }
173 mp_add_subcheck_to_check(&overall, none_sc);
174 mp_exit(overall);
175 }
105 176
106/* Linked list of mounted filesystems. */ 177 // Filter list first
107static struct mount_entry *mount_list; 178 for (parameter_list_elem *path = config.path_select_list.first; path;) {
179 if (!path->best_match) {
180 path = mp_int_fs_list_del(&config.path_select_list, path);
181 continue;
182 }
108 183
109/* For long options that have no equivalent short option, use a 184 struct mount_entry *mount_entry = path->best_match;
110 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
111enum
112{
113 SYNC_OPTION = CHAR_MAX + 1,
114 NO_SYNC_OPTION,
115 BLOCK_SIZE_OPTION
116};
117 185
118#ifdef _AIX 186#ifdef __CYGWIN__
119#pragma alloca 187 if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11) {
188 path = mp_int_fs_list_del(&config.path_select_list, path);
189 continue;
190 }
191
192 char *mountdir = NULL;
193 snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10);
194 if (GetDriveType(mountdir) != DRIVE_FIXED) {
195 mount_entry->me_remote = 1;
196 }
120#endif 197#endif
121 198
122int process_arguments (int, char **); 199 /* Remove filesystems already seen */
123void print_path (const char *mypath); 200 if (np_seen_name(config.seen, mount_entry->me_mountdir)) {
124void set_all_thresholds (struct parameter_list *path); 201 path = mp_int_fs_list_del(&config.path_select_list, path);
125int validate_arguments (uintmax_t, uintmax_t, double, double, double, double, char *); 202 continue;
126void print_help (void); 203 }
127void print_usage (void); 204
128double calculate_percent(uintmax_t, uintmax_t); 205 if (path->group == NULL) {
129bool stat_path (struct parameter_list *p); 206 if (config.fs_exclude_list && np_find_regmatch(config.fs_exclude_list, mount_entry->me_type)) {
130void get_stats (struct parameter_list *p, struct fs_usage *fsp); 207 // Skip excluded fs's
131void get_path_stats (struct parameter_list *p, struct fs_usage *fsp); 208 path = mp_int_fs_list_del(&config.path_select_list, path);
132 209 continue;
133char *exclude_device; 210 }
134char *units;
135uintmax_t mult = 1024 * 1024;
136int verbose = 0;
137bool erronly = false;
138bool display_mntp = false;
139bool exact_match = false;
140bool ignore_missing = false;
141bool freespace_ignore_reserved = false;
142bool display_inodes_perfdata = false;
143char *warn_freespace_units = NULL;
144char *crit_freespace_units = NULL;
145char *warn_freespace_percent = NULL;
146char *crit_freespace_percent = NULL;
147char *warn_usedspace_units = NULL;
148char *crit_usedspace_units = NULL;
149char *warn_usedspace_percent = NULL;
150char *crit_usedspace_percent = NULL;
151char *warn_usedinodes_percent = NULL;
152char *crit_usedinodes_percent = NULL;
153char *warn_freeinodes_percent = NULL;
154char *crit_freeinodes_percent = NULL;
155bool path_selected = false;
156bool path_ignored = false;
157char *group = NULL;
158struct stat *stat_buf;
159struct name_list *seen = NULL;
160
161
162int
163main (int argc, char **argv)
164{
165 int result = STATE_UNKNOWN;
166 int disk_result = STATE_UNKNOWN;
167 char *output;
168 char *ignored;
169 char *details;
170 char *perf;
171 char *perf_ilabel;
172 char *preamble = " - free space:";
173 char *ignored_preamble = " - ignored paths:";
174 char *flag_header;
175 int temp_result;
176
177 struct mount_entry *me;
178 struct fs_usage fsp;
179 struct parameter_list *temp_list, *path;
180 211
181#ifdef __CYGWIN__ 212 if (config.device_path_exclude_list && (np_find_name(config.device_path_exclude_list, mount_entry->me_devname) ||
182 char mountdir[32]; 213 np_find_name(config.device_path_exclude_list, mount_entry->me_mountdir))) {
183#endif 214 // Skip excluded device or mount paths
215 path = mp_int_fs_list_del(&config.path_select_list, path);
216 continue;
217 }
184 218
185 output = strdup (""); 219 if (config.fs_include_list && !np_find_regmatch(config.fs_include_list, mount_entry->me_type)) {
186 ignored = strdup (""); 220 // Skip not included fstypes
187 details = strdup (""); 221 path = mp_int_fs_list_del(&config.path_select_list, path);
188 perf = strdup (""); 222 continue;
189 perf_ilabel = strdup (""); 223 }
190 stat_buf = malloc(sizeof *stat_buf);
191
192 setlocale (LC_ALL, "");
193 bindtextdomain (PACKAGE, LOCALEDIR);
194 textdomain (PACKAGE);
195
196 mount_list = read_file_system_list (0);
197
198 /* Parse extra opts if any */
199 argv = np_extra_opts (&argc, argv, progname);
200
201 if (process_arguments (argc, argv) == ERROR)
202 usage4 (_("Could not parse arguments"));
203
204 /* If a list of paths has not been selected, find entire
205 mount list and create list of paths
206 */
207 if (path_selected == false && path_ignored == false) {
208 for (me = mount_list; me; me = me->me_next) {
209 if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) {
210 path = np_add_parameter(&path_select_list, me->me_mountdir);
211 }
212 path->best_match = me;
213 path->group = group;
214 set_all_thresholds(path);
215 }
216 }
217
218 if (path_ignored == false) {
219 np_set_best_match(path_select_list, mount_list, exact_match);
220 }
221
222 /* Error if no match found for specified paths */
223 temp_list = path_select_list;
224
225 while (path_select_list) {
226 if (! path_select_list->best_match && ignore_missing == true) {
227 /* If the first element will be deleted, the temp_list must be updated with the new start address as well */
228 if (path_select_list == temp_list) {
229 temp_list = path_select_list->name_next;
230 }
231 /* Add path argument to list of ignored paths to inform about missing paths being ignored and not alerted */
232 xasprintf (&ignored, "%s %s;", ignored, path_select_list->name);
233 /* Delete the path from the list so that it is not stat-checked later in the code. */
234 path_select_list = np_del_parameter(path_select_list, path_select_list->name_prev);
235 } else if (! path_select_list->best_match) {
236 /* Without --ignore-missing option, exit with Critical state. */
237 die (STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), path_select_list->name);
238 } else {
239 /* Continue jumping through the list */
240 path_select_list = path_select_list->name_next;
241 }
242 }
243
244 path_select_list = temp_list;
245
246 if (! path_select_list && ignore_missing == true) {
247 result = STATE_OK;
248 if (verbose >= 2) {
249 printf ("None of the provided paths were found\n");
250 }
251 }
252
253 /* Process for every path in list */
254 for (path = path_select_list; path; path=path->name_next) {
255 if (verbose >= 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL)
256 printf("Thresholds(pct) for %s warn: %f crit %f\n",
257 path->name,
258 path->freespace_percent->warning->end,
259 path->freespace_percent->critical->end);
260
261 if (verbose >= 3 && path->group != NULL)
262 printf("Group of %s: %s\n",path->name,path->group);
263
264 /* reset disk result */
265 disk_result = STATE_UNKNOWN;
266
267 me = path->best_match;
268
269 if (!me) {
270 continue;
271 }
272 224
273#ifdef __CYGWIN__ 225 /* Skip remote filesystems if we're not interested in them */
274 if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11) 226 if (mount_entry->me_remote && config.show_local_fs) {
275 continue; 227 if (config.stat_remote_fs) {
276 snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10); 228 // TODO Stat here
277 if (GetDriveType(mountdir) != DRIVE_FIXED) 229 if (!stat_path(path, config.ignore_missing) && config.ignore_missing) {
278 me->me_remote = 1; 230 }
279#endif 231 }
280 /* Filters */ 232 continue;
281 233 }
282 /* Remove filesystems already seen */
283 if (np_seen_name(seen, me->me_mountdir)) {
284 continue;
285 }
286 np_add_name(&seen, me->me_mountdir);
287
288 if (path->group == NULL) {
289 /* Skip remote filesystems if we're not interested in them */
290 if (me->me_remote && show_local_fs) {
291 if (stat_remote_fs) {
292 if (!stat_path(path) && ignore_missing == true) {
293 result = STATE_OK;
294 xasprintf (&ignored, "%s %s;", ignored, path->name);
295 }
296 }
297 continue;
298 /* Skip pseudo fs's if we haven't asked for all fs's */
299 } else if (me->me_dummy && !show_all_fs) {
300 continue;
301 /* Skip excluded fstypes */
302 } else if (fs_exclude_list && np_find_regmatch (fs_exclude_list, me->me_type)) {
303 continue;
304 /* Skip excluded fs's */
305 } else if (dp_exclude_list &&
306 (np_find_name (dp_exclude_list, me->me_devname) ||
307 np_find_name (dp_exclude_list, me->me_mountdir))) {
308 continue;
309 /* Skip not included fstypes */
310 } else if (fs_include_list && !np_find_regmatch(fs_include_list, me->me_type)) {
311 continue;
312 }
313 }
314
315 if (!stat_path(path)) {
316 if (ignore_missing == true) {
317 result = STATE_OK;
318 xasprintf (&ignored, "%s %s;", ignored, path->name);
319 }
320 continue;
321 }
322 get_fs_usage (me->me_mountdir, me->me_devname, &fsp);
323
324 if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) {
325 get_stats (path, &fsp);
326
327 if (verbose >= 3) {
328 printf ("For %s, used_pct=%f free_pct=%f used_units=%lu free_units=%lu total_units=%lu used_inodes_pct=%f free_inodes_pct=%f fsp.fsu_blocksize=%lu mult=%lu\n",
329 me->me_mountdir,
330 path->dused_pct,
331 path->dfree_pct,
332 path->dused_units,
333 path->dfree_units,
334 path->dtotal_units,
335 path->dused_inodes_percent,
336 path->dfree_inodes_percent,
337 fsp.fsu_blocksize,
338 mult);
339 }
340
341 /* Threshold comparisons */
342
343 temp_result = get_status(path->dfree_units, path->freespace_units);
344 if (verbose >=3) printf("Freespace_units result=%d\n", temp_result);
345 disk_result = max_state( disk_result, temp_result );
346
347 temp_result = get_status(path->dfree_pct, path->freespace_percent);
348 if (verbose >=3) printf("Freespace%% result=%d\n", temp_result);
349 disk_result = max_state( disk_result, temp_result );
350
351 temp_result = get_status(path->dused_units, path->usedspace_units);
352 if (verbose >=3) printf("Usedspace_units result=%d\n", temp_result);
353 disk_result = max_state( disk_result, temp_result );
354
355 temp_result = get_status(path->dused_pct, path->usedspace_percent);
356 if (verbose >=3) printf("Usedspace_percent result=%d\n", temp_result);
357 disk_result = max_state( disk_result, temp_result );
358
359 temp_result = get_status(path->dused_inodes_percent, path->usedinodes_percent);
360 if (verbose >=3) printf("Usedinodes_percent result=%d\n", temp_result);
361 disk_result = max_state( disk_result, temp_result );
362
363 temp_result = get_status(path->dfree_inodes_percent, path->freeinodes_percent);
364 if (verbose >=3) printf("Freeinodes_percent result=%d\n", temp_result);
365 disk_result = max_state( disk_result, temp_result );
366
367 result = max_state(result, disk_result);
368
369 /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
370 Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
371 data. Assumption that start=0. Roll on new syntax...
372 */
373
374 /* *_high_tide must be reinitialized at each run */
375 uint64_t warning_high_tide = UINT64_MAX;
376
377 if (path->freespace_units->warning != NULL) {
378 warning_high_tide = (path->dtotal_units - path->freespace_units->warning->end) * mult;
379 }
380 if (path->freespace_percent->warning != NULL) {
381 warning_high_tide = min( warning_high_tide, (uint64_t)((1.0 - path->freespace_percent->warning->end/100) * (path->dtotal_units * mult)) );
382 }
383
384 uint64_t critical_high_tide = UINT64_MAX;
385
386 if (path->freespace_units->critical != NULL) {
387 critical_high_tide = (path->dtotal_units - path->freespace_units->critical->end) * mult;
388 }
389 if (path->freespace_percent->critical != NULL) {
390 critical_high_tide = min( critical_high_tide, (uint64_t)((1.0 - path->freespace_percent->critical->end/100) * (path->dtotal_units * mult)) );
391 }
392
393 /* Nb: *_high_tide are unset when == UINT64_MAX */
394 xasprintf (&perf, "%s %s", perf,
395 perfdata_uint64 (
396 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
397 path->dused_units * mult, "B",
398 (warning_high_tide == UINT64_MAX ? false : true), warning_high_tide,
399 (critical_high_tide == UINT64_MAX ? false : true), critical_high_tide,
400 true, 0,
401 true, path->dtotal_units * mult));
402
403 if (display_inodes_perfdata) {
404 /* *_high_tide must be reinitialized at each run */
405 warning_high_tide = UINT64_MAX;
406 critical_high_tide = UINT64_MAX;
407
408 if (path->freeinodes_percent->warning != NULL) {
409 warning_high_tide = (uint64_t) fabs( min( (double) warning_high_tide, (double) (1.0 - path->freeinodes_percent->warning->end/100)*path->inodes_total ));
410 }
411 if (path->freeinodes_percent->critical != NULL) {
412 critical_high_tide = (uint64_t) fabs( min( (double) critical_high_tide, (double) (1.0 - path->freeinodes_percent->critical->end/100)*path->inodes_total ));
413 }
414
415 xasprintf (&perf_ilabel, "%s (inodes)", (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir);
416 /* Nb: *_high_tide are unset when == UINT64_MAX */
417 xasprintf (&perf, "%s %s", perf,
418 perfdata_uint64 (perf_ilabel,
419 path->inodes_used, "",
420 (warning_high_tide != UINT64_MAX ? true : false), warning_high_tide,
421 (critical_high_tide != UINT64_MAX ? true : false), critical_high_tide,
422 true, 0,
423 true, path->inodes_total));
424 }
425
426 if (disk_result==STATE_OK && erronly && !verbose)
427 continue;
428
429 if(disk_result && verbose >= 1) {
430 xasprintf(&flag_header, " %s [", state_text (disk_result));
431 } else {
432 xasprintf(&flag_header, "");
433 }
434 xasprintf (&output, "%s%s %s %llu%s (%.1f%%",
435 output, flag_header,
436 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
437 path->dfree_units,
438 units,
439 path->dfree_pct);
440 if (path->dused_inodes_percent < 0) {
441 xasprintf(&output, "%s inode=-)%s;", output, (disk_result ? "]" : ""));
442 } else {
443 xasprintf(&output, "%s inode=%.0f%%)%s;", output, path->dfree_inodes_percent, ((disk_result && verbose >= 1) ? "]" : ""));
444 }
445 free(flag_header);
446 }
447 }
448
449 if (verbose >= 2)
450 xasprintf (&output, "%s%s", output, details);
451
452 if (strcmp(output, "") == 0 && ! erronly) {
453 preamble = "";
454 xasprintf (&output, " - No disks were found for provided parameters");
455 }
456
457 printf ("DISK %s%s%s%s%s|%s\n", state_text (result), ((erronly && result==STATE_OK)) ? "" : preamble, output, (strcmp(ignored, "") == 0) ? "" : ignored_preamble, ignored, perf);
458 return result;
459}
460 234
235 // TODO why stat here? remove unstatable fs?
236 if (!stat_path(path, config.ignore_missing)) {
237 // if (config.ignore_missing) {
238 // xasprintf(&ignored, "%s %s;", ignored, path->name);
239 // }
240 // not accessible, remove from list
241 path = mp_int_fs_list_del(&config.path_select_list, path);
242 continue;
243 }
244 }
245
246 path = mp_int_fs_list_get_next(path);
247 }
248
249 // now get the actual measurements
250 for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem;) {
251 // Get actual metrics here
252 struct mount_entry *mount_entry = filesystem->best_match;
253 struct fs_usage fsp = {0};
254 get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp);
255
256 if (fsp.fsu_blocks != 0 && strcmp("none", mount_entry->me_mountdir) != 0) {
257 *filesystem = get_path_stats(*filesystem, fsp, config.freespace_ignore_reserved);
258
259 if (verbose >= 3) {
260 printf("For %s, used_units=%lu free_units=%lu total_units=%lu "
261 "fsp.fsu_blocksize=%lu\n",
262 mount_entry->me_mountdir, filesystem->used_bytes, filesystem->free_bytes, filesystem->total_bytes,
263 fsp.fsu_blocksize);
264 }
265 } else {
266 // failed to retrieve file system data or not mounted?
267 filesystem = mp_int_fs_list_del(&config.path_select_list, filesystem);
268 continue;
269 }
270 filesystem = mp_int_fs_list_get_next(filesystem);
271 }
272
273 if (verbose > 2) {
274 for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem;
275 filesystem = mp_int_fs_list_get_next(filesystem)) {
276 assert(filesystem->best_match != NULL);
277 if (filesystem->best_match == NULL) {
278 printf("Filesystem path %s has no mount_entry!\n", filesystem->name);
279 } else {
280 // printf("Filesystem path %s has a mount_entry!\n", filesystem->name);
281 }
282 }
283 }
284
285 measurement_unit_list *measurements = NULL;
286 measurement_unit_list *current = NULL;
287 // create measuring units, because of groups
288 for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem; filesystem = mp_int_fs_list_get_next(filesystem)) {
289 assert(filesystem->best_match != NULL);
290
291 if (filesystem->group == NULL) {
292 // create a measurement unit for the fs
293 measurement_unit unit = create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
294 if (measurements == NULL) {
295 measurements = current = add_measurement_list(NULL, unit);
296 } else {
297 current = add_measurement_list(measurements, unit);
298 }
299 } else {
300 // Grouped elements are consecutive
301 if (measurements == NULL) {
302 // first entry
303 measurement_unit unit = create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
304 unit.name = strdup(filesystem->group);
305 measurements = current = add_measurement_list(NULL, unit);
306 } else {
307 // if this is the first element of a group, the name of the previous entry is different
308 if (strcmp(filesystem->group, current->unit.name) != 0) {
309 // so, this must be the first element of a group
310 measurement_unit unit = create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
311 unit.name = filesystem->group;
312 current = add_measurement_list(measurements, unit);
313
314 } else {
315 // NOT the first entry of a group, add info to the other one
316 current->unit = add_filesystem_to_measurement_unit(current->unit, *filesystem);
317 }
318 }
319 }
320 }
321
322 /* Process for every path in list */
323 if (measurements != NULL) {
324 for (measurement_unit_list *unit = measurements; unit; unit = unit->next) {
325 mp_subcheck unit_sc = evaluate_filesystem(unit->unit, config.display_inodes_perfdata, config.display_unit);
326 mp_add_subcheck_to_check(&overall, unit_sc);
327 }
328 } else {
329 // Apparently no machting fs found
330 mp_subcheck none_sc = mp_subcheck_init();
331 xasprintf(&none_sc.output, "No filesystems were found for the provided parameters");
332
333 if (config.ignore_missing) {
334 none_sc = mp_set_subcheck_state(none_sc, STATE_OK);
335 } else {
336 none_sc = mp_set_subcheck_state(none_sc, STATE_UNKNOWN);
337 }
338 mp_add_subcheck_to_check(&overall, none_sc);
339 }
340
341 mp_exit(overall);
342}
461 343
462double calculate_percent(uintmax_t value, uintmax_t total) { 344double calculate_percent(uintmax_t value, uintmax_t total) {
463 double pct = -1; 345 double pct = -1;
464 if(value <= DBL_MAX && total != 0) { 346 if (value <= DBL_MAX && total != 0) {
465 pct = (double)value / total * 100.0; 347 pct = (double)value / (double)total * 100.0;
466 } 348 }
467 return pct; 349
350 return pct;
468} 351}
469 352
470/* process command-line arguments */ 353/* process command-line arguments */
471int 354check_disk_config_wrapper process_arguments(int argc, char **argv) {
472process_arguments (int argc, char **argv) 355
473{ 356 check_disk_config_wrapper result = {
474 int c, err; 357 .errorcode = OK,
475 struct parameter_list *se; 358 .config = check_disk_config_init(),
476 struct parameter_list *temp_list = NULL, *previous = NULL; 359 };
477 struct mount_entry *me; 360
478 regex_t re; 361 if (argc < 2) {
479 int cflags = REG_NOSUB | REG_EXTENDED; 362 result.errorcode = ERROR;
480 int default_cflags = cflags; 363 return result;
481 char errbuf[MAX_INPUT_BUFFER]; 364 }
482 int fnd = 0; 365
483 366 enum {
484 int option = 0; 367 output_format_index = CHAR_MAX + 1,
485 static struct option longopts[] = { 368 display_unit_index,
486 {"timeout", required_argument, 0, 't'}, 369 };
487 {"warning", required_argument, 0, 'w'}, 370
488 {"critical", required_argument, 0, 'c'}, 371 static struct option longopts[] = {{"timeout", required_argument, 0, 't'},
489 {"iwarning", required_argument, 0, 'W'}, 372 {"warning", required_argument, 0, 'w'},
490 /* Dang, -C is taken. We might want to reshuffle this. */ 373 {"critical", required_argument, 0, 'c'},
491 {"icritical", required_argument, 0, 'K'}, 374 {"iwarning", required_argument, 0, 'W'},
492 {"kilobytes", no_argument, 0, 'k'}, 375 {"icritical", required_argument, 0, 'K'},
493 {"megabytes", no_argument, 0, 'm'}, 376 {"kilobytes", no_argument, 0, 'k'},
494 {"units", required_argument, 0, 'u'}, 377 {"megabytes", no_argument, 0, 'm'},
495 {"path", required_argument, 0, 'p'}, 378 {"units", required_argument, 0, 'u'},
496 {"partition", required_argument, 0, 'p'}, 379 {"path", required_argument, 0, 'p'},
497 {"exclude_device", required_argument, 0, 'x'}, 380 {"partition", required_argument, 0, 'p'},
498 {"exclude-type", required_argument, 0, 'X'}, 381 {"exclude_device", required_argument, 0, 'x'},
499 {"include-type", required_argument, 0, 'N'}, 382 {"exclude-type", required_argument, 0, 'X'},
500 {"group", required_argument, 0, 'g'}, 383 {"include-type", required_argument, 0, 'N'},
501 {"eregi-path", required_argument, 0, 'R'}, 384 {"group", required_argument, 0, 'g'},
502 {"eregi-partition", required_argument, 0, 'R'}, 385 {"eregi-path", required_argument, 0, 'R'},
503 {"ereg-path", required_argument, 0, 'r'}, 386 {"eregi-partition", required_argument, 0, 'R'},
504 {"ereg-partition", required_argument, 0, 'r'}, 387 {"ereg-path", required_argument, 0, 'r'},
505 {"freespace-ignore-reserved", no_argument, 0, 'f'}, 388 {"ereg-partition", required_argument, 0, 'r'},
506 {"ignore-ereg-path", required_argument, 0, 'i'}, 389 {"freespace-ignore-reserved", no_argument, 0, 'f'},
507 {"ignore-ereg-partition", required_argument, 0, 'i'}, 390 {"ignore-ereg-path", required_argument, 0, 'i'},
508 {"ignore-eregi-path", required_argument, 0, 'I'}, 391 {"ignore-ereg-partition", required_argument, 0, 'i'},
509 {"ignore-eregi-partition", required_argument, 0, 'I'}, 392 {"ignore-eregi-path", required_argument, 0, 'I'},
510 {"ignore-missing", no_argument, 0, 'n'}, 393 {"ignore-eregi-partition", required_argument, 0, 'I'},
511 {"local", no_argument, 0, 'l'}, 394 {"ignore-missing", no_argument, 0, 'n'},
512 {"stat-remote-fs", no_argument, 0, 'L'}, 395 {"local", no_argument, 0, 'l'},
513 {"iperfdata", no_argument, 0, 'P'}, 396 {"stat-remote-fs", no_argument, 0, 'L'},
514 {"mountpoint", no_argument, 0, 'M'}, 397 {"iperfdata", no_argument, 0, 'P'},
515 {"errors-only", no_argument, 0, 'e'}, 398 {"mountpoint", no_argument, 0, 'M'},
516 {"exact-match", no_argument, 0, 'E'}, 399 {"errors-only", no_argument, 0, 'e'},
517 {"all", no_argument, 0, 'A'}, 400 {"exact-match", no_argument, 0, 'E'},
518 {"verbose", no_argument, 0, 'v'}, 401 {"all", no_argument, 0, 'A'},
519 {"quiet", no_argument, 0, 'q'}, 402 {"verbose", no_argument, 0, 'v'},
520 {"clear", no_argument, 0, 'C'}, 403 {"quiet", no_argument, 0, 'q'},
521 {"version", no_argument, 0, 'V'}, 404 {"clear", no_argument, 0, 'C'},
522 {"help", no_argument, 0, 'h'}, 405 {"version", no_argument, 0, 'V'},
523 {0, 0, 0, 0} 406 {"help", no_argument, 0, 'h'},
524 }; 407 {"output-format", required_argument, 0, output_format_index},
525 408 {"display-unit", required_argument, 0, display_unit_index},
526 if (argc < 2) 409 {0, 0, 0, 0}};
527 return ERROR; 410
528 411 for (int index = 1; index < argc; index++) {
529 np_add_regex(&fs_exclude_list, "iso9660", REG_EXTENDED); 412 if (strcmp("-to", argv[index]) == 0) {
530 413 strcpy(argv[index], "-t");
531 for (c = 1; c < argc; c++) 414 }
532 if (strcmp ("-to", argv[c]) == 0) 415 }
533 strcpy (argv[c], "-t"); 416
534 417 int cflags = REG_NOSUB | REG_EXTENDED;
535 while (1) { 418 int default_cflags = cflags;
536 c = getopt_long (argc, argv, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLPg:R:r:i:I:MEAn", longopts, &option); 419 char *warn_freespace_units = NULL;
537 420 char *crit_freespace_units = NULL;
538 if (c == -1 || c == EOF) 421 char *warn_freespace_percent = NULL;
539 break; 422 char *crit_freespace_percent = NULL;
540 423 char *warn_freeinodes_percent = NULL;
541 switch (c) { 424 char *crit_freeinodes_percent = NULL;
542 case 't': /* timeout period */ 425
543 if (is_integer (optarg)) { 426 bool path_selected = false;
544 timeout_interval = atoi (optarg); 427 char *group = NULL;
545 break; 428 byte_unit unit = MebiBytes_factor;
546 } 429
547 else { 430 result.config.mount_list = read_file_system_list(false);
548 usage2 (_("Timeout interval must be a positive integer"), optarg); 431
549 } 432 np_add_regex(&result.config.fs_exclude_list, "iso9660", REG_EXTENDED);
550 433
551 /* See comments for 'c' */ 434 while (true) {
552 case 'w': /* warning threshold */ 435 int option = 0;
436 int option_index = getopt_long(argc, argv, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLPg:R:r:i:I:MEAn", longopts, &option);
437
438 if (option_index == -1 || option_index == EOF) {
439 break;
440 }
441
442 switch (option_index) {
443 case 't': /* timeout period */
444 if (is_integer(optarg)) {
445 timeout_interval = atoi(optarg);
446 break;
447 } else {
448 usage2(_("Timeout interval must be a positive integer"), optarg);
449 }
450
451 /* See comments for 'c' */
452 case 'w': /* warning threshold */
553 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) { 453 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) {
554 die(STATE_UNKNOWN, "Argument for --warning invalid or missing: %s\n", optarg); 454 die(STATE_UNKNOWN, "Argument for --warning invalid or missing: %s\n", optarg);
555 } 455 }
556 456
557 if (strstr(optarg, "%")) { 457 if (strstr(optarg, "%")) {
558 if (*optarg == '@') { 458 if (*optarg == '@') {
559 warn_freespace_percent = optarg; 459 warn_freespace_percent = optarg;
560 } else { 460 } else {
561 xasprintf(&warn_freespace_percent, "@%s", optarg); 461 xasprintf(&warn_freespace_percent, "@%s", optarg);
562 } 462 }
563 } else { 463 } else {
564 if (*optarg == '@') { 464 if (*optarg == '@') {
565 warn_freespace_units = optarg; 465 warn_freespace_units = optarg;
566 } else { 466 } else {
567 xasprintf(&warn_freespace_units, "@%s", optarg); 467 xasprintf(&warn_freespace_units, "@%s", optarg);
568 } 468 }
569 } 469 }
570 break; 470 break;
571 471
572 /* Awful mistake where the range values do not make sense. Normally, 472 /* Awful mistake where the range values do not make sense. Normally,
573 you alert if the value is within the range, but since we are using 473 * you alert if the value is within the range, but since we are using
574 freespace, we have to alert if outside the range. Thus we artificially 474 * freespace, we have to alert if outside the range. Thus we artificially
575 force @ at the beginning of the range, so that it is backwards compatible 475 * force @ at the beginning of the range, so that it is backwards compatible
576 */ 476 */
577 case 'c': /* critical threshold */ 477 case 'c': /* critical threshold */
578 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) { 478 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) {
579 die(STATE_UNKNOWN, "Argument for --critical invalid or missing: %s\n", optarg); 479 die(STATE_UNKNOWN, "Argument for --critical invalid or missing: %s\n", optarg);
580 } 480 }
581 481
582 if (strstr(optarg, "%")) { 482 if (strstr(optarg, "%")) {
583 if (*optarg == '@') { 483 if (*optarg == '@') {
584 crit_freespace_percent = optarg; 484 crit_freespace_percent = optarg;
585 } else { 485 } else {
586 xasprintf(&crit_freespace_percent, "@%s", optarg); 486 xasprintf(&crit_freespace_percent, "@%s", optarg);
587 } 487 }
588 } else { 488 } else {
589 if (*optarg == '@') { 489 if (*optarg == '@') {
590 crit_freespace_units = optarg; 490 crit_freespace_units = optarg;
591 } else { 491 } else {
592 xasprintf(&crit_freespace_units, "@%s", optarg); 492 xasprintf(&crit_freespace_units, "@%s", optarg);
593 } 493 }
594 } 494 }
595 break; 495 break;
596
597 case 'W': /* warning inode threshold */
598 if (*optarg == '@') {
599 warn_freeinodes_percent = optarg;
600 } else {
601 xasprintf(&warn_freeinodes_percent, "@%s", optarg);
602 }
603 break;
604 case 'K': /* critical inode threshold */
605 if (*optarg == '@') {
606 crit_freeinodes_percent = optarg;
607 } else {
608 xasprintf(&crit_freeinodes_percent, "@%s", optarg);
609 }
610 break;
611 case 'u':
612 if (units)
613 free(units);
614 if (! strcasecmp (optarg, "bytes")) {
615 mult = (uintmax_t)1;
616 units = strdup ("B");
617 } else if (!strcmp(optarg, "KiB")) {
618 mult = (uintmax_t)1024;
619 units = strdup ("KiB");
620 } else if (! strcmp (optarg, "kB")) {
621 mult = (uintmax_t)1000;
622 units = strdup ("kB");
623 } else if (!strcmp(optarg, "MiB")) {
624 mult = (uintmax_t)1024 * 1024;
625 units = strdup ("MiB");
626 } else if (! strcmp (optarg, "MB")) {
627 mult = (uintmax_t)1000 * 1000;
628 units = strdup ("MB");
629 } else if (!strcmp(optarg, "GiB")) {
630 mult = (uintmax_t)1024 * 1024 * 1024;
631 units = strdup ("GiB");
632 } else if (! strcmp (optarg, "GB")){
633 mult = (uintmax_t)1000 * 1000 * 1000;
634 units = strdup ("GB");
635 } else if (!strcmp(optarg, "TiB")) {
636 mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
637 units = strdup ("TiB");
638 } else if (! strcmp (optarg, "TB")) {
639 mult = (uintmax_t)1000 * 1000 * 1000 * 1000;
640 units = strdup ("TB");
641 } else if (!strcmp(optarg, "PiB")) {
642 mult = (uintmax_t)1024 * 1024 * 1024 * 1024 * 1024;
643 units = strdup ("PiB");
644 } else if (! strcmp (optarg, "PB")){
645 mult = (uintmax_t)1000 * 1000 * 1000 * 1000 * 1000;
646 units = strdup ("PB");
647 } else {
648 die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
649 }
650 if (units == NULL)
651 die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
652 break;
653 case 'k': /* display mountpoint */
654 mult = 1024;
655 if (units)
656 free(units);
657 units = strdup ("kiB");
658 break;
659 case 'm': /* display mountpoint */
660 mult = 1024 * 1024;
661 if (units)
662 free(units);
663 units = strdup ("MiB");
664 break;
665 case 'L':
666 stat_remote_fs = 1;
667 /* fallthrough */
668 case 'l':
669 show_local_fs = 1;
670 break;
671 case 'P':
672 display_inodes_perfdata = 1;
673 break;
674 case 'p': /* select path */
675 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
676 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
677 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
678 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
679 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
680 }
681
682 /* add parameter if not found. overwrite thresholds if path has already been added */
683 if (! (se = np_find_parameter(path_select_list, optarg))) {
684 se = np_add_parameter(&path_select_list, optarg);
685
686 if (stat(optarg, &stat_buf[0]) && ignore_missing == true) {
687 path_ignored = true;
688 break;
689 }
690 }
691 se->group = group;
692 set_all_thresholds(se);
693
694 /* With autofs, it is required to stat() the path before re-populating the mount_list */
695 if (!stat_path(se)) {
696 break;
697 }
698 /* NB: We can't free the old mount_list "just like that": both list pointers and struct
699 * pointers are copied around. One of the reason it wasn't done yet is that other parts
700 * of check_disk need the same kind of cleanup so it'd better be done as a whole */
701 mount_list = read_file_system_list (0);
702 np_set_best_match(se, mount_list, exact_match);
703
704 path_selected = true;
705 break;
706 case 'x': /* exclude path or partition */
707 np_add_name(&dp_exclude_list, optarg);
708 break;
709 case 'X': /* exclude file system type */
710 err = np_add_regex(&fs_exclude_list, optarg, REG_EXTENDED);
711 if (err != 0) {
712 regerror (err, &fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
713 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
714 }
715 break;
716 case 'N': /* include file system type */
717 err = np_add_regex(&fs_include_list, optarg, REG_EXTENDED);
718 if (err != 0) {
719 regerror (err, &fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
720 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
721 }
722 break;
723 case 'v': /* verbose */
724 verbose++;
725 break;
726 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
727 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
728 erronly = true;
729 break;
730 case 'e':
731 erronly = true;
732 break;
733 case 'E':
734 if (path_selected)
735 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting paths\n"));
736 exact_match = true;
737 break;
738 case 'f':
739 freespace_ignore_reserved = true;
740 break;
741 case 'g':
742 if (path_selected)
743 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting paths\n"));
744 group = optarg;
745 break;
746 case 'I':
747 cflags |= REG_ICASE;
748 // Intentional fallthrough
749 case 'i':
750 if (!path_selected)
751 die (STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"), _("Paths need to be selected before using -i/-I. Use -A to select all paths explicitly"));
752 err = regcomp(&re, optarg, cflags);
753 if (err != 0) {
754 regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
755 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
756 }
757
758 temp_list = path_select_list;
759
760 previous = NULL;
761 while (temp_list) {
762 if (temp_list->best_match) {
763 if (np_regex_match_mount_entry(temp_list->best_match, &re)) {
764
765 if (verbose >=3)
766 printf("ignoring %s matching regex\n", temp_list->name);
767
768 temp_list = np_del_parameter(temp_list, previous);
769 /* pointer to first element needs to be updated if first item gets deleted */
770 if (previous == NULL)
771 path_select_list = temp_list;
772 } else {
773 previous = temp_list;
774 temp_list = temp_list->name_next;
775 }
776 } else {
777 previous = temp_list;
778 temp_list = temp_list->name_next;
779 }
780 }
781
782
783 cflags = default_cflags;
784 break;
785
786 case 'n':
787 ignore_missing = true;
788 break;
789 case 'A':
790 optarg = strdup(".*");
791 // Intentional fallthrough
792 case 'R':
793 cflags |= REG_ICASE;
794 // Intentional fallthrough
795 case 'r':
796 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
797 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
798 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
799 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
800 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R/-A (--ereg-path/--eregi-path/--all)\n"));
801 }
802
803 err = regcomp(&re, optarg, cflags);
804 if (err != 0) {
805 regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
806 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
807 }
808
809 for (me = mount_list; me; me = me->me_next) {
810 if (np_regex_match_mount_entry(me, &re)) {
811 fnd = true;
812 if (verbose >= 3)
813 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
814
815 /* add parameter if not found. overwrite thresholds if path has already been added */
816 if (! (se = np_find_parameter(path_select_list, me->me_mountdir))) {
817 se = np_add_parameter(&path_select_list, me->me_mountdir);
818 }
819 se->group = group;
820 set_all_thresholds(se);
821 }
822 }
823
824 if (!fnd && ignore_missing == true) {
825 path_ignored = true;
826 path_selected = true;
827 break;
828 } else if (!fnd)
829 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
830 _("Regular expression did not match any path or disk"), optarg);
831
832 fnd = false;
833 path_selected = true;
834 np_set_best_match(path_select_list, mount_list, exact_match);
835 cflags = default_cflags;
836
837 break;
838 case 'M': /* display mountpoint */
839 display_mntp = true;
840 break;
841 case 'C':
842 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
843 if (path_selected == false) {
844 struct parameter_list *path;
845 for (me = mount_list; me; me = me->me_next) {
846 if (! (path = np_find_parameter(path_select_list, me->me_mountdir)))
847 path = np_add_parameter(&path_select_list, me->me_mountdir);
848 path->best_match = me;
849 path->group = group;
850 set_all_thresholds(path);
851 }
852 }
853 warn_freespace_units = NULL;
854 crit_freespace_units = NULL;
855 warn_usedspace_units = NULL;
856 crit_usedspace_units = NULL;
857 warn_freespace_percent = NULL;
858 crit_freespace_percent = NULL;
859 warn_usedspace_percent = NULL;
860 crit_usedspace_percent = NULL;
861 warn_usedinodes_percent = NULL;
862 crit_usedinodes_percent = NULL;
863 warn_freeinodes_percent = NULL;
864 crit_freeinodes_percent = NULL;
865
866 path_selected = false;
867 group = NULL;
868 break;
869 case 'V': /* version */
870 print_revision (progname, NP_VERSION);
871 exit (STATE_UNKNOWN);
872 case 'h': /* help */
873 print_help ();
874 exit (STATE_UNKNOWN);
875 case '?': /* help */
876 usage (_("Unknown argument"));
877 }
878 }
879
880 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
881 c = optind;
882 if (warn_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
883 warn_usedspace_percent = argv[c++];
884
885 if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
886 crit_usedspace_percent = argv[c++];
887
888 if (argc > c) {
889 se = np_add_parameter(&path_select_list, strdup(argv[c++]));
890 path_selected = true;
891 set_all_thresholds(se);
892 }
893
894 if (units == NULL) {
895 units = strdup ("MiB");
896 mult = (uintmax_t)1024 * 1024;
897 }
898
899 return true;
900}
901 496
497 case 'W': /* warning inode threshold */
498 if (*optarg == '@') {
499 warn_freeinodes_percent = optarg;
500 } else {
501 xasprintf(&warn_freeinodes_percent, "@%s", optarg);
502 }
503 break;
504 case 'K': /* critical inode threshold */
505 if (*optarg == '@') {
506 crit_freeinodes_percent = optarg;
507 } else {
508 xasprintf(&crit_freeinodes_percent, "@%s", optarg);
509 }
510 break;
511 case 'u':
512 if (!strcasecmp(optarg, "bytes")) {
513 unit = Bytes_Factor;
514 } else if (!strcmp(optarg, "KiB")) {
515 unit = KibiBytes_factor;
516 } else if (!strcmp(optarg, "kB")) {
517 unit = KiloBytes_factor;
518 } else if (!strcmp(optarg, "MiB")) {
519 unit = MebiBytes_factor;
520 } else if (!strcmp(optarg, "MB")) {
521 unit = MegaBytes_factor;
522 } else if (!strcmp(optarg, "GiB")) {
523 unit = GibiBytes_factor;
524 } else if (!strcmp(optarg, "GB")) {
525 unit = GigaBytes_factor;
526 } else if (!strcmp(optarg, "TiB")) {
527 unit = TebiBytes_factor;
528 } else if (!strcmp(optarg, "TB")) {
529 unit = TeraBytes_factor;
530 } else if (!strcmp(optarg, "PiB")) {
531 unit = PebiBytes_factor;
532 } else if (!strcmp(optarg, "PB")) {
533 unit = PetaBytes_factor;
534 } else {
535 die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
536 }
537 break;
538 case 'k':
539 unit = KibiBytes_factor;
540 break;
541 case 'm':
542 unit = MebiBytes_factor;
543 break;
544 case display_unit_index:
545 if (!strcasecmp(optarg, "bytes")) {
546 result.config.display_unit = Bytes;
547 } else if (!strcmp(optarg, "KiB")) {
548 result.config.display_unit = KibiBytes;
549 } else if (!strcmp(optarg, "kB")) {
550 result.config.display_unit = KiloBytes;
551 } else if (!strcmp(optarg, "MiB")) {
552 result.config.display_unit = MebiBytes;
553 } else if (!strcmp(optarg, "MB")) {
554 result.config.display_unit = MegaBytes;
555 } else if (!strcmp(optarg, "GiB")) {
556 result.config.display_unit = GibiBytes;
557 } else if (!strcmp(optarg, "GB")) {
558 result.config.display_unit = GigaBytes;
559 } else if (!strcmp(optarg, "TiB")) {
560 result.config.display_unit = TebiBytes;
561 } else if (!strcmp(optarg, "TB")) {
562 result.config.display_unit = TeraBytes;
563 } else if (!strcmp(optarg, "PiB")) {
564 result.config.display_unit = PebiBytes;
565 } else if (!strcmp(optarg, "PB")) {
566 result.config.display_unit = PetaBytes;
567 } else {
568 die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
569 }
570 break;
571 case 'L':
572 result.config.stat_remote_fs = true;
573 /* fallthrough */
574 case 'l':
575 result.config.show_local_fs = true;
576 break;
577 case 'P':
578 result.config.display_inodes_perfdata = true;
579 break;
580 case 'p': /* select path */ {
581 if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent || crit_freespace_percent ||
582 warn_freeinodes_percent || crit_freeinodes_percent)) {
583 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
584 }
902 585
586 /* add parameter if not found. overwrite thresholds if path has already been added */
587 parameter_list_elem *search_entry;
588 if (!(search_entry = mp_int_fs_list_find(result.config.path_select_list, optarg))) {
589 search_entry = mp_int_fs_list_append(&result.config.path_select_list, optarg);
903 590
904void 591 // struct stat stat_buf = {};
905print_path (const char *mypath) 592 // if (stat(optarg, &stat_buf) && result.config.ignore_missing) {
906{ 593 // result.config.path_ignored = true;
907 if (mypath == NULL) 594 // break;
908 printf ("\n"); 595 // }
909 else 596 }
910 printf (_(" for %s\n"), mypath); 597 search_entry->group = group;
911} 598 set_all_thresholds(search_entry, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
599
600 warn_freeinodes_percent, crit_freeinodes_percent);
601
602 /* With autofs, it is required to stat() the path before re-populating the mount_list */
603 // if (!stat_path(se, result.config.ignore_missing)) {
604 // break;
605 // }
606 mp_int_fs_list_set_best_match(result.config.path_select_list, result.config.mount_list, result.config.exact_match);
607
608 path_selected = true;
609 } break;
610 case 'x': /* exclude path or partition */
611 np_add_name(&result.config.device_path_exclude_list, optarg);
612 break;
613 case 'X': /* exclude file system type */ {
614 int err = np_add_regex(&result.config.fs_exclude_list, optarg, REG_EXTENDED);
615 if (err != 0) {
616 char errbuf[MAX_INPUT_BUFFER];
617 regerror(err, &result.config.fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
618 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
619 }
620 break;
621 case 'N': /* include file system type */
622 err = np_add_regex(&result.config.fs_include_list, optarg, REG_EXTENDED);
623 if (err != 0) {
624 char errbuf[MAX_INPUT_BUFFER];
625 regerror(err, &result.config.fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
626 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
627 }
628 } break;
629 case 'v': /* verbose */
630 verbose++;
631 break;
632 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
633 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
634 result.config.erronly = true;
635 break;
636 case 'e':
637 result.config.erronly = true;
638 break;
639 case 'E':
640 if (path_selected) {
641 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting paths\n"));
642 }
643 result.config.exact_match = true;
644 break;
645 case 'f':
646 result.config.freespace_ignore_reserved = true;
647 break;
648 case 'g':
649 if (path_selected) {
650 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting paths\n"));
651 }
652 group = optarg;
653 break;
654 case 'I':
655 cflags |= REG_ICASE;
656 // Intentional fallthrough
657 case 'i': {
658 if (!path_selected) {
659 die(STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"),
660 _("Paths need to be selected before using -i/-I. Use -A to select all paths explicitly"));
661 }
662 regex_t regex;
663 int err = regcomp(&regex, optarg, cflags);
664 if (err != 0) {
665 char errbuf[MAX_INPUT_BUFFER];
666 regerror(err, &regex, errbuf, MAX_INPUT_BUFFER);
667 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
668 }
912 669
670 for (parameter_list_elem *elem = result.config.path_select_list.first; elem;) {
671 if (elem->best_match) {
672 if (np_regex_match_mount_entry(elem->best_match, &regex)) {
913 673
914void 674 if (verbose >= 3) {
915set_all_thresholds (struct parameter_list *path) 675 printf("ignoring %s matching regex\n", elem->name);
916{ 676 }
917 if (path->freespace_units != NULL) free(path->freespace_units);
918 set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
919 if (path->freespace_percent != NULL) free (path->freespace_percent);
920 set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
921 if (path->usedspace_units != NULL) free (path->usedspace_units);
922 set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
923 if (path->usedspace_percent != NULL) free (path->usedspace_percent);
924 set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
925 if (path->usedinodes_percent != NULL) free (path->usedinodes_percent);
926 set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
927 if (path->freeinodes_percent != NULL) free (path->freeinodes_percent);
928 set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
929}
930 677
931void 678 elem = mp_int_fs_list_del(&result.config.path_select_list, elem);
932print_help (void) 679 continue;
933{ 680 }
934 print_revision (progname, NP_VERSION); 681 }
935
936 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
937 printf (COPYRIGHT, copyright, email);
938
939 printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
940 printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
941
942 printf ("\n\n");
943
944 print_usage ();
945
946 printf (UT_HELP_VRSN);
947 printf (UT_EXTRA_OPTS);
948
949 printf (" %s\n", "-w, --warning=INTEGER");
950 printf (" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
951 printf (" %s\n", "-w, --warning=PERCENT%");
952 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
953 printf (" %s\n", "-c, --critical=INTEGER");
954 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
955 printf (" %s\n", "-c, --critical=PERCENT%");
956 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of disk space is free"));
957 printf (" %s\n", "-W, --iwarning=PERCENT%");
958 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
959 printf (" %s\n", "-K, --icritical=PERCENT%");
960 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
961 printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
962 printf (" %s\n", _("Mount point or block device as emitted by the mount(8) command (may be repeated)"));
963 printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
964 printf (" %s\n", _("Ignore device (only works if -p unspecified)"));
965 printf (" %s\n", "-C, --clear");
966 printf (" %s\n", _("Clear thresholds"));
967 printf (" %s\n", "-E, --exact-match");
968 printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
969 printf (" %s\n", "-e, --errors-only");
970 printf (" %s\n", _("Display only devices/mountpoints with errors"));
971 printf (" %s\n", "-f, --freespace-ignore-reserved");
972 printf (" %s\n", _("Don't account root-reserved blocks into freespace in perfdata"));
973 printf (" %s\n", "-P, --iperfdata");
974 printf (" %s\n", _("Display inode usage in perfdata"));
975 printf (" %s\n", "-g, --group=NAME");
976 printf (" %s\n", _("Group paths. Thresholds apply to (free-)space of all partitions together"));
977 printf (" %s\n", "-k, --kilobytes");
978 printf (" %s\n", _("Same as '--units kB'"));
979 printf (" %s\n", "-l, --local");
980 printf (" %s\n", _("Only check local filesystems"));
981 printf (" %s\n", "-L, --stat-remote-fs");
982 printf (" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
983 printf (" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
984 printf (" %s\n", "-M, --mountpoint");
985 printf (" %s\n", _("Display the (block) device instead of the mount point"));
986 printf (" %s\n", "-m, --megabytes");
987 printf (" %s\n", _("Same as '--units MB'"));
988 printf (" %s\n", "-A, --all");
989 printf (" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'"));
990 printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
991 printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
992 printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
993 printf (" %s\n", _("Regular expression for path or partition (may be repeated)"));
994 printf (" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
995 printf (" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
996 printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
997 printf (" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
998 printf (" %s\n", "-n, --ignore-missing");
999 printf (" %s\n", _("Return OK if no filesystem matches, filesystem does not exist or is inaccessible."));
1000 printf (" %s\n", _("(Provide this option before -p / -r / --ereg-path if used)"));
1001 printf (UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1002 printf (" %s\n", "-u, --units=STRING");
1003 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
1004 printf (UT_VERBOSE);
1005 printf (" %s\n", "-X, --exclude-type=TYPE_REGEX");
1006 printf (" %s\n", _("Ignore all filesystems of types matching given regex(7) (may be repeated)"));
1007 printf (" %s\n", "-N, --include-type=TYPE_REGEX");
1008 printf (" %s\n", _("Check only filesystems where the type matches this given regex(7) (may be repeated)"));
1009
1010 printf ("\n");
1011 printf ("%s\n", _("General usage hints:"));
1012 printf (" %s\n", _("- Arguments are positional! \"-w 5 -c 1 -p /foo -w6 -c2 -p /bar\" is not the same as"));
1013 printf (" %s\n", _("\"-w 5 -c 1 -p /bar w6 -c2 -p /foo\"."));
1014 printf (" %s\n", _("- The syntax is broadly: \"{thresholds a} {paths a} -C {thresholds b} {thresholds b} ...\""));
1015
1016
1017
1018 printf ("\n");
1019 printf ("%s\n", _("Examples:"));
1020 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
1021 printf (" %s\n\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
1022 printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -g sidDATA -r '^/oracle/SID/data.*$'");
1023 printf (" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
1024 printf (" %s\n\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
1025 printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar");
1026 printf (" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
1027
1028 printf (UT_SUPPORT);
1029}
1030 682
683 elem = mp_int_fs_list_get_next(elem);
684 }
1031 685
686 cflags = default_cflags;
687 } break;
688 case 'n':
689 result.config.ignore_missing = true;
690 break;
691 case 'A':
692 optarg = strdup(".*");
693 // Intentional fallthrough
694 case 'R':
695 cflags |= REG_ICASE;
696 // Intentional fallthrough
697 case 'r': {
698 if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent || crit_freespace_percent ||
699 warn_freeinodes_percent || crit_freeinodes_percent)) {
700 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"),
701 _("Must set a threshold value before using -r/-R/-A (--ereg-path/--eregi-path/--all)\n"));
702 }
1032 703
1033void 704 regex_t regex;
1034print_usage (void) 705 int err = regcomp(&regex, optarg, cflags);
1035{ 706 if (err != 0) {
1036 printf ("%s\n", _("Usage:")); 707 char errbuf[MAX_INPUT_BUFFER];
1037 printf (" %s {-w absolute_limit |-w percentage_limit%% | -W inode_percentage_limit } {-c absolute_limit|-c percentage_limit%% | -K inode_percentage_limit } {-p path | -x device}\n", progname); 708 regerror(err, &regex, errbuf, MAX_INPUT_BUFFER);
1038 printf ("[-C] [-E] [-e] [-f] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n"); 709 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
1039 printf ("[-t timeout] [-u unit] [-v] [-X type_regex] [-N type]\n"); 710 }
711
712 bool found = false;
713 for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
714 if (np_regex_match_mount_entry(me, &regex)) {
715 found = true;
716 if (verbose >= 3) {
717 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
718 }
719
720 /* add parameter if not found. overwrite thresholds if path has already been added */
721 parameter_list_elem *se = NULL;
722 if (!(se = mp_int_fs_list_find(result.config.path_select_list, me->me_mountdir))) {
723 se = mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
724 }
725 se->group = group;
726 set_all_thresholds(se, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
727 warn_freeinodes_percent, crit_freeinodes_percent);
728 }
729 }
730
731 if (!found) {
732 if (result.config.ignore_missing) {
733 result.config.path_ignored = true;
734 path_selected = true;
735 break;
736 }
737
738 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Regular expression did not match any path or disk"), optarg);
739 }
740
741 path_selected = true;
742 mp_int_fs_list_set_best_match(result.config.path_select_list, result.config.mount_list, result.config.exact_match);
743 cflags = default_cflags;
744
745 } break;
746 case 'M': /* display mountpoint */
747 result.config.display_mntp = true;
748 break;
749 case 'C': {
750 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
751 if (!path_selected) {
752 parameter_list_elem *path;
753 for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
754 if (!(path = mp_int_fs_list_find(result.config.path_select_list, me->me_mountdir))) {
755 path = mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
756 }
757 path->best_match = me;
758 path->group = group;
759 set_all_thresholds(path, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
760 warn_freeinodes_percent, crit_freeinodes_percent);
761 }
762 }
763
764 warn_freespace_units = NULL;
765 crit_freespace_units = NULL;
766 warn_freespace_percent = NULL;
767 crit_freespace_percent = NULL;
768 warn_freeinodes_percent = NULL;
769 crit_freeinodes_percent = NULL;
770
771 path_selected = false;
772 group = NULL;
773 } break;
774 case 'V': /* version */
775 print_revision(progname, NP_VERSION);
776 exit(STATE_UNKNOWN);
777 case 'h': /* help */
778 print_help();
779 exit(STATE_UNKNOWN);
780 case '?': /* help */
781 usage(_("Unknown argument"));
782 case output_format_index: {
783 parsed_output_format parser = mp_parse_output_format(optarg);
784 if (!parser.parsing_success) {
785 // TODO List all available formats here, maybe add anothoer usage function
786 printf("Invalid output format: %s\n", optarg);
787 exit(STATE_UNKNOWN);
788 }
789
790 result.config.output_format_is_set = true;
791 result.config.output_format = parser.output_format;
792 break;
793 }
794 }
795 }
796
797 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
798 int index = optind;
799
800 if (argc > index && is_intnonneg(argv[index])) {
801 if (verbose > 0) {
802 printf("Got an positional warn threshold: %s\n", argv[index]);
803 }
804 char *range = argv[index++];
805 mp_range_parsed tmp = mp_parse_range_string(range);
806 if (tmp.error != MP_PARSING_SUCCES) {
807 die(STATE_UNKNOWN, "failed to parse warning threshold");
808 }
809
810 mp_range tmp_range = tmp.range;
811 // Invert range to use it for free instead of used
812 // tmp_range.alert_on_inside_range = !tmp_range.alert_on_inside_range;
813
814 warn_freespace_percent = mp_range_to_string(tmp_range);
815
816 if (verbose > 0) {
817 printf("Positional warning threshold transformed to: %s\n", warn_freespace_percent);
818 }
819 }
820
821 if (argc > index && is_intnonneg(argv[index])) {
822 if (verbose > 0) {
823 printf("Got an positional crit threshold: %s\n", argv[index]);
824 }
825 char *range = argv[index++];
826 mp_range_parsed tmp = mp_parse_range_string(range);
827 if (tmp.error != MP_PARSING_SUCCES) {
828 die(STATE_UNKNOWN, "failed to parse warning threshold");
829 }
830
831 mp_range tmp_range = tmp.range;
832 // Invert range to use it for free instead of used
833 // tmp_range.alert_on_inside_range = !tmp_range.alert_on_inside_range;
834
835 crit_freespace_percent = mp_range_to_string(tmp_range);
836
837 if (verbose > 0) {
838 printf("Positional critical threshold transformed to: %s\n", crit_freespace_percent);
839 }
840 }
841
842 if (argc > index) {
843 if (verbose > 0) {
844 printf("Got an positional filesystem: %s\n", argv[index]);
845 }
846 struct parameter_list *se = mp_int_fs_list_append(&result.config.path_select_list, strdup(argv[index++]));
847 path_selected = true;
848 set_all_thresholds(se, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
849 warn_freeinodes_percent, crit_freeinodes_percent);
850 }
851
852 // If a list of paths has not been explicitly selected, find entire
853 // mount list and create list of paths
854 if (!path_selected && !result.config.path_ignored) {
855 for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
856 if (me->me_dummy != 0) {
857 // just do not add dummy filesystems
858 continue;
859 }
860
861 parameter_list_elem *path = NULL;
862 if (!(path = mp_int_fs_list_find(result.config.path_select_list, me->me_mountdir))) {
863 path = mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
864 }
865 path->best_match = me;
866 path->group = group;
867 set_all_thresholds(path, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
868 warn_freeinodes_percent, crit_freeinodes_percent);
869 }
870 }
871
872 // Set thresholds to the appropriate unit
873 for (parameter_list_elem *tmp = result.config.path_select_list.first; tmp; tmp = mp_int_fs_list_get_next(tmp)) {
874
875 mp_perfdata_value factor = mp_create_pd_value(unit);
876
877 if (tmp->freespace_units.critical_is_set) {
878 tmp->freespace_units.critical = mp_range_multiply(tmp->freespace_units.critical, factor);
879 }
880 if (tmp->freespace_units.warning_is_set) {
881 tmp->freespace_units.warning = mp_range_multiply(tmp->freespace_units.warning, factor);
882 }
883 }
884
885 return result;
1040} 886}
1041 887
1042bool 888void set_all_thresholds(parameter_list_elem *path, char *warn_freespace_units, char *crit_freespace_units, char *warn_freespace_percent,
1043stat_path (struct parameter_list *p) 889 char *crit_freespace_percent, char *warn_freeinodes_percent, char *crit_freeinodes_percent) {
1044{ 890 mp_range_parsed tmp;
1045 /* Stat entry to check that dir exists and is accessible */ 891
1046 if (verbose >= 3) 892 if (warn_freespace_units) {
1047 printf("calling stat on %s\n", p->name); 893 tmp = mp_parse_range_string(warn_freespace_units);
1048 if (stat (p->name, &stat_buf[0])) { 894 path->freespace_units = mp_thresholds_set_warn(path->freespace_units, tmp.range);
1049 if (verbose >= 3) 895 }
1050 printf("stat failed on %s\n", p->name); 896
1051 if (ignore_missing == true) { 897 if (crit_freespace_units) {
1052 return false; 898 tmp = mp_parse_range_string(crit_freespace_units);
1053 } else { 899 path->freespace_units = mp_thresholds_set_crit(path->freespace_units, tmp.range);
1054 printf("DISK %s - ", _("CRITICAL")); 900 }
1055 die (STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno)); 901
1056 } 902 if (warn_freespace_percent) {
1057 } 903 tmp = mp_parse_range_string(warn_freespace_percent);
1058 return true; 904 path->freespace_percent = mp_thresholds_set_warn(path->freespace_percent, tmp.range);
905 }
906
907 if (crit_freespace_percent) {
908 tmp = mp_parse_range_string(crit_freespace_percent);
909 path->freespace_percent = mp_thresholds_set_crit(path->freespace_percent, tmp.range);
910 }
911
912 if (warn_freeinodes_percent) {
913 tmp = mp_parse_range_string(warn_freeinodes_percent);
914 path->freeinodes_percent = mp_thresholds_set_warn(path->freeinodes_percent, tmp.range);
915 }
916
917 if (crit_freeinodes_percent) {
918 tmp = mp_parse_range_string(crit_freeinodes_percent);
919 path->freeinodes_percent = mp_thresholds_set_crit(path->freeinodes_percent, tmp.range);
920 }
1059} 921}
1060 922
923void print_help(void) {
924 print_revision(progname, NP_VERSION);
925
926 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
927 printf(COPYRIGHT, copyright, email);
928
929 printf("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
930 printf("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
931
932 printf("\n\n");
933
934 print_usage();
935
936 printf(UT_HELP_VRSN);
937 printf(UT_EXTRA_OPTS);
938
939 printf(" %s\n", "-w, --warning=INTEGER");
940 printf(" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
941 printf(" %s\n", "-w, --warning=PERCENT%");
942 printf(" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
943 printf(" %s\n", "-c, --critical=INTEGER");
944 printf(" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
945 printf(" %s\n", "-c, --critical=PERCENT%");
946 printf(" %s\n", _("Exit with CRITICAL status if less than PERCENT of disk space is free"));
947 printf(" %s\n", "-W, --iwarning=PERCENT%");
948 printf(" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
949 printf(" %s\n", "-K, --icritical=PERCENT%");
950 printf(" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
951 printf(" %s\n", "-p, --path=PATH, --partition=PARTITION");
952 printf(" %s\n", _("Mount point or block device as emitted by the mount(8) command (may be repeated)"));
953 printf(" %s\n", "-x, --exclude_device=PATH <STRING>");
954 printf(" %s\n", _("Ignore device (only works if -p unspecified)"));
955 printf(" %s\n", "-C, --clear");
956 printf(" %s\n", _("Clear thresholds"));
957 printf(" %s\n", "-E, --exact-match");
958 printf(" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
959 printf(" %s\n", "-e, --errors-only");
960 printf(" %s\n", _("Display only devices/mountpoints with errors"));
961 printf(" %s\n", "-f, --freespace-ignore-reserved");
962 printf(" %s\n", _("Don't account root-reserved blocks into freespace in perfdata"));
963 printf(" %s\n", "-P, --iperfdata");
964 printf(" %s\n", _("Display inode usage in perfdata"));
965 printf(" %s\n", "-g, --group=NAME");
966 printf(" %s\n", _("Group paths. Thresholds apply to (free-)space of all partitions together"));
967 printf(" %s\n", "-l, --local");
968 printf(" %s\n", _("Only check local filesystems"));
969 printf(" %s\n", "-L, --stat-remote-fs");
970 printf(" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
971 printf(" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
972 printf(" %s\n", "-M, --mountpoint");
973 printf(" %s\n", _("Display the (block) device instead of the mount point"));
974 printf(" %s\n", "-A, --all");
975 printf(" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'"));
976 printf(" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
977 printf(" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
978 printf(" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
979 printf(" %s\n", _("Regular expression for path or partition (may be repeated)"));
980 printf(" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
981 printf(" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
982 printf(" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
983 printf(" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
984 printf(" %s\n", "-n, --ignore-missing");
985 printf(" %s\n", _("Return OK if no filesystem matches, filesystem does not exist or is inaccessible."));
986 printf(" %s\n", _("(Provide this option before -p / -r / --ereg-path if used)"));
987 printf(UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
988 printf(" %s\n", "-u, --units=STRING");
989 printf(" %s\n", _("Select the unit used for the absolute value thresholds"));
990 printf(
991 " %s\n",
992 _("Choose one of \"bytes\", \"KiB\", \"kB\", \"MiB\", \"MB\", \"GiB\", \"GB\", \"TiB\", \"TB\", \"PiB\", \"PB\" (default: MiB)"));
993 printf(" %s\n", "-k, --kilobytes");
994 printf(" %s\n", _("Same as '--units kB'"));
995 printf(" %s\n", "--display-unit");
996 printf(" %s\n", _("Select the unit used for in the output"));
997 printf(
998 " %s\n",
999 _("Choose one of \"bytes\", \"KiB\", \"kB\", \"MiB\", \"MB\", \"GiB\", \"GB\", \"TiB\", \"TB\", \"PiB\", \"PB\" (default: MiB)"));
1000 printf(" %s\n", "-m, --megabytes");
1001 printf(" %s\n", _("Same as '--units MB'"));
1002 printf(UT_VERBOSE);
1003 printf(" %s\n", "-X, --exclude-type=TYPE_REGEX");
1004 printf(" %s\n", _("Ignore all filesystems of types matching given regex(7) (may be repeated)"));
1005 printf(" %s\n", "-N, --include-type=TYPE_REGEX");
1006 printf(" %s\n", _("Check only filesystems where the type matches this given regex(7) (may be repeated)"));
1007 printf(UT_OUTPUT_FORMAT);
1008
1009 printf("\n");
1010 printf("%s\n", _("General usage hints:"));
1011 printf(" %s\n", _("- Arguments are positional! \"-w 5 -c 1 -p /foo -w6 -c2 -p /bar\" is not the same as"));
1012 printf(" %s\n", _("\"-w 5 -c 1 -p /bar w6 -c2 -p /foo\"."));
1013 printf(" %s\n", _("- The syntax is broadly: \"{thresholds a} {paths a} -C {thresholds b} {thresholds b} ...\""));
1014
1015 printf("\n");
1016 printf("%s\n", _("Examples:"));
1017 printf(" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
1018 printf(" %s\n\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
1019 printf(" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -g sidDATA -r '^/oracle/SID/data.*$'");
1020 printf(" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
1021 printf(" %s\n\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
1022 printf(" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar");
1023 printf(" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
1024
1025 printf(UT_SUPPORT);
1026}
1061 1027
1062void 1028void print_usage(void) {
1063get_stats (struct parameter_list *p, struct fs_usage *fsp) { 1029 printf("%s\n", _("Usage:"));
1064 struct parameter_list *p_list; 1030 printf(" %s {-w absolute_limit |-w percentage_limit%% | -W inode_percentage_limit } {-c absolute_limit|-c percentage_limit%% | -K "
1065 struct fs_usage tmpfsp; 1031 "inode_percentage_limit } {-p path | -x device}\n",
1066 int first = 1; 1032 progname);
1033 printf("[-C] [-E] [-e] [-f] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
1034 printf("[-t timeout] [-u unit] [-v] [-X type_regex] [-N type]\n");
1035}
1067 1036
1068 if (p->group == NULL) { 1037bool stat_path(parameter_list_elem *parameters, bool ignore_missing) {
1069 get_path_stats(p,fsp); 1038 /* Stat entry to check that dir exists and is accessible */
1070 } else { 1039 if (verbose >= 3) {
1071 /* find all group members */ 1040 printf("calling stat on %s\n", parameters->name);
1072 for (p_list = path_select_list; p_list; p_list=p_list->name_next) { 1041 }
1073#ifdef __CYGWIN__ 1042
1074 if (strncmp(p_list->name, "/cygdrive/", 10) != 0) 1043 struct stat stat_buf = {0};
1075 continue; 1044 if (stat(parameters->name, &stat_buf)) {
1076#endif 1045 if (verbose >= 3) {
1077 if (p_list->group && ! (strcmp(p_list->group, p->group))) { 1046 printf("stat failed on %s\n", parameters->name);
1078 if (! stat_path(p_list)) 1047 }
1079 continue; 1048 if (ignore_missing) {
1080 get_fs_usage (p_list->best_match->me_mountdir, p_list->best_match->me_devname, &tmpfsp); 1049 return false;
1081 get_path_stats(p_list, &tmpfsp); 1050 }
1082 if (verbose >= 3) 1051 printf("DISK %s - ", _("CRITICAL"));
1083 printf("Group %s: adding %lu blocks sized %lu, (%s) used_units=%lu free_units=%lu total_units=%lu mult=%lu\n", 1052 die(STATE_CRITICAL, _("%s %s: %s\n"), parameters->name, _("is not accessible"), strerror(errno));
1084 p_list->group, 1053 }
1085 tmpfsp.fsu_blocks, 1054
1086 tmpfsp.fsu_blocksize, 1055 return true;
1087 p_list->best_match->me_mountdir, 1056}
1088 p_list->dused_units,
1089 p_list->dfree_units,
1090 p_list->dtotal_units,
1091 mult);
1092
1093 /* prevent counting the first FS of a group twice since its parameter_list entry
1094 * is used to carry the information of all file systems of the entire group */
1095 if (! first) {
1096 p->total += p_list->total;
1097 p->available += p_list->available;
1098 p->available_to_root += p_list->available_to_root;
1099 p->used += p_list->used;
1100
1101 p->dused_units += p_list->dused_units;
1102 p->dfree_units += p_list->dfree_units;
1103 p->dtotal_units += p_list->dtotal_units;
1104 p->inodes_total += p_list->inodes_total;
1105 p->inodes_free += p_list->inodes_free;
1106 p->inodes_free_to_root += p_list->inodes_free_to_root;
1107 p->inodes_used += p_list->inodes_used;
1108 }
1109 first = 0;
1110 }
1111 if (verbose >= 3)
1112 printf("Group %s now has: used_units=%lu free_units=%lu total_units=%lu fsu_blocksize=%lu mult=%lu\n",
1113 p->group,
1114 p->dused_units,
1115 p->dfree_units,
1116 p->dtotal_units,
1117 tmpfsp.fsu_blocksize,
1118 mult);
1119 }
1120 /* modify devname and mountdir for output */
1121 p->best_match->me_mountdir = p->best_match->me_devname = p->group;
1122 }
1123 /* finally calculate percentages for either plain FS or summed up group */
1124 p->dused_pct = calculate_percent( p->used, p->used + p->available ); /* used + available can never be > uintmax */
1125 p->dfree_pct = 100.0 - p->dused_pct;
1126 p->dused_inodes_percent = calculate_percent(p->inodes_total - p->inodes_free, p->inodes_total);
1127 p->dfree_inodes_percent = 100 - p->dused_inodes_percent;
1128 1057
1058static parameter_list_elem get_path_stats(parameter_list_elem parameters, const struct fs_usage fsp, bool freespace_ignore_reserved) {
1059 uintmax_t available = fsp.fsu_bavail;
1060 uintmax_t available_to_root = fsp.fsu_bfree;
1061 uintmax_t used = fsp.fsu_blocks - fsp.fsu_bfree;
1062 uintmax_t total;
1063
1064 if (freespace_ignore_reserved) {
1065 /* option activated : we subtract the root-reserved space from the total */
1066 total = fsp.fsu_blocks - available_to_root + available;
1067 } else {
1068 /* default behaviour : take all the blocks into account */
1069 total = fsp.fsu_blocks;
1070 }
1071
1072 parameters.used_bytes = used * fsp.fsu_blocksize;
1073 parameters.free_bytes = available * fsp.fsu_blocksize;
1074 parameters.total_bytes = total * fsp.fsu_blocksize;
1075
1076 /* Free file nodes. Not sure the workaround is required, but in case...*/
1077 parameters.inodes_free = fsp.fsu_ffree;
1078 parameters.inodes_free_to_root = fsp.fsu_ffree; /* Free file nodes for root. */
1079 parameters.inodes_used = fsp.fsu_files - fsp.fsu_ffree;
1080
1081 if (freespace_ignore_reserved) {
1082 /* option activated : we subtract the root-reserved inodes from the total */
1083 /* not all OS report fsp->fsu_favail, only the ones with statvfs syscall */
1084 /* for others, fsp->fsu_ffree == fsp->fsu_favail */
1085 parameters.inodes_total = fsp.fsu_files - parameters.inodes_free_to_root + parameters.inodes_free;
1086 } else {
1087 /* default behaviour : take all the inodes into account */
1088 parameters.inodes_total = fsp.fsu_files;
1089 }
1090
1091 return parameters;
1129} 1092}
1130 1093
1131void 1094mp_subcheck evaluate_filesystem(measurement_unit measurement_unit, bool display_inodes_perfdata, byte_unit unit) {
1132get_path_stats (struct parameter_list *p, struct fs_usage *fsp) { 1095 mp_subcheck result = mp_subcheck_init();
1133 p->available = fsp->fsu_bavail; 1096 result = mp_set_subcheck_default_state(result, STATE_UNKNOWN);
1134 p->available_to_root = fsp->fsu_bfree; 1097 xasprintf(&result.output, "%s", measurement_unit.name);
1135 p->used = fsp->fsu_blocks - fsp->fsu_bfree; 1098
1136 if (freespace_ignore_reserved) { 1099 if (!measurement_unit.is_group && measurement_unit.filesystem_type) {
1137 /* option activated : we subtract the root-reserved space from the total */ 1100 xasprintf(&result.output, "%s (%s)", result.output, measurement_unit.filesystem_type);
1138 p->total = fsp->fsu_blocks - p->available_to_root + p->available; 1101 }
1139 } else { 1102
1140 /* default behaviour : take all the blocks into account */ 1103 /* Threshold comparisons */
1141 p->total = fsp->fsu_blocks; 1104
1142 } 1105 // ===============================
1143 1106 // Free space absolute values test
1144 p->dused_units = p->used*fsp->fsu_blocksize/mult; 1107 mp_subcheck freespace_bytes_sc = mp_subcheck_init();
1145 p->dfree_units = p->available*fsp->fsu_blocksize/mult; 1108 freespace_bytes_sc = mp_set_subcheck_default_state(freespace_bytes_sc, STATE_OK);
1146 p->dtotal_units = p->total*fsp->fsu_blocksize/mult; 1109
1147 /* Free file nodes. Not sure the workaround is required, but in case...*/ 1110 if (unit != Humanized) {
1148 p->inodes_free = fsp->fsu_ffree; 1111 xasprintf(&freespace_bytes_sc.output, "Free space absolute: %ju%s (of %ju%s)", (uintmax_t)(measurement_unit.free_bytes / unit),
1149 p->inodes_free_to_root = fsp->fsu_ffree; /* Free file nodes for root. */ 1112 get_unit_string(unit), (uintmax_t)(measurement_unit.total_bytes / unit), get_unit_string(unit));
1150 p->inodes_used = fsp->fsu_files - fsp->fsu_ffree; 1113 } else {
1151 if (freespace_ignore_reserved) { 1114 xasprintf(&freespace_bytes_sc.output, "Free space absolute: %s (of %s)", humanize_byte_value(measurement_unit.free_bytes, false),
1152 /* option activated : we subtract the root-reserved inodes from the total */ 1115 humanize_byte_value((unsigned long long)measurement_unit.total_bytes, false));
1153 /* not all OS report fsp->fsu_favail, only the ones with statvfs syscall */ 1116 }
1154 /* for others, fsp->fsu_ffree == fsp->fsu_favail */ 1117
1155 p->inodes_total = fsp->fsu_files - p->inodes_free_to_root + p->inodes_free; 1118 mp_perfdata used_space = perfdata_init();
1156 } else { 1119 used_space.label = measurement_unit.name;
1157 /* default behaviour : take all the inodes into account */ 1120 used_space.value = mp_create_pd_value(measurement_unit.free_bytes);
1158 p->inodes_total = fsp->fsu_files; 1121 used_space = mp_set_pd_max_value(used_space, mp_create_pd_value(measurement_unit.total_bytes));
1159 } 1122 used_space = mp_set_pd_min_value(used_space, mp_create_pd_value(0));
1160 np_add_name(&seen, p->best_match->me_mountdir); 1123 used_space.uom = "B";
1124 used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
1125 freespace_bytes_sc = mp_set_subcheck_state(freespace_bytes_sc, mp_get_pd_status(used_space));
1126
1127 // special case for absolute space thresholds here:
1128 // if absolute values are not set, compute the thresholds from percentage thresholds
1129 mp_thresholds temp_thlds = measurement_unit.freespace_bytes_thresholds;
1130 if (!temp_thlds.critical_is_set && measurement_unit.freespace_percent_thresholds.critical_is_set) {
1131 mp_range tmp_range = measurement_unit.freespace_percent_thresholds.critical;
1132
1133 if (!tmp_range.end_infinity) {
1134 tmp_range.end = mp_create_pd_value(mp_get_pd_value(tmp_range.end) / 100 * measurement_unit.total_bytes);
1135 }
1136
1137 if (!tmp_range.start_infinity) {
1138 tmp_range.start = mp_create_pd_value(mp_get_pd_value(tmp_range.start) / 100 * measurement_unit.total_bytes);
1139 }
1140 measurement_unit.freespace_bytes_thresholds = mp_thresholds_set_crit(measurement_unit.freespace_bytes_thresholds, tmp_range);
1141 used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
1142 }
1143
1144 if (!temp_thlds.warning_is_set && measurement_unit.freespace_percent_thresholds.warning_is_set) {
1145 mp_range tmp_range = measurement_unit.freespace_percent_thresholds.warning;
1146 if (!tmp_range.end_infinity) {
1147 tmp_range.end = mp_create_pd_value(mp_get_pd_value(tmp_range.end) / 100 * measurement_unit.total_bytes);
1148 }
1149 if (!tmp_range.start_infinity) {
1150 tmp_range.start = mp_create_pd_value(mp_get_pd_value(tmp_range.start) / 100 * measurement_unit.total_bytes);
1151 }
1152 measurement_unit.freespace_bytes_thresholds = mp_thresholds_set_warn(measurement_unit.freespace_bytes_thresholds, tmp_range);
1153 used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
1154 }
1155
1156 mp_add_perfdata_to_subcheck(&freespace_bytes_sc, used_space);
1157 mp_add_subcheck_to_subcheck(&result, freespace_bytes_sc);
1158
1159 // ==========================
1160 // Free space percentage test
1161 mp_subcheck freespace_percent_sc = mp_subcheck_init();
1162 freespace_percent_sc = mp_set_subcheck_default_state(freespace_percent_sc, STATE_OK);
1163
1164 double free_percentage = calculate_percent(measurement_unit.free_bytes, measurement_unit.total_bytes);
1165 xasprintf(&freespace_percent_sc.output, "Free space percentage: %g%%", free_percentage);
1166
1167 // Using perfdata here just to get to the test result
1168 mp_perfdata free_space_percent_pd = perfdata_init();
1169 free_space_percent_pd.value = mp_create_pd_value(free_percentage);
1170 free_space_percent_pd = mp_pd_set_thresholds(free_space_percent_pd, measurement_unit.freespace_percent_thresholds);
1171
1172 freespace_percent_sc = mp_set_subcheck_state(freespace_percent_sc, mp_get_pd_status(free_space_percent_pd));
1173 mp_add_subcheck_to_subcheck(&result, freespace_percent_sc);
1174
1175 // ================
1176 // Free inodes test
1177 // Only ever useful if the number of inodes is static (e.g. ext4),
1178 // not when it is dynamic (e.g btrfs)
1179 // Assumption: if the total number of inodes == 0, we have such a case and just skip the test
1180 if (measurement_unit.inodes_total > 0) {
1181 mp_subcheck freeindodes_percent_sc = mp_subcheck_init();
1182 freeindodes_percent_sc = mp_set_subcheck_default_state(freeindodes_percent_sc, STATE_OK);
1183
1184 double free_inode_percentage = calculate_percent(measurement_unit.inodes_free, measurement_unit.inodes_total);
1185
1186 if (verbose > 0) {
1187 printf("free inode percentage computed: %g\n", free_inode_percentage);
1188 }
1189
1190 xasprintf(&freeindodes_percent_sc.output, "Inodes free: %g%% (%ju of %ju)", free_inode_percentage, measurement_unit.inodes_free,
1191 measurement_unit.inodes_total);
1192
1193 mp_perfdata inodes_pd = perfdata_init();
1194 xasprintf(&inodes_pd.label, "%s (inodes)", measurement_unit.name);
1195 inodes_pd = mp_set_pd_value(inodes_pd, measurement_unit.inodes_used);
1196 inodes_pd = mp_set_pd_max_value(inodes_pd, mp_create_pd_value(measurement_unit.inodes_total));
1197 inodes_pd = mp_set_pd_min_value(inodes_pd, mp_create_pd_value(0));
1198
1199 mp_thresholds absolut_inode_thresholds = measurement_unit.freeinodes_percent_thresholds;
1200
1201 if (absolut_inode_thresholds.critical_is_set) {
1202 absolut_inode_thresholds.critical =
1203 mp_range_multiply(absolut_inode_thresholds.critical, mp_create_pd_value(measurement_unit.inodes_total / 100));
1204 }
1205 if (absolut_inode_thresholds.warning_is_set) {
1206 absolut_inode_thresholds.warning =
1207 mp_range_multiply(absolut_inode_thresholds.warning, mp_create_pd_value(measurement_unit.inodes_total / 100));
1208 }
1209
1210 inodes_pd = mp_pd_set_thresholds(inodes_pd, absolut_inode_thresholds);
1211
1212 freeindodes_percent_sc = mp_set_subcheck_state(freeindodes_percent_sc, mp_get_pd_status(inodes_pd));
1213 if (display_inodes_perfdata) {
1214 mp_add_perfdata_to_subcheck(&freeindodes_percent_sc, inodes_pd);
1215 }
1216 mp_add_subcheck_to_subcheck(&result, freeindodes_percent_sc);
1217 }
1218
1219 return result;
1161} 1220}
diff --git a/plugins/check_disk.d/utils_disk.c b/plugins/check_disk.d/utils_disk.c
new file mode 100644
index 00000000..eec1282b
--- /dev/null
+++ b/plugins/check_disk.d/utils_disk.c
@@ -0,0 +1,517 @@
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 && dummy_match.rm_eo == len) {
130 return true;
131 }
132 }
133
134 return false;
135}
136
137bool np_seen_name(struct name_list *list, const char *name) {
138 for (struct name_list *iterator = list; iterator; iterator = iterator->next) {
139 if (!strcmp(iterator->name, name)) {
140 return true;
141 }
142 }
143 return false;
144}
145
146bool np_regex_match_mount_entry(struct mount_entry *me, regex_t *re) {
147 return ((regexec(re, me->me_devname, (size_t)0, NULL, 0) == 0) || (regexec(re, me->me_mountdir, (size_t)0, NULL, 0) == 0));
148}
149
150check_disk_config check_disk_config_init() {
151 check_disk_config tmp = {
152 .erronly = false,
153 .display_mntp = false,
154 .show_local_fs = false,
155 .stat_remote_fs = false,
156 .display_inodes_perfdata = false,
157
158 .exact_match = false,
159 .freespace_ignore_reserved = false,
160
161 .ignore_missing = false,
162 .path_ignored = false,
163
164 // FS Filters
165 .fs_exclude_list = NULL,
166 .fs_include_list = NULL,
167 .device_path_exclude_list = NULL,
168
169 // Actual filesystems paths to investigate
170 .path_select_list = filesystem_list_init(),
171
172 .mount_list = NULL,
173 .seen = NULL,
174
175 .display_unit = Humanized,
176 // .unit = MebiBytes,
177
178 .output_format_is_set = false,
179 };
180 return tmp;
181}
182
183char *get_unit_string(byte_unit_enum unit) {
184 switch (unit) {
185 case Bytes:
186 return "Bytes";
187 case KibiBytes:
188 return "KiB";
189 case MebiBytes:
190 return "MiB";
191 case GibiBytes:
192 return "GiB";
193 case TebiBytes:
194 return "TiB";
195 case PebiBytes:
196 return "PiB";
197 case ExbiBytes:
198 return "EiB";
199 case KiloBytes:
200 return "KB";
201 case MegaBytes:
202 return "MB";
203 case GigaBytes:
204 return "GB";
205 case TeraBytes:
206 return "TB";
207 case PetaBytes:
208 return "PB";
209 case ExaBytes:
210 return "EB";
211 default:
212 assert(false);
213 }
214}
215
216measurement_unit measurement_unit_init() {
217 measurement_unit tmp = {
218 .name = NULL,
219 .filesystem_type = NULL,
220 .is_group = false,
221
222 .freeinodes_percent_thresholds = mp_thresholds_init(),
223 .freespace_percent_thresholds = mp_thresholds_init(),
224 .freespace_bytes_thresholds = mp_thresholds_init(),
225
226 .free_bytes = 0,
227 .used_bytes = 0,
228 .total_bytes = 0,
229
230 .inodes_total = 0,
231 .inodes_free = 0,
232 .inodes_free_to_root = 0,
233 .inodes_used = 0,
234 };
235 return tmp;
236}
237
238// Add a given element to the list, memory for the new element is freshly allocated
239// Returns a pointer to new element
240measurement_unit_list *add_measurement_list(measurement_unit_list *list, measurement_unit elem) {
241 // find last element
242 measurement_unit_list *new = NULL;
243 if (list == NULL) {
244 new = calloc(1, sizeof(measurement_unit_list));
245 if (new == NULL) {
246 die(STATE_UNKNOWN, _("allocation failed"));
247 }
248 } else {
249 measurement_unit_list *list_elem = list;
250 while (list_elem->next != NULL) {
251 list_elem = list_elem->next;
252 }
253
254 new = calloc(1, sizeof(measurement_unit_list));
255 if (new == NULL) {
256 die(STATE_UNKNOWN, _("allocation failed"));
257 }
258
259 list_elem->next = new;
260 }
261
262 new->unit = elem;
263 new->next = NULL;
264 return new;
265}
266
267measurement_unit add_filesystem_to_measurement_unit(measurement_unit unit, parameter_list_elem filesystem) {
268
269 unit.free_bytes += filesystem.free_bytes;
270 unit.used_bytes += filesystem.used_bytes;
271 unit.total_bytes += filesystem.total_bytes;
272
273 unit.inodes_total += filesystem.inodes_total;
274 unit.inodes_free += filesystem.inodes_free;
275 unit.inodes_free_to_root += filesystem.inodes_free_to_root;
276 unit.inodes_used += filesystem.inodes_used;
277 return unit;
278}
279
280measurement_unit create_measurement_unit_from_filesystem(parameter_list_elem filesystem, bool display_mntp) {
281 measurement_unit result = measurement_unit_init();
282 if (!display_mntp) {
283 result.name = strdup(filesystem.best_match->me_mountdir);
284 } else {
285 result.name = strdup(filesystem.best_match->me_devname);
286 }
287
288 if (filesystem.group) {
289 result.is_group = true;
290 } else {
291 result.is_group = false;
292 if (filesystem.best_match) {
293 result.filesystem_type = filesystem.best_match->me_type;
294 }
295 }
296
297 result.freeinodes_percent_thresholds = filesystem.freeinodes_percent;
298 result.freespace_percent_thresholds = filesystem.freespace_percent;
299 result.freespace_bytes_thresholds = filesystem.freespace_units;
300 result.free_bytes = filesystem.free_bytes;
301 result.total_bytes = filesystem.total_bytes;
302 result.used_bytes = filesystem.used_bytes;
303 result.inodes_total = filesystem.inodes_total;
304 result.inodes_used = filesystem.inodes_used;
305 result.inodes_free = filesystem.inodes_free;
306 result.inodes_free_to_root = filesystem.inodes_free_to_root;
307 return result;
308}
309
310#define RANDOM_STRING_LENGTH 64
311
312char *humanize_byte_value(unsigned long long value, bool use_si_units) {
313 // Idea: A reasonable output should have at most 3 orders of magnitude
314 // before the decimal separator
315 // 353GiB is ok, 2444 GiB should be 2.386 TiB
316 char *result = calloc(RANDOM_STRING_LENGTH, sizeof(char));
317 if (result == NULL) {
318 die(STATE_UNKNOWN, _("allocation failed"));
319 }
320 const byte_unit KibiBytes_factor = 1024;
321 const byte_unit MebiBytes_factor = 1048576;
322 const byte_unit GibiBytes_factor = 1073741824;
323 const byte_unit TebiBytes_factor = 1099511627776;
324 const byte_unit PebiBytes_factor = 1125899906842624;
325 const byte_unit ExbiBytes_factor = 1152921504606846976;
326 const byte_unit KiloBytes_factor = 1000;
327 const byte_unit MegaBytes_factor = 1000000;
328 const byte_unit GigaBytes_factor = 1000000000;
329 const byte_unit TeraBytes_factor = 1000000000000;
330 const byte_unit PetaBytes_factor = 1000000000000000;
331 const byte_unit ExaBytes_factor = 1000000000000000000;
332
333 if (use_si_units) {
334 // SI units, powers of 10
335 if (value < KiloBytes_factor) {
336 snprintf(result, RANDOM_STRING_LENGTH, "%llu B", value);
337 } else if (value < MegaBytes_factor) {
338 snprintf(result, RANDOM_STRING_LENGTH, "%llu KB", value / KiloBytes_factor);
339 } else if (value < GigaBytes_factor) {
340 snprintf(result, RANDOM_STRING_LENGTH, "%llu MB", value / MegaBytes_factor);
341 } else if (value < TeraBytes_factor) {
342 snprintf(result, RANDOM_STRING_LENGTH, "%llu GB", value / GigaBytes_factor);
343 } else if (value < PetaBytes_factor) {
344 snprintf(result, RANDOM_STRING_LENGTH, "%llu TB", value / TeraBytes_factor);
345 } else if (value < ExaBytes_factor) {
346 snprintf(result, RANDOM_STRING_LENGTH, "%llu PB", value / PetaBytes_factor);
347 } else {
348 snprintf(result, RANDOM_STRING_LENGTH, "%llu EB", value / ExaBytes_factor);
349 }
350 } else {
351 // IEC units, powers of 2 ^ 10
352 if (value < KibiBytes_factor) {
353 snprintf(result, RANDOM_STRING_LENGTH, "%llu B", value);
354 } else if (value < MebiBytes_factor) {
355 snprintf(result, RANDOM_STRING_LENGTH, "%llu KiB", value / KibiBytes_factor);
356 } else if (value < GibiBytes_factor) {
357 snprintf(result, RANDOM_STRING_LENGTH, "%llu MiB", value / MebiBytes_factor);
358 } else if (value < TebiBytes_factor) {
359 snprintf(result, RANDOM_STRING_LENGTH, "%llu GiB", value / GibiBytes_factor);
360 } else if (value < PebiBytes_factor) {
361 snprintf(result, RANDOM_STRING_LENGTH, "%llu TiB", value / TebiBytes_factor);
362 } else if (value < ExbiBytes_factor) {
363 snprintf(result, RANDOM_STRING_LENGTH, "%llu PiB", value / PebiBytes_factor);
364 } else {
365 snprintf(result, RANDOM_STRING_LENGTH, "%llu EiB", value / ExbiBytes_factor);
366 }
367 }
368
369 return result;
370}
371
372filesystem_list filesystem_list_init() {
373 filesystem_list tmp = {
374 .length = 0,
375 .first = NULL,
376 };
377 return tmp;
378}
379
380parameter_list_elem *mp_int_fs_list_append(filesystem_list *list, const char *name) {
381 parameter_list_elem *current = list->first;
382 parameter_list_elem *new_path = (struct parameter_list *)malloc(sizeof *new_path);
383 *new_path = parameter_list_init(name);
384
385 if (current == NULL) {
386 list->first = new_path;
387 new_path->prev = NULL;
388 list->length = 1;
389 } else {
390 while (current->next) {
391 current = current->next;
392 }
393 current->next = new_path;
394 new_path->prev = current;
395 list->length++;
396 }
397 return new_path;
398}
399
400parameter_list_elem *mp_int_fs_list_find(filesystem_list list, const char *name) {
401 if (list.length == 0) {
402 return NULL;
403 }
404
405 for (parameter_list_elem *temp_list = list.first; temp_list; temp_list = temp_list->next) {
406 if (!strcmp(temp_list->name, name)) {
407 return temp_list;
408 }
409 }
410
411 return NULL;
412}
413
414parameter_list_elem *mp_int_fs_list_del(filesystem_list *list, parameter_list_elem *item) {
415 if (list->length == 0) {
416 return NULL;
417 }
418
419 if (item == NULL) {
420 // Got NULL for item, interpret this as "delete first element"
421 // as a kind of compatibility to the old function
422 item = list->first;
423 }
424
425 if (list->first == item) {
426 list->length--;
427
428 list->first = item->next;
429 if (list->first) {
430 list->first->prev = NULL;
431 }
432 return list->first;
433 }
434
435 // Was not the first element, continue
436 parameter_list_elem *prev = list->first;
437 parameter_list_elem *current = list->first->next;
438
439 while (current != item && current != NULL) {
440 prev = current;
441 current = current->next;
442 }
443
444 if (current == NULL) {
445 // didn't find that element ....
446 return NULL;
447 }
448
449 // remove the element
450 parameter_list_elem *next = current->next;
451 prev->next = next;
452 list->length--;
453 if (next) {
454 next->prev = prev;
455 }
456
457 if (item->name) {
458 free(item->name);
459 }
460 free(item);
461
462 return next;
463}
464
465parameter_list_elem *mp_int_fs_list_get_next(parameter_list_elem *current) {
466 if (!current) {
467 return NULL;
468 }
469 return current->next;
470}
471
472void mp_int_fs_list_set_best_match(filesystem_list list, struct mount_entry *mount_list, bool exact) {
473 for (parameter_list_elem *elem = list.first; elem; elem = mp_int_fs_list_get_next(elem)) {
474 if (!elem->best_match) {
475 size_t name_len = strlen(elem->name);
476 struct mount_entry *best_match = NULL;
477
478 /* set best match if path name exactly matches a mounted device name */
479 for (struct mount_entry *mount_entry = mount_list; mount_entry; mount_entry = mount_entry->me_next) {
480 if (strcmp(mount_entry->me_devname, elem->name) == 0) {
481 struct fs_usage fsp;
482 if (get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp) >= 0) {
483 best_match = mount_entry;
484 }
485 }
486 }
487
488 /* set best match by directory name if no match was found by devname */
489 if (!best_match) {
490 size_t best_match_len = 0;
491 for (struct mount_entry *mount_entry = mount_list; mount_entry; mount_entry = mount_entry->me_next) {
492 size_t len = strlen(mount_entry->me_mountdir);
493
494 if ((!exact && (best_match_len <= len && len <= name_len &&
495 (len == 1 || strncmp(mount_entry->me_mountdir, elem->name, len) == 0))) ||
496 (exact && strcmp(mount_entry->me_mountdir, elem->name) == 0)) {
497 struct fs_usage fsp;
498
499 if (get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp) >= 0) {
500 best_match = mount_entry;
501 best_match_len = len;
502 }
503 }
504 }
505 }
506
507 if (best_match) {
508 elem->best_match = best_match;
509 } else {
510 elem->best_match = NULL; /* Not sure why this is needed as it should be null on initialisation */
511 }
512
513 // No filesystem without a mount_entry!
514 // assert(elem->best_match != NULL);
515 }
516 }
517}
diff --git a/plugins/check_disk.d/utils_disk.h b/plugins/check_disk.d/utils_disk.h
new file mode 100644
index 00000000..6831d1fd
--- /dev/null
+++ b/plugins/check_disk.d/utils_disk.h
@@ -0,0 +1,157 @@
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, bool exact);
145
146measurement_unit measurement_unit_init();
147measurement_unit_list *add_measurement_list(measurement_unit_list *list, measurement_unit elem);
148measurement_unit add_filesystem_to_measurement_unit(measurement_unit unit, parameter_list_elem filesystem);
149measurement_unit create_measurement_unit_from_filesystem(parameter_list_elem filesystem, bool display_mntp);
150
151int search_parameter_list(parameter_list_elem *list, const char *name);
152bool np_regex_match_mount_entry(struct mount_entry *, regex_t *);
153
154char *get_unit_string(byte_unit_enum);
155check_disk_config check_disk_config_init();
156
157char *humanize_byte_value(unsigned long long value, bool use_si_units);
diff --git a/plugins/check_dns.c b/plugins/check_dns.c
index 468bc958..95f33083 100644
--- a/plugins/check_dns.c
+++ b/plugins/check_dns.c
@@ -1,36 +1,36 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_dns plugin 3 * Monitoring check_dns plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2008 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_dns plugin 10 * This file contains the check_dns plugin
11* 11 *
12* LIMITATION: nslookup on Solaris 7 can return output over 2 lines, which 12 * LIMITATION: nslookup on Solaris 7 can return output over 2 lines, which
13* will not be picked up by this plugin 13 * will not be picked up by this plugin
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 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 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 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 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/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_dns"; 32const char *progname = "check_dns";
33const char *copyright = "2000-2008"; 33const char *copyright = "2000-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "common.h" 36#include "common.h"
@@ -39,579 +39,591 @@ const char *email = "devel@monitoring-plugins.org";
39#include "netutils.h" 39#include "netutils.h"
40#include "runcmd.h" 40#include "runcmd.h"
41 41
42int process_arguments (int, char **); 42#include "states.h"
43int validate_arguments (void); 43#include "check_dns.d/config.h"
44int error_scan (char *, bool *); 44
45bool ip_match_cidr(const char *, const char *); 45typedef struct {
46unsigned long ip2long(const char *); 46 int errorcode;
47void print_help (void); 47 check_dns_config config;
48void print_usage (void); 48} check_dns_config_wrapper;
49 49static check_dns_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
50#define ADDRESS_LENGTH 256 50static check_dns_config_wrapper validate_arguments(check_dns_config_wrapper /*config_wrapper*/);
51char query_address[ADDRESS_LENGTH] = ""; 51static mp_state_enum error_scan(char * /*input_buffer*/, bool * /*is_nxdomain*/, const char /*dns_server*/[ADDRESS_LENGTH]);
52char dns_server[ADDRESS_LENGTH] = ""; 52static bool ip_match_cidr(const char * /*addr*/, const char * /*cidr_ro*/);
53char ptr_server[ADDRESS_LENGTH] = ""; 53static unsigned long ip2long(const char * /*src*/);
54bool verbose = false; 54static void print_help(void);
55char **expected_address = NULL; 55void print_usage(void);
56int expected_address_cnt = 0; 56
57bool expect_nxdomain = false; 57static bool verbose = false;
58 58
59bool expect_authority = false; 59static int qstrcmp(const void *p1, const void *p2) {
60bool all_match = false;
61thresholds *time_thresholds = NULL;
62
63static int
64qstrcmp(const void *p1, const void *p2)
65{
66 /* The actual arguments to this function are "pointers to 60 /* The actual arguments to this function are "pointers to
67 pointers to char", but strcmp() arguments are "pointers 61 pointers to char", but strcmp() arguments are "pointers
68 to char", hence the following cast plus dereference */ 62 to char", hence the following cast plus dereference */
69 return strcmp(* (char * const *) p1, * (char * const *) p2); 63 return strcmp(*(char *const *)p1, *(char *const *)p2);
70} 64}
71 65
66int main(int argc, char **argv) {
67 setlocale(LC_ALL, "");
68 bindtextdomain(PACKAGE, LOCALEDIR);
69 textdomain(PACKAGE);
70
71 /* Set signal handling and alarm */
72 if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
73 usage_va(_("Cannot catch SIGALRM"));
74 }
75
76 /* Parse extra opts if any */
77 argv = np_extra_opts(&argc, argv, progname);
78
79 check_dns_config_wrapper tmp = process_arguments(argc, argv);
80
81 if (tmp.errorcode == ERROR) {
82 usage_va(_("Could not parse arguments"));
83 }
84
85 const check_dns_config config = tmp.config;
86
87 char *command_line = NULL;
88 /* get the command to run */
89 xasprintf(&command_line, "%s %s %s", NSLOOKUP_COMMAND, config.query_address, config.dns_server);
90
91 struct timeval tv;
92 alarm(timeout_interval);
93 gettimeofday(&tv, NULL);
94
95 if (verbose) {
96 printf("%s\n", command_line);
97 }
98
99 output chld_out;
100 output chld_err;
101 char *msg = NULL;
102 mp_state_enum result = STATE_UNKNOWN;
103 /* run the command */
104 if ((np_runcmd(command_line, &chld_out, &chld_err, 0)) != 0) {
105 msg = (char *)_("nslookup returned an error status");
106 result = STATE_WARNING;
107 }
108
109 /* =====
110 * scan stdout, main results get retrieved here
111 * =====
112 */
113 char *address = NULL; /* comma separated str with addrs/ptrs (sorted) */
114 char **addresses = NULL; // All addresses parsed from stdout
115 size_t n_addresses = 0; // counter for retrieved addresses
116 bool non_authoritative = false;
117 bool is_nxdomain = false;
118 bool parse_address = false; /* This flag scans for Address: but only after Name: */
119 for (size_t i = 0; i < chld_out.lines; i++) {
120 if (addresses == NULL) {
121 addresses = malloc(sizeof(*addresses) * 10);
122 } else if (!(n_addresses % 10)) {
123 addresses = realloc(addresses, sizeof(*addresses) * (n_addresses + 10));
124 }
125
126 if (verbose) {
127 puts(chld_out.line[i]);
128 }
129
130 if (strcasestr(chld_out.line[i], ".in-addr.arpa") || strcasestr(chld_out.line[i], ".ip6.arpa")) {
131 if ((strstr(chld_out.line[i], "canonical name = ") != NULL)) {
132 continue;
133 }
134 char *temp_buffer = NULL;
135 if ((temp_buffer = strstr(chld_out.line[i], "name = "))) {
136 addresses[n_addresses++] = strdup(temp_buffer + 7);
137 } else {
138 msg = (char *)_("Warning plugin error");
139 result = STATE_WARNING;
140 }
141 }
142
143 /* bug ID: 2946553 - Older versions of bind will use all available dns
144 servers, we have to match the one specified */
145 if (strstr(chld_out.line[i], "Server:") && strlen(config.dns_server) > 0) {
146 char *temp_buffer = strchr(chld_out.line[i], ':');
147 if (temp_buffer == NULL) {
148 die(STATE_UNKNOWN, _("'%s' returned a weirdly formatted Server line\n"), NSLOOKUP_COMMAND);
149 }
150
151 temp_buffer++;
152
153 /* Strip leading tabs */
154 for (; *temp_buffer != '\0' && *temp_buffer == '\t'; temp_buffer++) {
155 /* NOOP */;
156 }
157
158 strip(temp_buffer);
159 if (strlen(temp_buffer) == 0) {
160 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty server string\n"), NSLOOKUP_COMMAND);
161 }
162
163 if (strcmp(temp_buffer, config.dns_server) != 0) {
164 die(STATE_CRITICAL, _("DNS CRITICAL - No response from DNS %s\n"), config.dns_server);
165 }
166 }
167
168 /* the server is responding, we just got the host name... */
169 if (strstr(chld_out.line[i], "Name:")) {
170 parse_address = true;
171 } else if (parse_address && (strstr(chld_out.line[i], "Address:") || strstr(chld_out.line[i], "Addresses:"))) {
172 char *temp_buffer = strchr(chld_out.line[i], ':');
173 if (temp_buffer == NULL) {
174 die(STATE_UNKNOWN, _("'%s' returned a weirdly formatted Address line\n"), NSLOOKUP_COMMAND);
175 }
176
177 temp_buffer++;
178
179 /* Strip leading spaces */
180 while (*temp_buffer == ' ') {
181 temp_buffer++;
182 }
183
184 strip(temp_buffer);
185 if (strlen(temp_buffer) == 0) {
186 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty host name string\n"), NSLOOKUP_COMMAND);
187 }
188
189 addresses[n_addresses++] = strdup(temp_buffer);
190 } else if (strstr(chld_out.line[i], _("Non-authoritative answer:"))) {
191 non_authoritative = true;
192 }
193
194 result = error_scan(chld_out.line[i], &is_nxdomain, config.dns_server);
195 if (result != STATE_OK) {
196 msg = strchr(chld_out.line[i], ':');
197 if (msg) {
198 msg++;
199 }
200 break;
201 }
202 }
203
204 char input_buffer[MAX_INPUT_BUFFER];
205 /* scan stderr */
206 for (size_t i = 0; i < chld_err.lines; i++) {
207 if (verbose) {
208 puts(chld_err.line[i]);
209 }
210
211 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));
213 msg = strchr(input_buffer, ':');
214 if (msg) {
215 msg++;
216 } else {
217 msg = input_buffer;
218 }
219 }
220 }
221
222 if (is_nxdomain && !config.expect_nxdomain) {
223 die(STATE_CRITICAL, _("Domain '%s' was not found by the server\n"), config.query_address);
224 }
225
226 if (addresses) {
227 size_t slen = 1;
228 char *adrp = NULL;
229 qsort(addresses, n_addresses, sizeof(*addresses), qstrcmp);
230 for (size_t i = 0; i < n_addresses; i++) {
231 slen += strlen(addresses[i]) + 1;
232 }
233
234 // Temporary pointer adrp gets moved, address stays on the beginning
235 adrp = address = malloc(slen);
236 for (size_t i = 0; i < n_addresses; i++) {
237 if (i) {
238 *adrp++ = ',';
239 }
240 strcpy(adrp, addresses[i]);
241 adrp += strlen(addresses[i]);
242 }
243 *adrp = 0;
244 } else {
245 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' msg parsing exited with no address\n"), NSLOOKUP_COMMAND);
246 }
247
248 /* compare to expected address */
249 if (result == STATE_OK && config.expected_address_cnt > 0) {
250 result = STATE_CRITICAL;
251 char *temp_buffer = "";
252 unsigned long expect_match = (1 << config.expected_address_cnt) - 1;
253 unsigned long addr_match = (1 << n_addresses) - 1;
254
255 for (size_t i = 0; i < config.expected_address_cnt; i++) {
256 /* check if we get a match on 'raw' ip or cidr */
257 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])) {
259 result = STATE_OK;
260 addr_match &= ~(1 << j);
261 expect_match &= ~(1 << i);
262 }
263 }
264
265 /* prepare an error string */
266 xasprintf(&temp_buffer, "%s%s; ", temp_buffer, config.expected_address[i]);
267 }
268 /* check if expected_address must cover all in addresses and none may be missing */
269 if (config.all_match && (expect_match != 0 || addr_match != 0)) {
270 result = STATE_CRITICAL;
271 }
272 if (result == STATE_CRITICAL) {
273 /* Strip off last semicolon... */
274 temp_buffer[strlen(temp_buffer) - 2] = '\0';
275 xasprintf(&msg, _("expected '%s' but got '%s'"), temp_buffer, address);
276 }
277 }
278
279 if (config.expect_nxdomain) {
280 if (!is_nxdomain) {
281 result = STATE_CRITICAL;
282 xasprintf(&msg, _("Domain '%s' was found by the server: '%s'\n"), config.query_address, address);
283 } else {
284 if (address != NULL) {
285 free(address);
286 }
287 address = "NXDOMAIN";
288 }
289 }
290
291 /* check if authoritative */
292 if (result == STATE_OK && config.expect_authority && non_authoritative) {
293 result = STATE_CRITICAL;
294 xasprintf(&msg, _("server %s is not authoritative for %s"), config.dns_server, config.query_address);
295 }
296
297 long microsec = deltime(tv);
298 double elapsed_time = (double)microsec / 1.0e6;
299
300 if (result == STATE_OK) {
301 result = get_status(elapsed_time, config.time_thresholds);
302 if (result == STATE_OK) {
303 printf("DNS %s: ", _("OK"));
304 } else if (result == STATE_WARNING) {
305 printf("DNS %s: ", _("WARNING"));
306 } else if (result == STATE_CRITICAL) {
307 printf("DNS %s: ", _("CRITICAL"));
308 }
309 printf(ngettext("%.3f second response time", "%.3f seconds response time", elapsed_time), elapsed_time);
310 printf(_(". %s returns %s"), config.query_address, address);
311 if ((config.time_thresholds->warning != NULL) && (config.time_thresholds->critical != NULL)) {
312 printf("|%s\n", fperfdata("time", elapsed_time, "s", true, config.time_thresholds->warning->end, true,
313 config.time_thresholds->critical->end, true, 0, false, 0));
314 } else if ((config.time_thresholds->warning == NULL) && (config.time_thresholds->critical != NULL)) {
315 printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, true, config.time_thresholds->critical->end, true, 0, false, 0));
316 } else if ((config.time_thresholds->warning != NULL) && (config.time_thresholds->critical == NULL)) {
317 printf("|%s\n", fperfdata("time", elapsed_time, "s", true, config.time_thresholds->warning->end, false, 0, true, 0, false, 0));
318 } else {
319 printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, false, 0, true, 0, false, 0));
320 }
321 } else if (result == STATE_WARNING) {
322 printf(_("DNS WARNING - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
323 } else if (result == STATE_CRITICAL) {
324 printf(_("DNS CRITICAL - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
325 } else {
326 printf(_("DNS UNKNOWN - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
327 }
72 328
73int 329 exit(result);
74main (int argc, char **argv)
75{
76 char *command_line = NULL;
77 char input_buffer[MAX_INPUT_BUFFER];
78 char *address = NULL; /* comma separated str with addrs/ptrs (sorted) */
79 char **addresses = NULL;
80 int n_addresses = 0;
81 char *msg = NULL;
82 char *temp_buffer = NULL;
83 bool non_authoritative = false;
84 int result = STATE_UNKNOWN;
85 double elapsed_time;
86 long microsec;
87 struct timeval tv;
88 bool parse_address = false; /* This flag scans for Address: but only after Name: */
89 output chld_out, chld_err;
90 bool is_nxdomain = false;
91
92 setlocale (LC_ALL, "");
93 bindtextdomain (PACKAGE, LOCALEDIR);
94 textdomain (PACKAGE);
95
96 /* Set signal handling and alarm */
97 if (signal (SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
98 usage_va(_("Cannot catch SIGALRM"));
99 }
100
101 /* Parse extra opts if any */
102 argv=np_extra_opts (&argc, argv, progname);
103
104 if (process_arguments (argc, argv) == ERROR) {
105 usage_va(_("Could not parse arguments"));
106 }
107
108 /* get the command to run */
109 xasprintf (&command_line, "%s %s %s", NSLOOKUP_COMMAND, query_address, dns_server);
110
111 alarm (timeout_interval);
112 gettimeofday (&tv, NULL);
113
114 if (verbose)
115 printf ("%s\n", command_line);
116
117 /* run the command */
118 if((np_runcmd(command_line, &chld_out, &chld_err, 0)) != 0) {
119 msg = (char *)_("nslookup returned an error status");
120 result = STATE_WARNING;
121 }
122
123 /* scan stdout */
124 for(size_t i = 0; i < chld_out.lines; i++) {
125 if (addresses == NULL)
126 addresses = malloc(sizeof(*addresses)*10);
127 else if (!(n_addresses % 10))
128 addresses = realloc(addresses,sizeof(*addresses) * (n_addresses + 10));
129
130 if (verbose)
131 puts(chld_out.line[i]);
132
133 if (strcasestr (chld_out.line[i], ".in-addr.arpa") || strcasestr (chld_out.line[i], ".ip6.arpa")) {
134 if ((temp_buffer = strstr (chld_out.line[i], "name = ")))
135 addresses[n_addresses++] = strdup (temp_buffer + 7);
136 else {
137 msg = (char *)_("Warning plugin error");
138 result = STATE_WARNING;
139 }
140 }
141
142 /* bug ID: 2946553 - Older versions of bind will use all available dns
143 servers, we have to match the one specified */
144 if (strstr (chld_out.line[i], "Server:") && strlen(dns_server) > 0) {
145 temp_buffer = strchr (chld_out.line[i], ':');
146 temp_buffer++;
147
148 /* Strip leading tabs */
149 for (; *temp_buffer != '\0' && *temp_buffer == '\t'; temp_buffer++)
150 /* NOOP */;
151
152 strip(temp_buffer);
153 if (temp_buffer==NULL || strlen(temp_buffer)==0) {
154 die (STATE_CRITICAL,
155 _("DNS CRITICAL - '%s' returned empty server string\n"),
156 NSLOOKUP_COMMAND);
157 }
158
159 if (strcmp(temp_buffer, dns_server) != 0) {
160 die (STATE_CRITICAL, _("DNS CRITICAL - No response from DNS %s\n"), dns_server);
161 }
162 }
163
164 /* the server is responding, we just got the host name... */
165 if (strstr (chld_out.line[i], "Name:"))
166 parse_address = true;
167 else if (parse_address && (strstr (chld_out.line[i], "Address:") ||
168 strstr (chld_out.line[i], "Addresses:"))) {
169 temp_buffer = index (chld_out.line[i], ':');
170 temp_buffer++;
171
172 /* Strip leading spaces */
173 while (*temp_buffer == ' ')
174 temp_buffer++;
175
176 strip(temp_buffer);
177 if (temp_buffer==NULL || strlen(temp_buffer)==0) {
178 die (STATE_CRITICAL,
179 _("DNS CRITICAL - '%s' returned empty host name string\n"),
180 NSLOOKUP_COMMAND);
181 }
182
183 addresses[n_addresses++] = strdup(temp_buffer);
184 }
185 else if (strstr (chld_out.line[i], _("Non-authoritative answer:"))) {
186 non_authoritative = true;
187 }
188
189
190 result = error_scan (chld_out.line[i], &is_nxdomain);
191 if (result != STATE_OK) {
192 msg = strchr (chld_out.line[i], ':');
193 if(msg) msg++;
194 break;
195 }
196 }
197
198 /* scan stderr */
199 for(size_t i = 0; i < chld_err.lines; i++) {
200 if (verbose)
201 puts(chld_err.line[i]);
202
203 if (error_scan (chld_err.line[i], &is_nxdomain) != STATE_OK) {
204 result = max_state (result, error_scan (chld_err.line[i], &is_nxdomain));
205 msg = strchr(input_buffer, ':');
206 if(msg)
207 msg++;
208 else
209 msg = input_buffer;
210 }
211 }
212
213 if (is_nxdomain && !expect_nxdomain) {
214 die (STATE_CRITICAL, _("Domain '%s' was not found by the server\n"), query_address);
215 }
216
217 if (addresses) {
218 int i,slen;
219 char *adrp;
220 qsort(addresses, n_addresses, sizeof(*addresses), qstrcmp);
221 for(i=0, slen=1; i < n_addresses; i++) {
222 slen += strlen(addresses[i])+1;
223 }
224 adrp = address = malloc(slen);
225 for(i=0; i < n_addresses; i++) {
226 if (i) *adrp++ = ',';
227 strcpy(adrp, addresses[i]);
228 adrp += strlen(addresses[i]);
229 }
230 *adrp = 0;
231 } else
232 die (STATE_CRITICAL,
233 _("DNS CRITICAL - '%s' msg parsing exited with no address\n"),
234 NSLOOKUP_COMMAND);
235
236 /* compare to expected address */
237 if (result == STATE_OK && expected_address_cnt > 0) {
238 result = STATE_CRITICAL;
239 temp_buffer = "";
240 unsigned long expect_match = (1 << expected_address_cnt) - 1;
241 unsigned long addr_match = (1 << n_addresses) - 1;
242
243 for (int i=0; i<expected_address_cnt; i++) {
244 int j;
245 /* check if we get a match on 'raw' ip or cidr */
246 for (j=0; j<n_addresses; j++) {
247 if ( strcmp(addresses[j], expected_address[i]) == 0
248 || ip_match_cidr(addresses[j], expected_address[i]) ) {
249 result = STATE_OK;
250 addr_match &= ~(1 << j);
251 expect_match &= ~(1 << i);
252 }
253 }
254
255 /* prepare an error string */
256 xasprintf(&temp_buffer, "%s%s; ", temp_buffer, expected_address[i]);
257 }
258 /* check if expected_address must cover all in addresses and none may be missing */
259 if (all_match && (expect_match != 0 || addr_match != 0))
260 result = STATE_CRITICAL;
261 if (result == STATE_CRITICAL) {
262 /* Strip off last semicolon... */
263 temp_buffer[strlen(temp_buffer)-2] = '\0';
264 xasprintf(&msg, _("expected '%s' but got '%s'"), temp_buffer, address);
265 }
266 }
267
268 if (expect_nxdomain) {
269 if (!is_nxdomain) {
270 result = STATE_CRITICAL;
271 xasprintf(&msg, _("Domain '%s' was found by the server: '%s'\n"), query_address, address);
272 } else {
273 if (address != NULL) free(address);
274 address = "NXDOMAIN";
275 }
276 }
277
278 /* check if authoritative */
279 if (result == STATE_OK && expect_authority && non_authoritative) {
280 result = STATE_CRITICAL;
281 xasprintf(&msg, _("server %s is not authoritative for %s"), dns_server, query_address);
282 }
283
284 microsec = deltime (tv);
285 elapsed_time = (double)microsec / 1.0e6;
286
287 if (result == STATE_OK) {
288 result = get_status(elapsed_time, time_thresholds);
289 if (result == STATE_OK) {
290 printf ("DNS %s: ", _("OK"));
291 } else if (result == STATE_WARNING) {
292 printf ("DNS %s: ", _("WARNING"));
293 } else if (result == STATE_CRITICAL) {
294 printf ("DNS %s: ", _("CRITICAL"));
295 }
296 printf (ngettext("%.3f second response time", "%.3f seconds response time", elapsed_time), elapsed_time);
297 printf (_(". %s returns %s"), query_address, address);
298 if ((time_thresholds->warning != NULL) && (time_thresholds->critical != NULL)) {
299 printf ("|%s\n", fperfdata ("time", elapsed_time, "s",
300 true, time_thresholds->warning->end,
301 true, time_thresholds->critical->end,
302 true, 0, false, 0));
303 } else if ((time_thresholds->warning == NULL) && (time_thresholds->critical != NULL)) {
304 printf ("|%s\n", fperfdata ("time", elapsed_time, "s",
305 false, 0,
306 true, time_thresholds->critical->end,
307 true, 0, false, 0));
308 } else if ((time_thresholds->warning != NULL) && (time_thresholds->critical == NULL)) {
309 printf ("|%s\n", fperfdata ("time", elapsed_time, "s",
310 true, time_thresholds->warning->end,
311 false, 0,
312 true, 0, false, 0));
313 } else
314 printf ("|%s\n", fperfdata ("time", elapsed_time, "s", false, 0, false, 0, true, 0, false, 0));
315 }
316 else if (result == STATE_WARNING)
317 printf (_("DNS WARNING - %s\n"),
318 !strcmp (msg, "") ? _(" Probably a non-existent host/domain") : msg);
319 else if (result == STATE_CRITICAL)
320 printf (_("DNS CRITICAL - %s\n"),
321 !strcmp (msg, "") ? _(" Probably a non-existent host/domain") : msg);
322 else
323 printf (_("DNS UNKNOWN - %s\n"),
324 !strcmp (msg, "") ? _(" Probably a non-existent host/domain") : msg);
325
326 return result;
327} 330}
328 331
329bool ip_match_cidr(const char *addr, const char *cidr_ro) { 332bool ip_match_cidr(const char *addr, const char *cidr_ro) {
330 char *subnet, *mask_c, *cidr = strdup(cidr_ro); 333 char *subnet;
331 int mask; 334 char *mask_c;
332 subnet = strtok(cidr, "/"); 335 char *cidr = strdup(cidr_ro);
333 mask_c = strtok(NULL, "\0"); 336 int mask;
334 if (!subnet || !mask_c) { 337 subnet = strtok(cidr, "/");
335 return false; 338 mask_c = strtok(NULL, "\0");
339 if (!subnet || !mask_c) {
340 return false;
336 } 341 }
337 mask = atoi(mask_c); 342 mask = atoi(mask_c);
338 343
339 /* https://www.cryptobells.com/verifying-ips-in-a-subnet-in-php/ */ 344 /* https://www.cryptobells.com/verifying-ips-in-a-subnet-in-php/ */
340 return (ip2long(addr) & ~((1 << (32 - mask)) - 1)) == (ip2long(subnet) >> (32 - mask)) << (32 - mask); 345 return (ip2long(addr) & ~((1 << (32 - mask)) - 1)) == (ip2long(subnet) >> (32 - mask)) << (32 - mask);
341} 346}
342 347
343unsigned long 348unsigned long ip2long(const char *src) {
344ip2long(const char* src) { 349 unsigned long ip[4];
345 unsigned long ip[4]; 350 /* http://computer-programming-forum.com/47-c-language/1376ffb92a12c471.htm */
346 /* 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 &&
347 return (sscanf(src, "%3lu.%3lu.%3lu.%3lu", 352 ip[3] < 256)
348 &ip[0], &ip[1], &ip[2], &ip[3]) == 4 && 353 ? ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3]
349 ip[0] < 256 && ip[1] < 256 && 354 : 0;
350 ip[2] < 256 && ip[3] < 256)
351 ? ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3]
352 : 0;
353} 355}
354 356
355int 357mp_state_enum error_scan(char *input_buffer, bool *is_nxdomain, const char dns_server[ADDRESS_LENGTH]) {
356error_scan (char *input_buffer, bool *is_nxdomain)
357{
358
359 const int nxdomain = strstr (input_buffer, "Non-existent") ||
360 strstr (input_buffer, "** server can't find") ||
361 strstr (input_buffer, "** Can't find") ||
362 strstr (input_buffer, "NXDOMAIN");
363 if (nxdomain) *is_nxdomain = true;
364
365 /* the DNS lookup timed out */
366 if (strstr (input_buffer, _("Note: nslookup is deprecated and may be removed from future releases.")) ||
367 strstr (input_buffer, _("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.")))
369 return STATE_OK;
370
371 /* DNS server is not running... */
372 else if (strstr (input_buffer, "No response from server"))
373 die (STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
374 else if (strstr (input_buffer, "no servers could be reached"))
375 die (STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
376
377 /* Host name is valid, but server doesn't have records... */
378 else if (strstr (input_buffer, "No records"))
379 die (STATE_CRITICAL, _("DNS %s has no records\n"), dns_server);
380
381 /* Connection was refused */
382 else if (strstr (input_buffer, "Connection refused") ||
383 strstr (input_buffer, "Couldn't find server") ||
384 strstr (input_buffer, "Refused") ||
385 (strstr (input_buffer, "** server can't find") &&
386 strstr (input_buffer, ": REFUSED")))
387 die (STATE_CRITICAL, _("Connection to DNS %s was refused\n"), dns_server);
388
389 /* Query refused (usually by an ACL in the namserver) */
390 else if (strstr (input_buffer, "Query refused"))
391 die (STATE_CRITICAL, _("Query was refused by DNS server at %s\n"), dns_server);
392
393 /* No information (e.g. nameserver IP has two PTR records) */
394 else if (strstr (input_buffer, "No information"))
395 die (STATE_CRITICAL, _("No information returned by DNS server at %s\n"), dns_server);
396
397 /* Network is unreachable */
398 else if (strstr (input_buffer, "Network is unreachable"))
399 die (STATE_CRITICAL, _("Network is unreachable\n"));
400
401 /* Internal server failure */
402 else if (strstr (input_buffer, "Server failure"))
403 die (STATE_CRITICAL, _("DNS failure for %s\n"), dns_server);
404
405 /* Request error or the DNS lookup timed out */
406 else if (strstr (input_buffer, "Format error") ||
407 strstr (input_buffer, "Timed out"))
408 return STATE_WARNING;
409
410 return STATE_OK;
411 358
412} 359 const int nxdomain = strstr(input_buffer, "Non-existent") || strstr(input_buffer, "** server can't find") ||
360 strstr(input_buffer, "** Can't find") || strstr(input_buffer, "NXDOMAIN");
361 if (nxdomain) {
362 *is_nxdomain = true;
363 }
413 364
365 /* the DNS lookup timed out */
366 if (strstr(input_buffer, _("Note: nslookup is deprecated and may be removed from future releases.")) ||
367 strstr(input_buffer, _("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."))) {
369 return STATE_OK;
370 }
414 371
415/* process command-line arguments */ 372 /* DNS server is not running... */
416int 373 else if (strstr(input_buffer, "No response from server")) {
417process_arguments (int argc, char **argv) 374 die(STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
418{ 375 } else if (strstr(input_buffer, "no servers could be reached")) {
419 int c; 376 die(STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
420 char *warning = NULL; 377 }
421 char *critical = NULL; 378
422 379 /* Host name is valid, but server doesn't have records... */
423 int opt_index = 0; 380 else if (strstr(input_buffer, "No records")) {
424 static struct option long_opts[] = { 381 die(STATE_CRITICAL, _("DNS %s has no records\n"), dns_server);
425 {"help", no_argument, 0, 'h'}, 382 }
426 {"version", no_argument, 0, 'V'}, 383
427 {"verbose", no_argument, 0, 'v'}, 384 /* Connection was refused */
428 {"timeout", required_argument, 0, 't'}, 385 else if (strstr(input_buffer, "Connection refused") || strstr(input_buffer, "Couldn't find server") ||
429 {"hostname", required_argument, 0, 'H'}, 386 strstr(input_buffer, "Refused") || (strstr(input_buffer, "** server can't find") && strstr(input_buffer, ": REFUSED"))) {
430 {"server", required_argument, 0, 's'}, 387 die(STATE_CRITICAL, _("Connection to DNS %s was refused\n"), dns_server);
431 {"reverse-server", required_argument, 0, 'r'}, 388 }
432 {"expected-address", required_argument, 0, 'a'}, 389
433 {"expect-nxdomain", no_argument, 0, 'n'}, 390 /* Query refused (usually by an ACL in the namserver) */
434 {"expect-authority", no_argument, 0, 'A'}, 391 else if (strstr(input_buffer, "Query refused")) {
435 {"all", no_argument, 0, 'L'}, 392 die(STATE_CRITICAL, _("Query was refused by DNS server at %s\n"), dns_server);
436 {"warning", required_argument, 0, 'w'}, 393 }
437 {"critical", required_argument, 0, 'c'}, 394
438 {0, 0, 0, 0} 395 /* No information (e.g. nameserver IP has two PTR records) */
439 }; 396 else if (strstr(input_buffer, "No information")) {
440 397 die(STATE_CRITICAL, _("No information returned by DNS server at %s\n"), dns_server);
441 if (argc < 2) 398 }
442 return ERROR; 399
443 400 /* Network is unreachable */
444 for (c = 1; c < argc; c++) 401 else if (strstr(input_buffer, "Network is unreachable")) {
445 if (strcmp ("-to", argv[c]) == 0) 402 die(STATE_CRITICAL, _("Network is unreachable\n"));
446 strcpy (argv[c], "-t"); 403 }
447 404
448 while (1) { 405 /* Internal server failure */
449 c = getopt_long (argc, argv, "hVvALnt:H:s:r:a:w:c:", long_opts, &opt_index); 406 else if (strstr(input_buffer, "Server failure")) {
450 407 die(STATE_CRITICAL, _("DNS failure for %s\n"), dns_server);
451 if (c == -1 || c == EOF)
452 break;
453
454 switch (c) {
455 case 'h': /* help */
456 print_help ();
457 exit (STATE_UNKNOWN);
458 case 'V': /* version */
459 print_revision (progname, NP_VERSION);
460 exit (STATE_UNKNOWN);
461 case 'v': /* version */
462 verbose = true;
463 break;
464 case 't': /* timeout period */
465 timeout_interval = atoi (optarg);
466 break;
467 case 'H': /* hostname */
468 if (strlen (optarg) >= ADDRESS_LENGTH)
469 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
470 strcpy (query_address, optarg);
471 break;
472 case 's': /* server name */
473 /* TODO: this host_or_die check is probably unnecessary.
474 * Better to confirm nslookup response matches */
475 host_or_die(optarg);
476 if (strlen (optarg) >= ADDRESS_LENGTH)
477 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
478 strcpy (dns_server, optarg);
479 break;
480 case 'r': /* reverse server name */
481 /* TODO: Is this host_or_die necessary? */
482 host_or_die(optarg);
483 if (strlen (optarg) >= ADDRESS_LENGTH)
484 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
485 strcpy (ptr_server, optarg);
486 break;
487 case 'a': /* expected address */
488 if (strlen (optarg) >= ADDRESS_LENGTH)
489 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
490 if (strchr(optarg, ',') != NULL) {
491 char *comma = strchr(optarg, ',');
492 while (comma != NULL) {
493 expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**));
494 expected_address[expected_address_cnt] = strndup(optarg, comma - optarg);
495 expected_address_cnt++;
496 optarg = comma + 1;
497 comma = strchr(optarg, ',');
498 } 408 }
499 expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**)); 409
500 expected_address[expected_address_cnt] = strdup(optarg); 410 /* Request error or the DNS lookup timed out */
501 expected_address_cnt++; 411 else if (strstr(input_buffer, "Format error") || strstr(input_buffer, "Timed out")) {
502 } else { 412 return STATE_WARNING;
503 expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**)); 413 }
504 expected_address[expected_address_cnt] = strdup(optarg); 414
505 expected_address_cnt++; 415 return STATE_OK;
506 }
507 break;
508 case 'n': /* expect NXDOMAIN */
509 expect_nxdomain = true;
510 break;
511 case 'A': /* expect authority */
512 expect_authority = true;
513 break;
514 case 'L': /* all must match */
515 all_match = true;
516 break;
517 case 'w':
518 warning = optarg;
519 break;
520 case 'c':
521 critical = optarg;
522 break;
523 default: /* args not parsable */
524 usage5();
525 }
526 }
527
528 c = optind;
529 if (strlen(query_address)==0 && c<argc) {
530 if (strlen(argv[c])>=ADDRESS_LENGTH)
531 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
532 strcpy (query_address, argv[c++]);
533 }
534
535 if (strlen(dns_server)==0 && c<argc) {
536 /* TODO: See -s option */
537 host_or_die(argv[c]);
538 if (strlen(argv[c]) >= ADDRESS_LENGTH)
539 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
540 strcpy (dns_server, argv[c++]);
541 }
542
543 set_thresholds(&time_thresholds, warning, critical);
544
545 return validate_arguments ();
546} 416}
547 417
418/* process command-line arguments */
419check_dns_config_wrapper process_arguments(int argc, char **argv) {
420 static struct option long_opts[] = {{"help", no_argument, 0, 'h'},
421 {"version", no_argument, 0, 'V'},
422 {"verbose", no_argument, 0, 'v'},
423 {"timeout", required_argument, 0, 't'},
424 {"hostname", required_argument, 0, 'H'},
425 {"server", required_argument, 0, 's'},
426 {"reverse-server", required_argument, 0, 'r'},
427 {"expected-address", required_argument, 0, 'a'},
428 {"expect-nxdomain", no_argument, 0, 'n'},
429 {"expect-authority", no_argument, 0, 'A'},
430 {"all", no_argument, 0, 'L'},
431 {"warning", required_argument, 0, 'w'},
432 {"critical", required_argument, 0, 'c'},
433 {0, 0, 0, 0}};
434
435 check_dns_config_wrapper result = {
436 .config = check_dns_config_init(),
437 .errorcode = OK,
438 };
439
440 if (argc < 2) {
441 result.errorcode = ERROR;
442 return result;
443 }
444
445 for (int index = 1; index < argc; index++) {
446 if (strcmp("-to", argv[index]) == 0) {
447 strcpy(argv[index], "-t");
448 }
449 }
450
451 char *warning = NULL;
452 char *critical = NULL;
453 int opt_index = 0;
454 int index = 0;
455 while (true) {
456 index = getopt_long(argc, argv, "hVvALnt:H:s:r:a:w:c:", long_opts, &opt_index);
457
458 if (index == -1 || index == EOF) {
459 break;
460 }
461
462 switch (index) {
463 case 'h': /* help */
464 print_help();
465 exit(STATE_UNKNOWN);
466 case 'V': /* version */
467 print_revision(progname, NP_VERSION);
468 exit(STATE_UNKNOWN);
469 case 'v': /* version */
470 verbose = true;
471 break;
472 case 't': /* timeout period */
473 timeout_interval = atoi(optarg);
474 break;
475 case 'H': /* hostname */
476 if (strlen(optarg) >= ADDRESS_LENGTH) {
477 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
478 }
479 strcpy(result.config.query_address, optarg);
480 break;
481 case 's': /* server name */
482 /* TODO: this host_or_die check is probably unnecessary.
483 * Better to confirm nslookup response matches */
484 host_or_die(optarg);
485 if (strlen(optarg) >= ADDRESS_LENGTH) {
486 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
487 }
488 strcpy(result.config.dns_server, optarg);
489 break;
490 case 'r': /* reverse server name */
491 /* TODO: Is this host_or_die necessary? */
492 // TODO This does not do anything!!! 2025-03-08 rincewind
493 host_or_die(optarg);
494 if (strlen(optarg) >= ADDRESS_LENGTH) {
495 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
496 }
497 static char ptr_server[ADDRESS_LENGTH] = "";
498 strcpy(ptr_server, optarg);
499 break;
500 case 'a': /* expected address */
501 if (strlen(optarg) >= ADDRESS_LENGTH) {
502 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
503 }
504 if (strchr(optarg, ',') != NULL) {
505 char *comma = strchr(optarg, ',');
506 while (comma != NULL) {
507 result.config.expected_address =
508 (char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **));
509 result.config.expected_address[result.config.expected_address_cnt] = strndup(optarg, comma - optarg);
510 result.config.expected_address_cnt++;
511 optarg = comma + 1;
512 comma = strchr(optarg, ',');
513 }
514 result.config.expected_address =
515 (char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **));
516 result.config.expected_address[result.config.expected_address_cnt] = strdup(optarg);
517 result.config.expected_address_cnt++;
518 } else {
519 result.config.expected_address =
520 (char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **));
521 result.config.expected_address[result.config.expected_address_cnt] = strdup(optarg);
522 result.config.expected_address_cnt++;
523 }
524 break;
525 case 'n': /* expect NXDOMAIN */
526 result.config.expect_nxdomain = true;
527 break;
528 case 'A': /* expect authority */
529 result.config.expect_authority = true;
530 break;
531 case 'L': /* all must match */
532 result.config.all_match = true;
533 break;
534 case 'w':
535 warning = optarg;
536 break;
537 case 'c':
538 critical = optarg;
539 break;
540 default: /* args not parsable */
541 usage5();
542 }
543 }
544
545 index = optind;
546 if (strlen(result.config.query_address) == 0 && index < argc) {
547 if (strlen(argv[index]) >= ADDRESS_LENGTH) {
548 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
549 }
550 strcpy(result.config.query_address, argv[index++]);
551 }
548 552
549int 553 if (strlen(result.config.dns_server) == 0 && index < argc) {
550validate_arguments () 554 /* TODO: See -s option */
551{ 555 host_or_die(argv[index]);
552 if (query_address[0] == 0) { 556 if (strlen(argv[index]) >= ADDRESS_LENGTH) {
553 printf ("missing --host argument\n"); 557 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
554 return ERROR; 558 }
555 } 559 strcpy(result.config.dns_server, argv[index++]);
560 }
556 561
557 if (expected_address_cnt > 0 && expect_nxdomain) { 562 set_thresholds(&result.config.time_thresholds, warning, critical);
558 printf ("--expected-address and --expect-nxdomain cannot be combined\n");
559 return ERROR;
560 }
561 563
562 return OK; 564 return validate_arguments(result);
563} 565}
564 566
567check_dns_config_wrapper validate_arguments(check_dns_config_wrapper config_wrapper) {
568 if (config_wrapper.config.query_address[0] == 0) {
569 printf("missing --host argument\n");
570 config_wrapper.errorcode = ERROR;
571 return config_wrapper;
572 }
573
574 if (config_wrapper.config.expected_address_cnt > 0 && config_wrapper.config.expect_nxdomain) {
575 printf("--expected-address and --expect-nxdomain cannot be combined\n");
576 config_wrapper.errorcode = ERROR;
577 return config_wrapper;
578 }
565 579
566void 580 return config_wrapper;
567print_help (void)
568{
569 print_revision (progname, NP_VERSION);
570
571 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
572 printf (COPYRIGHT, copyright, email);
573
574 printf ("%s\n", _("This plugin uses the nslookup program to obtain the IP address for the given host/domain query."));
575 printf ("%s\n", _("An optional DNS server to use may be specified."));
576 printf ("%s\n", _("If no DNS server is specified, the default server(s) specified in /etc/resolv.conf will be used."));
577
578 printf ("\n\n");
579
580 print_usage ();
581
582 printf (UT_HELP_VRSN);
583 printf (UT_EXTRA_OPTS);
584
585 printf (" -H, --hostname=HOST\n");
586 printf (" %s\n", _("The name or address you want to query"));
587 printf (" -s, --server=HOST\n");
588 printf (" %s\n", _("Optional DNS server you want to use for the lookup"));
589 printf (" -a, --expected-address=IP-ADDRESS|CIDR|HOST\n");
590 printf (" %s\n", _("Optional IP-ADDRESS/CIDR you expect the DNS server to return. HOST must end"));
591 printf (" %s\n", _("with a dot (.). This option can be repeated multiple times (Returns OK if any"));
592 printf (" %s\n", _("value matches)."));
593 printf (" -n, --expect-nxdomain\n");
594 printf (" %s\n", _("Expect the DNS server to return NXDOMAIN (i.e. the domain was not found)"));
595 printf (" %s\n", _("Cannot be used together with -a"));
596 printf (" -A, --expect-authority\n");
597 printf (" %s\n", _("Optionally expect the DNS server to be authoritative for the lookup"));
598 printf (" -w, --warning=seconds\n");
599 printf (" %s\n", _("Return warning if elapsed time exceeds value. Default off"));
600 printf (" -c, --critical=seconds\n");
601 printf (" %s\n", _("Return critical if elapsed time exceeds value. Default off"));
602 printf (" -L, --all\n");
603 printf (" %s\n", _("Return critical if the list of expected addresses does not match all addresses"));
604 printf (" %s\n", _("returned. Default off"));
605
606 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
607
608 printf (UT_SUPPORT);
609} 581}
610 582
583void print_help(void) {
584 print_revision(progname, NP_VERSION);
585
586 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
587 printf(COPYRIGHT, copyright, email);
588
589 printf("%s\n", _("This plugin uses the nslookup program to obtain the IP address for the given host/domain query."));
590 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."));
592
593 printf("\n\n");
594
595 print_usage();
596
597 printf(UT_HELP_VRSN);
598 printf(UT_EXTRA_OPTS);
599
600 printf(" -H, --hostname=HOST\n");
601 printf(" %s\n", _("The name or address you want to query"));
602 printf(" -s, --server=HOST\n");
603 printf(" %s\n", _("Optional DNS server you want to use for the lookup"));
604 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"));
606 printf(" %s\n", _("with a dot (.). This option can be repeated multiple times (Returns OK if any"));
607 printf(" %s\n", _("value matches)."));
608 printf(" -n, --expect-nxdomain\n");
609 printf(" %s\n", _("Expect the DNS server to return NXDOMAIN (i.e. the domain was not found)"));
610 printf(" %s\n", _("Cannot be used together with -a"));
611 printf(" -A, --expect-authority\n");
612 printf(" %s\n", _("Optionally expect the DNS server to be authoritative for the lookup"));
613 printf(" -w, --warning=seconds\n");
614 printf(" %s\n", _("Return warning if elapsed time exceeds value. Default off"));
615 printf(" -c, --critical=seconds\n");
616 printf(" %s\n", _("Return critical if elapsed time exceeds value. Default off"));
617 printf(" -L, --all\n");
618 printf(" %s\n", _("Return critical if the list of expected addresses does not match all addresses"));
619 printf(" %s\n", _("returned. Default off"));
620
621 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
622
623 printf(UT_SUPPORT);
624}
611 625
612void 626void print_usage(void) {
613print_usage (void) 627 printf("%s\n", _("Usage:"));
614{ 628 printf("%s -H host [-s server] [-a expected-address] [-n] [-A] [-t timeout] [-w warn] [-c crit] [-L]\n", progname);
615 printf ("%s\n", _("Usage:"));
616 printf ("%s -H host [-s server] [-a expected-address] [-n] [-A] [-t timeout] [-w warn] [-c crit] [-L]\n", progname);
617} 629}
diff --git a/plugins/check_dns.d/config.h b/plugins/check_dns.d/config.h
new file mode 100644
index 00000000..9ec4eb82
--- /dev/null
+++ b/plugins/check_dns.d/config.h
@@ -0,0 +1,34 @@
1#pragma once
2
3#include "../../config.h"
4#include "thresholds.h"
5#include <stddef.h>
6
7#define ADDRESS_LENGTH 256
8
9typedef struct {
10 bool all_match;
11 char dns_server[ADDRESS_LENGTH];
12 char query_address[ADDRESS_LENGTH];
13 bool expect_nxdomain;
14 bool expect_authority;
15 char **expected_address;
16 size_t expected_address_cnt;
17
18 thresholds *time_thresholds;
19} check_dns_config;
20
21check_dns_config check_dns_config_init() {
22 check_dns_config tmp = {
23 .all_match = false,
24 .dns_server = "",
25 .query_address = "",
26 .expect_nxdomain = false,
27 .expect_authority = false,
28 .expected_address = NULL,
29 .expected_address_cnt = 0,
30
31 .time_thresholds = NULL,
32 };
33 return tmp;
34}
diff --git a/plugins/check_dummy.c b/plugins/check_dummy.c
index 212a1344..19f6c046 100644
--- a/plugins/check_dummy.c
+++ b/plugins/check_dummy.c
@@ -1,124 +1,111 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_dummy plugin 3 * Monitoring check_dummy plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2007 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_dummy plugin 10 * This file contains the check_dummy plugin
11* 11 *
12* This plugin will simply return the state corresponding to the numeric value 12 * This plugin will simply return the state corresponding to the numeric value
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_dummy"; 31const char *progname = "check_dummy";
32const char *copyright = "1999-2007"; 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 "utils.h" 36#include "utils.h"
37 37
38void print_help (void); 38static void print_help(void);
39void print_usage (void); 39void print_usage(void);
40 40
41 41int main(int argc, char **argv) {
42int 42 int result = STATE_UNKNOWN;
43main (int argc, char **argv) 43
44{ 44 setlocale(LC_ALL, "");
45 int result = STATE_UNKNOWN; 45 bindtextdomain(PACKAGE, LOCALEDIR);
46 46 textdomain(PACKAGE);
47 setlocale (LC_ALL, ""); 47
48 bindtextdomain (PACKAGE, LOCALEDIR); 48 if (argc < 2)
49 textdomain (PACKAGE); 49 usage4(_("Could not parse arguments"));
50 50 else if (strcmp(argv[1], "-V") == 0 || strcmp(argv[1], "--version") == 0) {
51 if (argc < 2) 51 print_revision(progname, NP_VERSION);
52 usage4 (_("Could not parse arguments")); 52 exit(STATE_UNKNOWN);
53 else if (strcmp (argv[1], "-V") == 0 || strcmp (argv[1], "--version") == 0) { 53 } else if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) {
54 print_revision (progname, NP_VERSION); 54 print_help();
55 exit (STATE_UNKNOWN); 55 exit(STATE_UNKNOWN);
56 } 56 } else if (!is_integer(argv[1]))
57 else if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) { 57 usage4(_("Arguments to check_dummy must be an integer"));
58 print_help (); 58 else
59 exit (STATE_UNKNOWN); 59 result = atoi(argv[1]);
60 } 60
61 else if (!is_integer (argv[1])) 61 switch (result) {
62 usage4 (_("Arguments to check_dummy must be an integer")); 62 case STATE_OK:
63 else 63 printf(_("OK"));
64 result = atoi (argv[1]); 64 break;
65 65 case STATE_WARNING:
66 switch (result) { 66 printf(_("WARNING"));
67 case STATE_OK: 67 break;
68 printf (_("OK")); 68 case STATE_CRITICAL:
69 break; 69 printf(_("CRITICAL"));
70 case STATE_WARNING: 70 break;
71 printf (_("WARNING")); 71 case STATE_UNKNOWN:
72 break; 72 printf(_("UNKNOWN"));
73 case STATE_CRITICAL: 73 break;
74 printf (_("CRITICAL")); 74 default:
75 break; 75 printf(_("UNKNOWN"));
76 case STATE_UNKNOWN: 76 printf(": ");
77 printf (_("UNKNOWN")); 77 printf(_("Status %d is not a supported error state\n"), result);
78 break; 78 return STATE_UNKNOWN;
79 default: 79 }
80 printf (_("UNKNOWN")); 80
81 printf (": "); 81 if (argc >= 3)
82 printf (_("Status %d is not a supported error state\n"), result); 82 printf(": %s", argv[2]);
83 return STATE_UNKNOWN; 83
84 } 84 printf("\n");
85 85
86 if (argc >= 3) 86 return result;
87 printf (": %s", argv[2]);
88
89 printf("\n");
90
91 return result;
92} 87}
93 88
89void print_help(void) {
90 print_revision(progname, NP_VERSION);
94 91
92 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
93 printf(COPYRIGHT, copyright, email);
95 94
96void 95 printf("%s\n", _("This plugin will simply return the state corresponding to the numeric value"));
97print_help (void)
98{
99 print_revision (progname, NP_VERSION);
100 96
101 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 97 printf("%s\n", _("of the <state> argument with optional text"));
102 printf (COPYRIGHT, copyright, email);
103 98
104 printf ("%s\n", _("This plugin will simply return the state corresponding to the numeric value")); 99 printf("\n\n");
105 100
106 printf ("%s\n", _("of the <state> argument with optional text")); 101 print_usage();
107 102
108 printf ("\n\n"); 103 printf(UT_HELP_VRSN);
109 104
110 print_usage (); 105 printf(UT_SUPPORT);
111
112 printf (UT_HELP_VRSN);
113
114 printf (UT_SUPPORT);
115} 106}
116 107
117 108void print_usage(void) {
118 109 printf("%s\n", _("Usage:"));
119void 110 printf(" %s <integer state> [optional text]\n", progname);
120print_usage (void)
121{
122 printf ("%s\n", _("Usage:"));
123 printf (" %s <integer state> [optional text]\n", progname);
124} 111}
diff --git a/plugins/check_fping.c b/plugins/check_fping.c
index 70d6f9fc..8018e06d 100644
--- a/plugins/check_fping.c
+++ b/plugins/check_fping.c
@@ -1,36 +1,36 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_fping plugin 3 * Monitoring check_fping plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2007 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_disk plugin 10 * This file contains the check_fping plugin
11* 11 *
12* This plugin will use the fping command to ping the specified host for a 12 * This plugin will use the fping command to ping the specified host for a
13* fast check 13 * fast check
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 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 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 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 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/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_fping"; 32const char *progname = "check_fping";
33const char *copyright = "2000-2007"; 33const char *copyright = "2000-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "common.h" 36#include "common.h"
@@ -38,490 +38,544 @@ const char *email = "devel@monitoring-plugins.org";
38#include "netutils.h" 38#include "netutils.h"
39#include "utils.h" 39#include "utils.h"
40#include <stdbool.h> 40#include <stdbool.h>
41#include "check_fping.d/config.h"
42#include "states.h"
41 43
42enum { 44enum {
43 PACKET_COUNT = 1, 45 PL = 0,
44 PACKET_SIZE = 56, 46 RTA = 1
45 PL = 0,
46 RTA = 1
47}; 47};
48 48
49int textscan (char *buf); 49static mp_state_enum textscan(char *buf, const char * /*server_name*/, bool /*crta_p*/, double /*crta*/, bool /*wrta_p*/, double /*wrta*/,
50int process_arguments (int, char **); 50 bool /*cpl_p*/, int /*cpl*/, bool /*wpl_p*/, int /*wpl*/, bool /*alive_p*/);
51int get_threshold (char *arg, char *rv[2]); 51
52void print_help (void); 52typedef struct {
53void print_usage (void); 53 int errorcode;
54 54 check_fping_config config;
55char *server_name = NULL; 55} check_fping_config_wrapper;
56char *sourceip = NULL; 56static check_fping_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
57char *sourceif = NULL; 57static int get_threshold(char *arg, char *rv[2]);
58int packet_size = PACKET_SIZE; 58static void print_help(void);
59int packet_count = PACKET_COUNT; 59void print_usage(void);
60int target_timeout = 0; 60
61int packet_interval = 0; 61static bool verbose = false;
62bool verbose = false; 62
63int cpl; 63int main(int argc, char **argv) {
64int wpl; 64 setlocale(LC_ALL, "");
65double crta; 65 bindtextdomain(PACKAGE, LOCALEDIR);
66double wrta; 66 textdomain(PACKAGE);
67bool cpl_p = false; 67
68bool wpl_p = false; 68 /* Parse extra opts if any */
69bool alive_p = false; 69 argv = np_extra_opts(&argc, argv, progname);
70bool crta_p = false; 70
71bool wrta_p = false; 71 check_fping_config_wrapper tmp_config = process_arguments(argc, argv);
72 72 if (tmp_config.errorcode == ERROR) {
73int 73 usage4(_("Could not parse arguments"));
74main (int argc, char **argv) 74 }
75{ 75
76/* normally should be int result = STATE_UNKNOWN; */ 76 const check_fping_config config = tmp_config.config;
77 77
78 int status = STATE_UNKNOWN; 78 char *server = NULL;
79 int result = 0; 79 server = strscpy(server, config.server_name);
80 char *fping_prog = NULL; 80
81 char *server = NULL; 81 char *option_string = "";
82 char *command_line = NULL; 82 char *fping_prog = NULL;
83 char *input_buffer = NULL; 83
84 char *option_string = ""; 84 /* First determine if the target is dualstack or ipv6 only. */
85 input_buffer = malloc (MAX_INPUT_BUFFER); 85 bool server_is_inet6_addr = is_inet6_addr(server);
86 86
87 setlocale (LC_ALL, ""); 87 /*
88 bindtextdomain (PACKAGE, LOCALEDIR); 88 * If the user requested -6 OR the user made no assertion and the address is v6 or dualstack
89 textdomain (PACKAGE); 89 * -> we use ipv6
90 90 * If the user requested -4 OR the user made no assertion and the address is v4 ONLY
91 /* Parse extra opts if any */ 91 * -> we use ipv4
92 argv=np_extra_opts (&argc, argv, progname); 92 */
93 93 if (address_family == AF_INET6 || (address_family == AF_UNSPEC && server_is_inet6_addr)) {
94 if (process_arguments (argc, argv) == ERROR) 94 xasprintf(&option_string, "%s-6 ", option_string);
95 usage4 (_("Could not parse arguments")); 95 } else {
96 96 xasprintf(&option_string, "%s-4 ", option_string);
97 server = strscpy (server, server_name); 97 }
98 98 fping_prog = strdup(PATH_TO_FPING);
99 /* compose the command */ 99
100 if (target_timeout) 100 /* compose the command */
101 xasprintf(&option_string, "%s-t %d ", option_string, target_timeout); 101 if (config.target_timeout) {
102 if (packet_interval) 102 xasprintf(&option_string, "%s-t %d ", option_string, config.target_timeout);
103 xasprintf(&option_string, "%s-p %d ", option_string, packet_interval); 103 }
104 if (sourceip) 104 if (config.packet_interval) {
105 xasprintf(&option_string, "%s-S %s ", option_string, sourceip); 105 xasprintf(&option_string, "%s-p %d ", option_string, config.packet_interval);
106 if (sourceif) 106 }
107 xasprintf(&option_string, "%s-I %s ", option_string, sourceif); 107 if (config.sourceip) {
108 108 xasprintf(&option_string, "%s-S %s ", option_string, config.sourceip);
109#ifdef PATH_TO_FPING6 109 }
110 if (address_family != AF_INET && is_inet6_addr(server)) 110 if (config.sourceif) {
111 fping_prog = strdup(PATH_TO_FPING6); 111 xasprintf(&option_string, "%s-I %s ", option_string, config.sourceif);
112 else 112 }
113 fping_prog = strdup(PATH_TO_FPING); 113 if (config.dontfrag) {
114#else 114 xasprintf(&option_string, "%s-M ", option_string);
115 fping_prog = strdup(PATH_TO_FPING); 115 }
116#endif 116 if (config.randomize_packet_data) {
117 117 xasprintf(&option_string, "%s-R ", option_string);
118 xasprintf (&command_line, "%s %s-b %d -c %d %s", fping_prog, 118 }
119 option_string, packet_size, packet_count, server); 119
120 120 if (config.fwmark_set) {
121 if (verbose) 121 xasprintf(&option_string, "%s--fwmark %u ", option_string, config.fwmark);
122 printf ("%s\n", command_line); 122 }
123 123
124 /* run the command */ 124 if (config.icmp_timestamp) {
125 child_process = spopen (command_line); 125 xasprintf(&option_string, "%s--icmp-timestamp ", option_string);
126 if (child_process == NULL) { 126 }
127 printf (_("Could not open pipe: %s\n"), command_line); 127
128 return STATE_UNKNOWN; 128 if (config.check_source) {
129 } 129 xasprintf(&option_string, "%s--check-source ", option_string);
130 130 }
131 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); 131
132 if (child_stderr == NULL) { 132 char *command_line = NULL;
133 printf (_("Could not open stderr for %s\n"), command_line); 133
134 } 134 if (config.icmp_timestamp) {
135 135 // no packet size settable for ICMP timestamp
136 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) { 136 xasprintf(&command_line, "%s %s -c %d %s", fping_prog, option_string, config.packet_count, server);
137 if (verbose) 137 } else {
138 printf ("%s", input_buffer); 138 xasprintf(&command_line, "%s %s-b %d -c %d %s", fping_prog, option_string, config.packet_size, config.packet_count, server);
139 status = max_state (status, textscan (input_buffer)); 139 }
140 } 140
141 141 if (verbose) {
142 /* If we get anything on STDERR, at least set warning */ 142 printf("%s\n", command_line);
143 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) { 143 }
144 status = max_state (status, STATE_WARNING); 144
145 if (verbose) 145 /* run the command */
146 printf ("%s", input_buffer); 146 child_process = spopen(command_line);
147 status = max_state (status, textscan (input_buffer)); 147 if (child_process == NULL) {
148 } 148 printf(_("Could not open pipe: %s\n"), command_line);
149 (void) fclose (child_stderr); 149 return STATE_UNKNOWN;
150 150 }
151 /* close the pipe */ 151
152 result = spclose (child_process); 152 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
153 if (result) { 153 if (child_stderr == NULL) {
154 /* need to use max_state not max */ 154 printf(_("Could not open stderr for %s\n"), command_line);
155 status = max_state (status, STATE_WARNING); 155 }
156 } 156
157 157 char *input_buffer = malloc(MAX_INPUT_BUFFER);
158 if (result > 1 ) { 158 mp_state_enum status = STATE_UNKNOWN;
159 status = max_state (status, STATE_UNKNOWN); 159 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
160 if (result == 2) { 160 if (verbose) {
161 die (STATE_UNKNOWN, _("FPING UNKNOWN - IP address not found\n")); 161 printf("%s", input_buffer);
162 } 162 }
163 if (result == 3) { 163 status = max_state(status, textscan(input_buffer, config.server_name, config.crta_p, config.crta, config.wrta_p, config.wrta,
164 die (STATE_UNKNOWN, _("FPING UNKNOWN - invalid commandline argument\n")); 164 config.cpl_p, config.cpl, config.wpl_p, config.wpl, config.alive_p));
165 } 165 }
166 if (result == 4) { 166
167 die (STATE_UNKNOWN, _("FPING UNKNOWN - failed system call\n")); 167 /* If we get anything on STDERR, at least set warning */
168 } 168 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
169 169 status = max_state(status, STATE_WARNING);
170 } 170 if (verbose) {
171 171 printf("%s", input_buffer);
172 printf ("FPING %s - %s\n", state_text (status), server_name); 172 }
173 173 status = max_state(status, textscan(input_buffer, config.server_name, config.crta_p, config.crta, config.wrta_p, config.wrta,
174 return status; 174 config.cpl_p, config.cpl, config.wpl_p, config.wpl, config.alive_p));
175 }
176 (void)fclose(child_stderr);
177
178 /* close the pipe */
179 int result = spclose(child_process);
180 if (result) {
181 /* need to use max_state not max */
182 status = max_state(status, STATE_WARNING);
183 }
184
185 if (result > 1) {
186 status = max_state(status, STATE_UNKNOWN);
187 if (result == 2) {
188 die(STATE_UNKNOWN, _("FPING UNKNOWN - IP address not found\n"));
189 }
190 if (result == 3) {
191 die(STATE_UNKNOWN, _("FPING UNKNOWN - invalid commandline argument\n"));
192 }
193 if (result == 4) {
194 die(STATE_UNKNOWN, _("FPING UNKNOWN - failed system call\n"));
195 }
196 }
197
198 printf("FPING %s - %s\n", state_text(status), config.server_name);
199
200 return status;
175} 201}
176 202
177 203mp_state_enum textscan(char *buf, const char *server_name, bool crta_p, double crta, bool wrta_p, double wrta, bool cpl_p, int cpl,
178int textscan (char *buf) { 204 bool wpl_p, int wpl, bool alive_p) {
179 char *rtastr = NULL; 205 /* stops testing after the first successful reply. */
180 char *losstr = NULL; 206 double rta;
181 char *xmtstr = NULL; 207 double loss;
182 double loss; 208 char *rtastr = NULL;
183 double rta; 209 if (alive_p && strstr(buf, "avg, 0% loss)")) {
184 double xmt; 210 rtastr = strstr(buf, "ms (");
185 int status = STATE_UNKNOWN; 211 rtastr = 1 + index(rtastr, '(');
186 212 rta = strtod(rtastr, NULL);
187 /* stops testing after the first successful reply. */ 213 loss = strtod("0", NULL);
188 if (alive_p && strstr(buf, "avg, 0% loss)")) { 214 die(STATE_OK, _("FPING %s - %s (rta=%f ms)|%s\n"), state_text(STATE_OK), server_name, rta,
189 rtastr = strstr (buf, "ms ("); 215 /* No loss since we only waited for the first reply
190 rtastr = 1 + index(rtastr, '('); 216 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100), */
191 rta = strtod(rtastr, NULL); 217 fperfdata("rta", rta / 1.0e3, "s", wrta_p, wrta / 1.0e3, crta_p, crta / 1.0e3, true, 0, false, 0));
192 loss=strtod("0",NULL); 218 }
193 die (STATE_OK, 219
194 _("FPING %s - %s (rta=%f ms)|%s\n"), 220 mp_state_enum status = STATE_UNKNOWN;
195 state_text (STATE_OK), server_name,rta, 221 char *xmtstr = NULL;
196 /* No loss since we only waited for the first reply 222 double xmt;
197 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100), */ 223 char *losstr = NULL;
198 fperfdata ("rta", rta/1.0e3, "s", wrta_p, wrta/1.0e3, crta_p, crta/1.0e3, true, 0, false, 0)); 224 if (strstr(buf, "not found")) {
199 } 225 die(STATE_CRITICAL, _("FPING UNKNOWN - %s not found\n"), server_name);
200 226
201 if (strstr (buf, "not found")) { 227 } else if (strstr(buf, "is unreachable") || strstr(buf, "Unreachable")) {
202 die (STATE_CRITICAL, _("FPING UNKNOWN - %s not found\n"), server_name); 228 die(STATE_CRITICAL, _("FPING CRITICAL - %s is unreachable\n"), "host");
203 229
204 } 230 } else if (strstr(buf, "Operation not permitted") || strstr(buf, "No such device")) {
205 else if (strstr (buf, "is unreachable") || strstr (buf, "Unreachable")) { 231 die(STATE_UNKNOWN, _("FPING UNKNOWN - %s parameter error\n"), "host");
206 die (STATE_CRITICAL, _("FPING CRITICAL - %s is unreachable\n"), 232 } else if (strstr(buf, "is down")) {
207 "host"); 233 die(STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name);
208 234
209 } 235 } else if (strstr(buf, "is alive")) {
210 else if (strstr (buf, "Operation not permitted") || strstr (buf, "No such device") ) { 236 status = STATE_OK;
211 die (STATE_UNKNOWN, _("FPING UNKNOWN - %s parameter error\n"), 237
212 "host"); 238 } else if (strstr(buf, "xmt/rcv/%loss") && strstr(buf, "min/avg/max")) {
213 } 239 losstr = strstr(buf, "=");
214 else if (strstr (buf, "is down")) { 240 losstr = 1 + strstr(losstr, "/");
215 die (STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name); 241 losstr = 1 + strstr(losstr, "/");
216 242 rtastr = strstr(buf, "min/avg/max");
217 } 243 rtastr = strstr(rtastr, "=");
218 else if (strstr (buf, "is alive")) { 244 rtastr = 1 + index(rtastr, '/');
219 status = STATE_OK; 245 loss = strtod(losstr, NULL);
220 246 rta = strtod(rtastr, NULL);
221 } 247 if (cpl_p && loss > cpl) {
222 else if (strstr (buf, "xmt/rcv/%loss") && strstr (buf, "min/avg/max")) { 248 status = STATE_CRITICAL;
223 losstr = strstr (buf, "="); 249 } else if (crta_p && rta > crta) {
224 losstr = 1 + strstr (losstr, "/"); 250 status = STATE_CRITICAL;
225 losstr = 1 + strstr (losstr, "/"); 251 } else if (wpl_p && loss > wpl) {
226 rtastr = strstr (buf, "min/avg/max"); 252 status = STATE_WARNING;
227 rtastr = strstr (rtastr, "="); 253 } else if (wrta_p && rta > wrta) {
228 rtastr = 1 + index (rtastr, '/'); 254 status = STATE_WARNING;
229 loss = strtod (losstr, NULL); 255 } else {
230 rta = strtod (rtastr, NULL); 256 status = STATE_OK;
231 if (cpl_p && loss > cpl) 257 }
232 status = STATE_CRITICAL; 258 die(status, _("FPING %s - %s (loss=%.0f%%, rta=%f ms)|%s %s\n"), state_text(status), server_name, loss, rta,
233 else if (crta_p && rta > crta) 259 perfdata("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, false, 0, false, 0),
234 status = STATE_CRITICAL; 260 fperfdata("rta", rta / 1.0e3, "s", wrta_p, wrta / 1.0e3, crta_p, crta / 1.0e3, true, 0, false, 0));
235 else if (wpl_p && loss > wpl) 261
236 status = STATE_WARNING; 262 } else if (strstr(buf, "xmt/rcv/%loss")) {
237 else if (wrta_p && rta > wrta) 263 /* no min/max/avg if host was unreachable in fping v2.2.b1 */
238 status = STATE_WARNING; 264 /* in v2.4b2: 10.99.0.1 : xmt/rcv/%loss = 0/0/0% */
239 else 265 losstr = strstr(buf, "=");
240 status = STATE_OK; 266 xmtstr = 1 + losstr;
241 die (status, 267 xmt = strtod(xmtstr, NULL);
242 _("FPING %s - %s (loss=%.0f%%, rta=%f ms)|%s %s\n"), 268 if (xmt == 0) {
243 state_text (status), server_name, loss, rta, 269 die(STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name);
244 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100), 270 }
245 fperfdata ("rta", rta/1.0e3, "s", wrta_p, wrta/1.0e3, crta_p, crta/1.0e3, true, 0, false, 0)); 271 losstr = 1 + strstr(losstr, "/");
246 272 losstr = 1 + strstr(losstr, "/");
247 } 273 loss = strtod(losstr, NULL);
248 else if(strstr (buf, "xmt/rcv/%loss") ) { 274 if (atoi(losstr) == 100) {
249 /* no min/max/avg if host was unreachable in fping v2.2.b1 */ 275 status = STATE_CRITICAL;
250 /* in v2.4b2: 10.99.0.1 : xmt/rcv/%loss = 0/0/0% */ 276 } else if (cpl_p && loss > cpl) {
251 losstr = strstr (buf, "="); 277 status = STATE_CRITICAL;
252 xmtstr = 1 + losstr; 278 } else if (wpl_p && loss > wpl) {
253 xmt = strtod (xmtstr, NULL); 279 status = STATE_WARNING;
254 if(xmt == 0) 280 } else {
255 die (STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name); 281 status = STATE_OK;
256 losstr = 1 + strstr (losstr, "/"); 282 }
257 losstr = 1 + strstr (losstr, "/"); 283 /* loss=%.0f%%;%d;%d;0;100 */
258 loss = strtod (losstr, NULL); 284 die(status, _("FPING %s - %s (loss=%.0f%% )|%s\n"), state_text(status), server_name, loss,
259 if (atoi(losstr) == 100) 285 perfdata("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, false, 0, false, 0));
260 status = STATE_CRITICAL; 286
261 else if (cpl_p && loss > cpl) 287 } else {
262 status = STATE_CRITICAL; 288 status = max_state(status, STATE_WARNING);
263 else if (wpl_p && loss > wpl) 289 }
264 status = STATE_WARNING; 290
265 else 291 return status;
266 status = STATE_OK;
267 /* loss=%.0f%%;%d;%d;0;100 */
268 die (status, _("FPING %s - %s (loss=%.0f%% )|%s\n"),
269 state_text (status), server_name, loss ,
270 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100));
271
272 }
273 else {
274 status = max_state (status, STATE_WARNING);
275 }
276
277 return status;
278} 292}
279 293
280
281
282/* process command-line arguments */ 294/* process command-line arguments */
283int 295check_fping_config_wrapper process_arguments(int argc, char **argv) {
284process_arguments (int argc, char **argv) 296 enum {
285{ 297 FWMARK_OPT = CHAR_MAX + 1,
286 int c; 298 ICMP_TIMESTAMP_OPT,
287 char *rv[2]; 299 CHECK_SOURCE_OPT,
288 300 };
289 int option = 0; 301 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
290 static struct option longopts[] = { 302 {"sourceip", required_argument, 0, 'S'},
291 {"hostname", required_argument, 0, 'H'}, 303 {"sourceif", required_argument, 0, 'I'},
292 {"sourceip", required_argument, 0, 'S'}, 304 {"critical", required_argument, 0, 'c'},
293 {"sourceif", required_argument, 0, 'I'}, 305 {"warning", required_argument, 0, 'w'},
294 {"critical", required_argument, 0, 'c'}, 306 {"alive", no_argument, 0, 'a'},
295 {"warning", required_argument, 0, 'w'}, 307 {"bytes", required_argument, 0, 'b'},
296 {"alive", no_argument, 0, 'a'}, 308 {"number", required_argument, 0, 'n'},
297 {"bytes", required_argument, 0, 'b'}, 309 {"target-timeout", required_argument, 0, 'T'},
298 {"number", required_argument, 0, 'n'}, 310 {"interval", required_argument, 0, 'i'},
299 {"target-timeout", required_argument, 0, 'T'}, 311 {"verbose", no_argument, 0, 'v'},
300 {"interval", required_argument, 0, 'i'}, 312 {"version", no_argument, 0, 'V'},
301 {"verbose", no_argument, 0, 'v'}, 313 {"help", no_argument, 0, 'h'},
302 {"version", no_argument, 0, 'V'}, 314 {"use-ipv4", no_argument, 0, '4'},
303 {"help", no_argument, 0, 'h'}, 315 {"use-ipv6", no_argument, 0, '6'},
304 {"use-ipv4", no_argument, 0, '4'}, 316 {"dontfrag", no_argument, 0, 'M'},
305 {"use-ipv6", no_argument, 0, '6'}, 317 {"random", no_argument, 0, 'R'},
306 {0, 0, 0, 0} 318#ifdef FPING_VERSION_5_2_OR_HIGHER
307 }; 319 // only available with fping version >= 5.2
308 320 {"fwmark", required_argument, NULL, FWMARK_OPT},
309 rv[PL] = NULL; 321# ifdef FPING_VERSION_5_3_OR_HIGHER
310 rv[RTA] = NULL; 322 // only available with fping version >= 5.3
311 323 {"icmp-timestamp", no_argument, NULL, ICMP_TIMESTAMP_OPT},
312 if (argc < 2) 324 {"check-source", no_argument, NULL, CHECK_SOURCE_OPT},
313 return ERROR; 325# endif
314
315 if (!is_option (argv[1])) {
316 server_name = argv[1];
317 argv[1] = argv[0];
318 argv = &argv[1];
319 argc--;
320 }
321
322 while (1) {
323 c = getopt_long (argc, argv, "+hVvaH:S:c:w:b:n:T:i:I:46", longopts, &option);
324
325 if (c == -1 || c == EOF || c == 1)
326 break;
327
328 switch (c) {
329 case '?': /* print short usage statement if args not parsable */
330 usage5 ();
331 case 'a': /* host alive mode */
332 alive_p = true;
333 break;
334 case 'h': /* help */
335 print_help ();
336 exit (STATE_UNKNOWN);
337 case 'V': /* version */
338 print_revision (progname, NP_VERSION);
339 exit (STATE_UNKNOWN);
340 case 'v': /* verbose mode */
341 verbose = true;
342 break;
343 case 'H': /* hostname */
344 if (is_host (optarg) == false) {
345 usage2 (_("Invalid hostname/address"), optarg);
346 }
347 server_name = strscpy (server_name, optarg);
348 break;
349 case 'S': /* sourceip */
350 if (is_host (optarg) == false) {
351 usage2 (_("Invalid hostname/address"), optarg);
352 }
353 sourceip = strscpy (sourceip, optarg);
354 break;
355 case 'I': /* sourceip */
356 sourceif = strscpy (sourceif, optarg);
357 break;
358 case '4': /* IPv4 only */
359 address_family = AF_INET;
360 break;
361 case '6': /* IPv6 only */
362#ifdef USE_IPV6
363 address_family = AF_INET6;
364#else
365 usage (_("IPv6 support not available\n"));
366#endif 326#endif
367 break; 327 {0, 0, 0, 0}};
368 case 'c':
369 get_threshold (optarg, rv);
370 if (rv[RTA]) {
371 crta = strtod (rv[RTA], NULL);
372 crta_p = true;
373 rv[RTA] = NULL;
374 }
375 if (rv[PL]) {
376 cpl = atoi (rv[PL]);
377 cpl_p = true;
378 rv[PL] = NULL;
379 }
380 break;
381 case 'w':
382 get_threshold (optarg, rv);
383 if (rv[RTA]) {
384 wrta = strtod (rv[RTA], NULL);
385 wrta_p = true;
386 rv[RTA] = NULL;
387 }
388 if (rv[PL]) {
389 wpl = atoi (rv[PL]);
390 wpl_p = true;
391 rv[PL] = NULL;
392 }
393 break;
394 case 'b': /* bytes per packet */
395 if (is_intpos (optarg))
396 packet_size = atoi (optarg);
397 else
398 usage (_("Packet size must be a positive integer"));
399 break;
400 case 'n': /* number of packets */
401 if (is_intpos (optarg))
402 packet_count = atoi (optarg);
403 else
404 usage (_("Packet count must be a positive integer"));
405 break;
406 case 'T': /* timeout in msec */
407 if (is_intpos (optarg))
408 target_timeout = atoi (optarg);
409 else
410 usage (_("Target timeout must be a positive integer"));
411 break;
412 case 'i': /* interval in msec */
413 if (is_intpos (optarg))
414 packet_interval = atoi (optarg);
415 else
416 usage (_("Interval must be a positive integer"));
417 break;
418 }
419 }
420
421 if (server_name == NULL)
422 usage4 (_("Hostname was not supplied"));
423
424 return OK;
425}
426
427 328
428int 329 char *rv[2];
429get_threshold (char *arg, char *rv[2]) 330 rv[PL] = NULL;
430{ 331 rv[RTA] = NULL;
431 char *arg1 = NULL;
432 char *arg2 = NULL;
433
434 arg1 = strscpy (arg1, arg);
435 if (strpbrk (arg1, ",:"))
436 arg2 = 1 + strpbrk (arg1, ",:");
437
438 if (arg2) {
439 arg1[strcspn (arg1, ",:")] = 0;
440 if (strstr (arg1, "%") && strstr (arg2, "%"))
441 die (STATE_UNKNOWN,
442 _("%s: Only one threshold may be packet loss (%s)\n"), progname,
443 arg);
444 if (!strstr (arg1, "%") && !strstr (arg2, "%"))
445 die (STATE_UNKNOWN,
446 _("%s: Only one threshold must be packet loss (%s)\n"),
447 progname, arg);
448 }
449
450 if (arg2 && strstr (arg2, "%")) {
451 rv[PL] = arg2;
452 rv[RTA] = arg1;
453 }
454 else if (arg2) {
455 rv[PL] = arg1;
456 rv[RTA] = arg2;
457 }
458 else if (strstr (arg1, "%")) {
459 rv[PL] = arg1;
460 }
461 else {
462 rv[RTA] = arg1;
463 }
464
465 return OK;
466}
467 332
333 int option = 0;
468 334
469void print_help (void) { 335 check_fping_config_wrapper result = {
336 .errorcode = OK,
337 .config = check_fping_config_init(),
338 };
470 339
471 print_revision (progname, NP_VERSION); 340 if (argc < 2) {
341 result.errorcode = ERROR;
342 return result;
343 }
472 344
473 printf ("Copyright (c) 1999 Didi Rieder <adrieder@sbox.tu-graz.ac.at>\n"); 345 if (!is_option(argv[1])) {
474 printf (COPYRIGHT, copyright, email); 346 result.config.server_name = argv[1];
347 argv[1] = argv[0];
348 argv = &argv[1];
349 argc--;
350 }
475 351
476 printf ("%s\n", _("This plugin will use the fping command to ping the specified host for a fast check")); 352 while (true) {
353 int option_index = getopt_long(argc, argv, "+hVvaH:S:c:w:b:n:T:i:I:M:R:46", longopts, &option);
477 354
478 printf ("%s\n", _("Note that it is necessary to set the suid flag on fping.")); 355 if (option_index == -1 || option_index == EOF || option_index == 1) {
356 break;
357 }
479 358
480 printf ("\n\n"); 359 switch (option_index) {
360 case '?': /* print short usage statement if args not parsable */
361 usage5();
362 case 'a': /* host alive mode */
363 result.config.alive_p = true;
364 break;
365 case 'h': /* help */
366 print_help();
367 exit(STATE_UNKNOWN);
368 case 'V': /* version */
369 print_revision(progname, NP_VERSION);
370 exit(STATE_UNKNOWN);
371 case 'v': /* verbose mode */
372 verbose = true;
373 break;
374 case 'H': /* hostname */
375 if (!is_host(optarg)) {
376 usage2(_("Invalid hostname/address"), optarg);
377 }
378 result.config.server_name = optarg;
379 break;
380 case 'S': /* sourceip */
381 if (!is_host(optarg)) {
382 usage2(_("Invalid hostname/address"), optarg);
383 }
384 result.config.sourceip = optarg;
385 break;
386 case 'I': /* sourceip */
387 result.config.sourceif = optarg;
388 break;
389 case '4': /* IPv4 only */
390 address_family = AF_INET;
391 break;
392 case '6': /* IPv6 only */
393 address_family = AF_INET6;
394 break;
395 case 'c':
396 get_threshold(optarg, rv);
397 if (rv[RTA]) {
398 result.config.crta = strtod(rv[RTA], NULL);
399 result.config.crta_p = true;
400 rv[RTA] = NULL;
401 }
402 if (rv[PL]) {
403 result.config.cpl = atoi(rv[PL]);
404 result.config.cpl_p = true;
405 rv[PL] = NULL;
406 }
407 break;
408 case 'w':
409 get_threshold(optarg, rv);
410 if (rv[RTA]) {
411 result.config.wrta = strtod(rv[RTA], NULL);
412 result.config.wrta_p = true;
413 rv[RTA] = NULL;
414 }
415 if (rv[PL]) {
416 result.config.wpl = atoi(rv[PL]);
417 result.config.wpl_p = true;
418 rv[PL] = NULL;
419 }
420 break;
421 case 'b': /* bytes per packet */
422 if (is_intpos(optarg)) {
423 result.config.packet_size = atoi(optarg);
424 } else {
425 usage(_("Packet size must be a positive integer"));
426 }
427 break;
428 case 'n': /* number of packets */
429 if (is_intpos(optarg)) {
430 result.config.packet_count = atoi(optarg);
431 } else {
432 usage(_("Packet count must be a positive integer"));
433 }
434 break;
435 case 'T': /* timeout in msec */
436 if (is_intpos(optarg)) {
437 result.config.target_timeout = atoi(optarg);
438 } else {
439 usage(_("Target timeout must be a positive integer"));
440 }
441 break;
442 case 'i': /* interval in msec */
443 if (is_intpos(optarg)) {
444 result.config.packet_interval = atoi(optarg);
445 } else {
446 usage(_("Interval must be a positive integer"));
447 }
448 break;
449 case 'R':
450 result.config.randomize_packet_data = true;
451 break;
452 case 'M':
453 result.config.dontfrag = true;
454 break;
455 case FWMARK_OPT:
456 if (is_intpos(optarg)) {
457 result.config.fwmark = (unsigned int)atol(optarg);
458 result.config.fwmark_set = true;
459 } else {
460 usage(_("fwmark must be a positive integer"));
461 }
462 break;
463 case ICMP_TIMESTAMP_OPT:
464 result.config.icmp_timestamp = true;
465 break;
466 case CHECK_SOURCE_OPT:
467 result.config.check_source = true;
468 break;
469 }
470 }
481 471
482 print_usage (); 472 if (result.config.server_name == NULL) {
473 usage4(_("Hostname was not supplied"));
474 }
483 475
484 printf (UT_HELP_VRSN); 476 return result;
485 printf (UT_EXTRA_OPTS); 477}
486 478
487 printf (UT_IPv46); 479int get_threshold(char *arg, char *rv[2]) {
480 char *arg2 = NULL;
481
482 char *arg1 = strdup(arg);
483 if (strpbrk(arg1, ",:")) {
484 arg2 = 1 + strpbrk(arg1, ",:");
485 }
486
487 if (arg2) {
488 arg1[strcspn(arg1, ",:")] = 0;
489 if (strstr(arg1, "%") && strstr(arg2, "%")) {
490 die(STATE_UNKNOWN, _("%s: Only one threshold may be packet loss (%s)\n"), progname, arg);
491 }
492 if (!strstr(arg1, "%") && !strstr(arg2, "%")) {
493 die(STATE_UNKNOWN, _("%s: Only one threshold must be packet loss (%s)\n"), progname, arg);
494 }
495 }
496
497 if (arg2 && strstr(arg2, "%")) {
498 rv[PL] = arg2;
499 rv[RTA] = arg1;
500 } else if (arg2) {
501 rv[PL] = arg1;
502 rv[RTA] = arg2;
503 } else if (strstr(arg1, "%")) {
504 rv[PL] = arg1;
505 } else {
506 rv[RTA] = arg1;
507 }
508
509 return OK;
510}
488 511
489 printf (" %s\n", "-H, --hostname=HOST"); 512void print_help(void) {
490 printf (" %s\n", _("name or IP Address of host to ping (IP Address bypasses name lookup, reducing system load)")); 513
491 printf (" %s\n", "-w, --warning=THRESHOLD"); 514 print_revision(progname, NP_VERSION);
492 printf (" %s\n", _("warning threshold pair")); 515
493 printf (" %s\n", "-c, --critical=THRESHOLD"); 516 printf("Copyright (c) 1999 Didi Rieder <adrieder@sbox.tu-graz.ac.at>\n");
494 printf (" %s\n", _("critical threshold pair")); 517 printf(COPYRIGHT, copyright, email);
495 printf (" %s\n", "-a, --alive"); 518
496 printf (" %s\n", _("Return OK after first successful reply")); 519 printf("%s\n", _("This plugin will use the fping command to ping the specified host for a fast check"));
497 printf (" %s\n", "-b, --bytes=INTEGER"); 520
498 printf (" %s (default: %d)\n", _("size of ICMP packet"),PACKET_SIZE); 521 printf("%s\n", _("Note that it is necessary to set the suid flag on fping."));
499 printf (" %s\n", "-n, --number=INTEGER"); 522
500 printf (" %s (default: %d)\n", _("number of ICMP packets to send"),PACKET_COUNT); 523 printf("\n\n");
501 printf (" %s\n", "-T, --target-timeout=INTEGER"); 524
502 printf (" %s (default: fping's default for -t)\n", _("Target timeout (ms)")); 525 print_usage();
503 printf (" %s\n", "-i, --interval=INTEGER"); 526
504 printf (" %s (default: fping's default for -p)\n", _("Interval (ms) between sending packets")); 527 printf(UT_HELP_VRSN);
505 printf (" %s\n", "-S, --sourceip=HOST"); 528 printf(UT_EXTRA_OPTS);
506 printf (" %s\n", _("name or IP Address of sourceip")); 529
507 printf (" %s\n", "-I, --sourceif=IF"); 530 printf(UT_IPv46);
508 printf (" %s\n", _("source interface name")); 531
509 printf (UT_VERBOSE); 532 printf(" %s\n", "-H, --hostname=HOST");
510 printf ("\n"); 533 printf(" %s\n", _("name or IP Address of host to ping (IP Address bypasses name lookup, reducing system load)"));
511 printf (" %s\n", _("THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel time (ms)")); 534 printf(" %s\n", "-w, --warning=THRESHOLD");
512 printf (" %s\n", _("which triggers a WARNING or CRITICAL state, and <pl> is the percentage of")); 535 printf(" %s\n", _("warning threshold pair"));
513 printf (" %s\n", _("packet loss to trigger an alarm state.")); 536 printf(" %s\n", "-c, --critical=THRESHOLD");
537 printf(" %s\n", _("critical threshold pair"));
538 printf(" %s\n", "-a, --alive");
539 printf(" %s\n", _("Return OK after first successful reply"));
540 printf(" %s\n", "-b, --bytes=INTEGER");
541 printf(" %s (default: %d)\n", _("size of ICMP packet"), PACKET_SIZE);
542 printf(" %s\n", "-n, --number=INTEGER");
543 printf(" %s (default: %d)\n", _("number of ICMP packets to send"), PACKET_COUNT);
544 printf(" %s\n", "-T, --target-timeout=INTEGER");
545 printf(" %s (default: fping's default for -t)\n", _("Target timeout (ms)"));
546 printf(" %s\n", "-i, --interval=INTEGER");
547 printf(" %s (default: fping's default for -p)\n", _("Interval (ms) between sending packets"));
548 printf(" %s\n", "-S, --sourceip=HOST");
549 printf(" %s\n", _("name or IP Address of sourceip"));
550 printf(" %s\n", "-I, --sourceif=IF");
551 printf(" %s\n", _("source interface name"));
552 printf(" %s\n", "-M, --dontfrag");
553 printf(" %s\n", _("set the Don't Fragment flag"));
554 printf(" %s\n", "-R, --random");
555 printf(" %s\n", _("random packet data (to foil link data compression)"));
556#ifdef FPING_VERSION_5_2_OR_HIGHER
557 printf(" %s\n", "--fwmark=INTEGER");
558 printf(" %s\n", _("set the routing mark to INTEGER (fping option)"));
559# ifdef FPING_VERSION_5_3_OR_HIGHER
560 printf(" %s\n", "--icmp-timestamp");
561 printf(" %s\n", _("use ICMP Timestamp instead of ICMP Echo (fping option)"));
562 printf(" %s\n", "--check-source");
563 printf(" %s\n", _("discard replies not from target address (fping option)"));
564# endif
565#endif
566 printf(UT_VERBOSE);
567 printf("\n");
568 printf(" %s\n", _("THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel time (ms)"));
569 printf(" %s\n", _("which triggers a WARNING or CRITICAL state, and <pl> is the percentage of"));
570 printf(" %s\n", _("packet loss to trigger an alarm state."));
514 571
515 printf ("\n"); 572 printf("\n");
516 printf (" %s\n", _("IPv4 is used by default. Specify -6 to use IPv6.")); 573 printf(" %s\n", _("IPv4 is used by default. Specify -6 to use IPv6."));
517 574
518 printf (UT_SUPPORT); 575 printf(UT_SUPPORT);
519} 576}
520 577
521 578void print_usage(void) {
522void 579 printf("%s\n", _("Usage:"));
523print_usage (void) 580 printf(" %s <host_address> -w limit -c limit [-b size] [-n number] [-T number] [-i number]\n", progname);
524{
525 printf ("%s\n", _("Usage:"));
526 printf (" %s <host_address> -w limit -c limit [-b size] [-n number] [-T number] [-i number]\n", progname);
527} 581}
diff --git a/plugins/check_fping.d/config.h b/plugins/check_fping.d/config.h
new file mode 100644
index 00000000..d95e9ded
--- /dev/null
+++ b/plugins/check_fping.d/config.h
@@ -0,0 +1,82 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6enum {
7 PACKET_SIZE = 56,
8 PACKET_COUNT = 1,
9};
10
11typedef struct {
12 char *server_name;
13 char *sourceip;
14 char *sourceif;
15 int packet_size;
16 int packet_count;
17 int target_timeout;
18 int packet_interval;
19 bool randomize_packet_data;
20 bool dontfrag;
21 bool alive_p;
22
23 double crta;
24 bool crta_p;
25 double wrta;
26 bool wrta_p;
27
28 int cpl;
29 bool cpl_p;
30 int wpl;
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
40 // only available with fping version >= 5.3
41 // Setting icmp_timestamp tells fping to use ICMP Timestamp (ICMP type 13) instead
42 // of ICMP Echo
43 bool icmp_timestamp;
44
45 // Setting check_source lets fping discard replies which are not from the target address
46 bool check_source;
47} check_fping_config;
48
49check_fping_config check_fping_config_init() {
50 check_fping_config tmp = {
51 .server_name = NULL,
52 .sourceip = NULL,
53 .sourceif = NULL,
54 .packet_size = PACKET_SIZE,
55 .packet_count = PACKET_COUNT,
56 .target_timeout = 0,
57 .packet_interval = 0,
58 .randomize_packet_data = false,
59 .dontfrag = false,
60 .alive_p = false,
61
62 .crta = 0,
63 .crta_p = false,
64 .wrta = 0,
65 .wrta_p = false,
66
67 .cpl = 0,
68 .cpl_p = false,
69 .wpl = 0,
70 .wpl_p = false,
71
72 // only available with fping version >= 5.2
73 .fwmark = 0,
74 .fwmark_set = false, // just to be deterministic
75
76 // only available with fping version >= 5.3
77 .icmp_timestamp = false,
78 .check_source = false,
79
80 };
81 return tmp;
82}
diff --git a/plugins/check_game.c b/plugins/check_game.c
index ca126973..c0193b03 100644
--- a/plugins/check_game.c
+++ b/plugins/check_game.c
@@ -1,335 +1,317 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_game plugin 3 * Monitoring check_game plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2002-2007 Monitoring Plugins Development Team 6 * Copyright (c) 2002-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_game plugin 10 * This file contains the check_game plugin
11* 11 *
12* This plugin tests game server connections with the specified host. 12 * This plugin tests game server connections with the specified host.
13* using the qstat program 13 * using the qstat program
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 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 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 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 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/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_game"; 32const char *progname = "check_game";
33const char *copyright = "2002-2007"; 33const char *copyright = "2002-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "common.h" 36#include "common.h"
37#include "utils.h" 37#include "utils.h"
38#include "runcmd.h" 38#include "runcmd.h"
39#include "check_game.d/config.h"
40#include "../lib/monitoringplug.h"
39 41
40int process_arguments (int, char **); 42typedef struct {
41int validate_arguments (void); 43 int errorcode;
42void print_help (void); 44 check_game_config config;
43void print_usage (void); 45} check_game_config_wrapper;
44 46
45#define QSTAT_DATA_DELIMITER "," 47static check_game_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
48static void print_help(void);
49void print_usage(void);
46 50
47#define QSTAT_HOST_ERROR "ERROR" 51#define QSTAT_DATA_DELIMITER ","
48#define QSTAT_HOST_DOWN "DOWN"
49#define QSTAT_HOST_TIMEOUT "TIMEOUT"
50#define QSTAT_MAX_RETURN_ARGS 12
51
52char *server_ip;
53char *game_type;
54int port = 0;
55
56bool verbose = false;
57
58int qstat_game_players_max = -1;
59int qstat_game_players = -1;
60int qstat_game_field = -1;
61int qstat_map_field = -1;
62int qstat_ping_field = -1;
63
64
65int
66main (int argc, char **argv)
67{
68 char *command_line;
69 int result = STATE_UNKNOWN;
70 char *p, *ret[QSTAT_MAX_RETURN_ARGS];
71 size_t i = 0;
72 output chld_out;
73
74 setlocale (LC_ALL, "");
75 bindtextdomain (PACKAGE, LOCALEDIR);
76 textdomain (PACKAGE);
77
78 /* Parse extra opts if any */
79 argv=np_extra_opts (&argc, argv, progname);
80
81 if (process_arguments (argc, argv) == ERROR)
82 usage_va(_("Could not parse arguments"));
83
84 result = STATE_OK;
85
86 /* create the command line to execute */
87 xasprintf (&command_line, "%s -raw %s -%s %s",
88 PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, game_type, server_ip);
89
90 if (port)
91 xasprintf (&command_line, "%s:%-d", command_line, port);
92
93 if (verbose)
94 printf ("%s\n", command_line);
95
96 /* run the command. historically, this plugin ignores output on stderr,
97 * as well as return status of the qstat program */
98 (void)np_runcmd(command_line, &chld_out, NULL, 0);
99
100 /* sanity check */
101 /* was thinking about running qstat without any options, capturing the
102 -default line, parsing it & making an array of all know server types
103 but thought this would be too much hassle considering this is a tool
104 for intelligent sysadmins (ha). Could put a static array of known
105 server types in a header file but then we'd be limiting ourselves
106
107 In the end, I figured I'd simply let an error occur & then trap it
108 */
109
110 if (!strncmp (chld_out.line[0], "unknown option", 14)) {
111 printf (_("CRITICAL - Host type parameter incorrect!\n"));
112 result = STATE_CRITICAL;
113 return result;
114 }
115
116 p = (char *) strtok (chld_out.line[0], QSTAT_DATA_DELIMITER);
117 while (p != NULL) {
118 ret[i] = p;
119 p = (char *) strtok (NULL, QSTAT_DATA_DELIMITER);
120 i++;
121 if (i >= QSTAT_MAX_RETURN_ARGS)
122 break;
123 }
124
125 if (strstr (ret[2], QSTAT_HOST_ERROR)) {
126 printf (_("CRITICAL - Host not found\n"));
127 result = STATE_CRITICAL;
128 }
129 else if (strstr (ret[2], QSTAT_HOST_DOWN)) {
130 printf (_("CRITICAL - Game server down or unavailable\n"));
131 result = STATE_CRITICAL;
132 }
133 else if (strstr (ret[2], QSTAT_HOST_TIMEOUT)) {
134 printf (_("CRITICAL - Game server timeout\n"));
135 result = STATE_CRITICAL;
136 }
137 else {
138 printf ("OK: %s/%s %s (%s), Ping: %s ms|%s %s\n",
139 ret[qstat_game_players],
140 ret[qstat_game_players_max],
141 ret[qstat_game_field],
142 ret[qstat_map_field],
143 ret[qstat_ping_field],
144 perfdata ("players", atol(ret[qstat_game_players]), "",
145 false, 0, false, 0,
146 true, 0, true, atol(ret[qstat_game_players_max])),
147 fperfdata ("ping", strtod(ret[qstat_ping_field], NULL), "",
148 false, 0, false, 0,
149 true, 0, false, 0));
150 }
151
152 return result;
153}
154 52
53#define QSTAT_HOST_ERROR "ERROR"
54#define QSTAT_HOST_DOWN "DOWN"
55#define QSTAT_HOST_TIMEOUT "TIMEOUT"
56#define QSTAT_MAX_RETURN_ARGS 12
155 57
156int 58static bool verbose = false;
157process_arguments (int argc, char **argv) 59
158{ 60int main(int argc, char **argv) {
159 int c; 61 setlocale(LC_ALL, "");
160 62 bindtextdomain(PACKAGE, LOCALEDIR);
161 int opt_index = 0; 63 textdomain(PACKAGE);
162 static struct option long_opts[] = { 64
163 {"help", no_argument, 0, 'h'}, 65 /* Parse extra opts if any */
164 {"version", no_argument, 0, 'V'}, 66 argv = np_extra_opts(&argc, argv, progname);
165 {"verbose", no_argument, 0, 'v'}, 67
166 {"timeout", required_argument, 0, 't'}, 68 check_game_config_wrapper tmp = process_arguments(argc, argv);
167 {"hostname", required_argument, 0, 'H'}, 69
168 {"port", required_argument, 0, 'P'}, 70 if (tmp.errorcode == ERROR) {
169 {"game-type", required_argument, 0, 'G'}, 71 usage_va(_("Could not parse arguments"));
170 {"map-field", required_argument, 0, 'm'}, 72 }
171 {"ping-field", required_argument, 0, 'p'}, 73
172 {"game-field", required_argument, 0, 'g'}, 74 check_game_config config = tmp.config;
173 {"players-field", required_argument, 0, 129}, 75
174 {"max-players-field", required_argument, 0, 130}, 76 mp_state_enum result = STATE_OK;
175 {0, 0, 0, 0} 77
176 }; 78 /* create the command line to execute */
177 79 char *command_line = NULL;
178 if (argc < 2) 80 xasprintf(&command_line, "%s -raw %s -%s %s", PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, config.game_type, config.server_ip);
179 return ERROR; 81
180 82 if (config.port) {
181 for (c = 1; c < argc; c++) { 83 xasprintf(&command_line, "%s:%-d", command_line, config.port);
182 if (strcmp ("-mf", argv[c]) == 0) 84 }
183 strcpy (argv[c], "-m"); 85
184 else if (strcmp ("-pf", argv[c]) == 0) 86 if (verbose) {
185 strcpy (argv[c], "-p"); 87 printf("%s\n", command_line);
186 else if (strcmp ("-gf", argv[c]) == 0) 88 }
187 strcpy (argv[c], "-g"); 89
188 } 90 /* run the command. historically, this plugin ignores output on stderr,
189 91 * as well as return status of the qstat program */
190 while (1) { 92 output chld_out = {};
191 c = getopt_long (argc, argv, "hVvt:H:P:G:g:p:m:", long_opts, &opt_index); 93 (void)np_runcmd(command_line, &chld_out, NULL, 0);
192 94
193 if (c == -1 || c == EOF) 95 /* sanity check */
194 break; 96 /* was thinking about running qstat without any options, capturing the
195 97 -default line, parsing it & making an array of all know server types
196 switch (c) { 98 but thought this would be too much hassle considering this is a tool
197 case 'h': /* help */ 99 for intelligent sysadmins (ha). Could put a static array of known
198 print_help (); 100 server types in a header file but then we'd be limiting ourselves
199 exit (STATE_UNKNOWN); 101
200 case 'V': /* version */ 102 In the end, I figured I'd simply let an error occur & then trap it
201 print_revision (progname, NP_VERSION); 103 */
202 exit (STATE_UNKNOWN); 104
203 case 'v': /* version */ 105 if (!strncmp(chld_out.line[0], "unknown option", strlen("unknown option"))) {
204 verbose = true; 106 printf(_("CRITICAL - Host type parameter incorrect!\n"));
205 break; 107 result = STATE_CRITICAL;
206 case 't': /* timeout period */ 108 exit(result);
207 timeout_interval = atoi (optarg); 109 }
208 break; 110
209 case 'H': /* hostname */ 111 char *ret[QSTAT_MAX_RETURN_ARGS];
210 if (strlen (optarg) >= MAX_HOST_ADDRESS_LENGTH) 112 size_t i = 0;
211 die (STATE_UNKNOWN, _("Input buffer overflow\n")); 113 char *sequence = strtok(chld_out.line[0], QSTAT_DATA_DELIMITER);
212 server_ip = optarg; 114 while (sequence != NULL) {
213 break; 115 ret[i] = sequence;
214 case 'P': /* port */ 116 sequence = strtok(NULL, QSTAT_DATA_DELIMITER);
215 port = atoi (optarg); 117 i++;
216 break; 118 if (i >= QSTAT_MAX_RETURN_ARGS) {
217 case 'G': /* hostname */ 119 break;
218 if (strlen (optarg) >= MAX_INPUT_BUFFER) 120 }
219 die (STATE_UNKNOWN, _("Input buffer overflow\n")); 121 }
220 game_type = optarg; 122
221 break; 123 if (strstr(ret[2], QSTAT_HOST_ERROR)) {
222 case 'p': /* index of ping field */ 124 printf(_("CRITICAL - Host not found\n"));
223 qstat_ping_field = atoi (optarg); 125 result = STATE_CRITICAL;
224 if (qstat_ping_field < 0 || qstat_ping_field > QSTAT_MAX_RETURN_ARGS) 126 } else if (strstr(ret[2], QSTAT_HOST_DOWN)) {
225 return ERROR; 127 printf(_("CRITICAL - Game server down or unavailable\n"));
226 break; 128 result = STATE_CRITICAL;
227 case 'm': /* index on map field */ 129 } else if (strstr(ret[2], QSTAT_HOST_TIMEOUT)) {
228 qstat_map_field = atoi (optarg); 130 printf(_("CRITICAL - Game server timeout\n"));
229 if (qstat_map_field < 0 || qstat_map_field > QSTAT_MAX_RETURN_ARGS) 131 result = STATE_CRITICAL;
230 return ERROR; 132 } else {
231 break; 133 printf("OK: %s/%s %s (%s), Ping: %s ms|%s %s\n", ret[config.qstat_game_players], ret[config.qstat_game_players_max],
232 case 'g': /* index of game field */ 134 ret[config.qstat_game_field], ret[config.qstat_map_field], ret[config.qstat_ping_field],
233 qstat_game_field = atoi (optarg); 135 perfdata("players", atol(ret[config.qstat_game_players]), "", false, 0, false, 0, true, 0, true,
234 if (qstat_game_field < 0 || qstat_game_field > QSTAT_MAX_RETURN_ARGS) 136 atol(ret[config.qstat_game_players_max])),
235 return ERROR; 137 fperfdata("ping", strtod(ret[config.qstat_ping_field], NULL), "", false, 0, false, 0, true, 0, false, 0));
236 break; 138 }
237 case 129: /* index of player count field */ 139
238 qstat_game_players = atoi (optarg); 140 exit(result);
239 if (qstat_game_players_max == 0)
240 qstat_game_players_max = qstat_game_players - 1;
241 if (qstat_game_players < 0 || qstat_game_players > QSTAT_MAX_RETURN_ARGS)
242 return ERROR;
243 break;
244 case 130: /* index of max players field */
245 qstat_game_players_max = atoi (optarg);
246 if (qstat_game_players_max < 0 || qstat_game_players_max > QSTAT_MAX_RETURN_ARGS)
247 return ERROR;
248 break;
249 default: /* args not parsable */
250 usage5();
251 }
252 }
253
254 c = optind;
255 /* first option is the game type */
256 if (!game_type && c<argc)
257 game_type = strdup (argv[c++]);
258
259 /* Second option is the server name */
260 if (!server_ip && c<argc)
261 server_ip = strdup (argv[c++]);
262
263 return validate_arguments ();
264} 141}
265 142
266 143#define players_field_index 129
267int 144#define max_players_field_index 130
268validate_arguments (void) 145
269{ 146check_game_config_wrapper process_arguments(int argc, char **argv) {
270 if (qstat_game_players_max < 0) 147 static struct option long_opts[] = {{"help", no_argument, 0, 'h'},
271 qstat_game_players_max = 4; 148 {"version", no_argument, 0, 'V'},
272 149 {"verbose", no_argument, 0, 'v'},
273 if (qstat_game_players < 0) 150 {"timeout", required_argument, 0, 't'},
274 qstat_game_players = 5; 151 {"hostname", required_argument, 0, 'H'},
275 152 {"port", required_argument, 0, 'P'},
276 if (qstat_game_field < 0) 153 {"game-type", required_argument, 0, 'G'},
277 qstat_game_field = 2; 154 {"map-field", required_argument, 0, 'm'},
278 155 {"ping-field", required_argument, 0, 'p'},
279 if (qstat_map_field < 0) 156 {"game-field", required_argument, 0, 'g'},
280 qstat_map_field = 3; 157 {"players-field", required_argument, 0, players_field_index},
281 158 {"max-players-field", required_argument, 0, max_players_field_index},
282 if (qstat_ping_field < 0) 159 {0, 0, 0, 0}};
283 qstat_ping_field = 5; 160
284 161 check_game_config_wrapper result = {
285 return OK; 162 .config = check_game_config_init(),
163 .errorcode = OK,
164 };
165
166 if (argc < 2) {
167 result.errorcode = ERROR;
168 return result;
169 }
170
171 for (int option_counter = 1; option_counter < argc; option_counter++) {
172 if (strcmp("-mf", argv[option_counter]) == 0) {
173 strcpy(argv[option_counter], "-m");
174 } else if (strcmp("-pf", argv[option_counter]) == 0) {
175 strcpy(argv[option_counter], "-p");
176 } else if (strcmp("-gf", argv[option_counter]) == 0) {
177 strcpy(argv[option_counter], "-g");
178 }
179 }
180
181 int opt_index = 0;
182 while (true) {
183 int option_index = getopt_long(argc, argv, "hVvt:H:P:G:g:p:m:", long_opts, &opt_index);
184
185 if (option_index == -1 || option_index == EOF) {
186 break;
187 }
188
189 switch (option_index) {
190 case 'h': /* help */
191 print_help();
192 exit(STATE_UNKNOWN);
193 case 'V': /* version */
194 print_revision(progname, NP_VERSION);
195 exit(STATE_UNKNOWN);
196 case 'v': /* version */
197 verbose = true;
198 break;
199 case 't': /* timeout period */
200 timeout_interval = atoi(optarg);
201 break;
202 case 'H': /* hostname */
203 if (strlen(optarg) >= MAX_HOST_ADDRESS_LENGTH) {
204 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
205 }
206 result.config.server_ip = optarg;
207 break;
208 case 'P': /* port */
209 result.config.port = atoi(optarg);
210 break;
211 case 'G': /* hostname */
212 if (strlen(optarg) >= MAX_INPUT_BUFFER) {
213 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
214 }
215 result.config.game_type = optarg;
216 break;
217 case 'p': /* index of ping field */
218 result.config.qstat_ping_field = atoi(optarg);
219 if (result.config.qstat_ping_field < 0 || result.config.qstat_ping_field > QSTAT_MAX_RETURN_ARGS) {
220 result.errorcode = ERROR;
221 return result;
222 }
223 break;
224 case 'm': /* index on map field */
225 result.config.qstat_map_field = atoi(optarg);
226 if (result.config.qstat_map_field < 0 || result.config.qstat_map_field > QSTAT_MAX_RETURN_ARGS) {
227 result.errorcode = ERROR;
228 return result;
229 }
230 break;
231 case 'g': /* index of game field */
232 result.config.qstat_game_field = atoi(optarg);
233 if (result.config.qstat_game_field < 0 || result.config.qstat_game_field > QSTAT_MAX_RETURN_ARGS) {
234 result.errorcode = ERROR;
235 return result;
236 }
237 break;
238 case players_field_index: /* index of player count field */
239 result.config.qstat_game_players = atoi(optarg);
240 if (result.config.qstat_game_players_max == 0) {
241 result.config.qstat_game_players_max = result.config.qstat_game_players - 1;
242 }
243 if (result.config.qstat_game_players < 0 || result.config.qstat_game_players > QSTAT_MAX_RETURN_ARGS) {
244 result.errorcode = ERROR;
245 return result;
246 }
247 break;
248 case max_players_field_index: /* index of max players field */
249 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) {
251 result.errorcode = ERROR;
252 return result;
253 }
254 break;
255 default: /* args not parsable */
256 usage5();
257 }
258 }
259
260 int option_counter = optind;
261 /* first option is the game type */
262 if (!result.config.game_type && option_counter < argc) {
263 result.config.game_type = strdup(argv[option_counter++]);
264 }
265
266 /* Second option is the server name */
267 if (!result.config.server_ip && option_counter < argc) {
268 result.config.server_ip = strdup(argv[option_counter++]);
269 }
270
271 return result;
286} 272}
287 273
274void print_help(void) {
275 print_revision(progname, NP_VERSION);
288 276
289void 277 printf("Copyright (c) 1999 Ian Cass, Knowledge Matters Limited\n");
290print_help (void) 278 printf(COPYRIGHT, copyright, email);
291{
292 print_revision (progname, NP_VERSION);
293
294 printf ("Copyright (c) 1999 Ian Cass, Knowledge Matters Limited\n");
295 printf (COPYRIGHT, copyright, email);
296 279
297 printf (_("This plugin tests game server connections with the specified host.")); 280 printf(_("This plugin tests game server connections with the specified host."));
298 281
299 printf ("\n\n"); 282 printf("\n\n");
300 283
301 print_usage (); 284 print_usage();
302 285
303 printf (UT_HELP_VRSN); 286 printf(UT_HELP_VRSN);
304 printf (UT_EXTRA_OPTS); 287 printf(UT_EXTRA_OPTS);
288 printf(" -H, --hostname=ADDRESS\n"
289 " Host name, IP Address, or unix socket (must be an absolute path)\n");
290 printf(" %s\n", "-P");
291 printf(" %s\n", _("Optional port to connect to"));
292 printf(" %s\n", "-g");
293 printf(" %s\n", _("Field number in raw qstat output that contains game name"));
294 printf(" %s\n", "-m");
295 printf(" %s\n", _("Field number in raw qstat output that contains map name"));
296 printf(" %s\n", "-p");
297 printf(" %s\n", _("Field number in raw qstat output that contains ping time"));
305 298
306 printf (" %s\n", "-p"); 299 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
307 printf (" %s\n", _("Optional port of which to connect"));
308 printf (" %s\n", "gf");
309 printf (" %s\n", _("Field number in raw qstat output that contains game name"));
310 printf (" %s\n", "-mf");
311 printf (" %s\n", _("Field number in raw qstat output that contains map name"));
312 printf (" %s\n", "-pf");
313 printf (" %s\n", _("Field number in raw qstat output that contains ping time"));
314 300
315 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 301 printf("\n");
302 printf("%s\n", _("Notes:"));
303 printf(" %s\n", _("This plugin uses the 'qstat' command, the popular game server status query tool."));
304 printf(" %s\n", _("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 306
317 printf ("\n"); 307 printf(UT_SUPPORT);
318 printf ("%s\n", _("Notes:"));
319 printf (" %s\n", _("This plugin uses the 'qstat' command, the popular game server status query tool."));
320 printf (" %s\n", _("If you don't have the package installed, you will need to download it from"));
321 printf (" %s\n", _("https://github.com/multiplay/qstat before you can use this plugin."));
322
323 printf (UT_SUPPORT);
324} 308}
325 309
326 310void print_usage(void) {
327 311 printf("%s\n", _("Usage:"));
328void 312 printf(" %s [-hvV] [-P port] [-t timeout] [-g game_field] [-m map_field] [-p ping_field] [-G game-time] [-H hostname] <game> "
329print_usage (void) 313 "<ip_address>\n",
330{ 314 progname);
331 printf ("%s\n", _("Usage:"));
332 printf (" %s [-hvV] [-P port] [-t timeout] [-g game_field] [-m map_field] [-p ping_field] [-G game-time] [-H hostname] <game> <ip_address>\n", progname);
333} 315}
334 316
335/****************************************************************************** 317/******************************************************************************
diff --git a/plugins/check_game.d/config.h b/plugins/check_game.d/config.h
new file mode 100644
index 00000000..c95a1ced
--- /dev/null
+++ b/plugins/check_game.d/config.h
@@ -0,0 +1,30 @@
1#pragma once
2#include "../../config.h"
3#include <stddef.h>
4
5typedef struct {
6 char *server_ip;
7 char *game_type;
8 int port;
9
10 int qstat_game_players_max;
11 int qstat_game_players;
12 int qstat_game_field;
13 int qstat_map_field;
14 int qstat_ping_field;
15} check_game_config;
16
17check_game_config check_game_config_init() {
18 check_game_config tmp = {
19 .server_ip = NULL,
20 .game_type = NULL,
21 .port = 0,
22
23 .qstat_game_players_max = 4,
24 .qstat_game_players = 5,
25 .qstat_map_field = 3,
26 .qstat_game_field = 2,
27 .qstat_ping_field = 5,
28 };
29 return tmp;
30}
diff --git a/plugins/check_hpjd.c b/plugins/check_hpjd.c
index c34bb082..62417fd6 100644
--- a/plugins/check_hpjd.c
+++ b/plugins/check_hpjd.c
@@ -1,47 +1,46 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_hpjd plugin 3 * Monitoring check_hpjd plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2007 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_hpjd plugin 10 * This file contains the check_hpjd plugin
11* 11 *
12* This plugin tests the STATUS of an HP printer with a JetDirect card. 12 * This plugin tests the STATUS of an HP printer with a JetDirect card.
13* Net-SNMP must be installed on the computer running the plugin. 13 * Net-SNMP must be installed on the computer running the plugin.
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 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 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 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 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/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_hpjd"; 32const char *progname = "check_hpjd";
33const char *copyright = "2000-2007"; 33const char *copyright = "2000-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "common.h" 36#include "common.h"
37#include "popen.h" 37#include "popen.h"
38#include "utils.h" 38#include "utils.h"
39#include "netutils.h" 39#include "netutils.h"
40#include "states.h"
41#include "check_hpjd.d/config.h"
40 42
41#define DEFAULT_COMMUNITY "public" 43#define DEFAULT_COMMUNITY "public"
42#define DEFAULT_PORT "161"
43
44const char *option_summary = "-H host [-C community]\n";
45 44
46#define HPJD_LINE_STATUS ".1.3.6.1.4.1.11.2.3.9.1.1.2.1" 45#define HPJD_LINE_STATUS ".1.3.6.1.4.1.11.2.3.9.1.1.2.1"
47#define HPJD_PAPER_STATUS ".1.3.6.1.4.1.11.2.3.9.1.1.2.2" 46#define HPJD_PAPER_STATUS ".1.3.6.1.4.1.11.2.3.9.1.1.2.2"
@@ -56,185 +55,161 @@ const char *option_summary = "-H host [-C community]\n";
56#define HPJD_GD_PAPER_OUTPUT ".1.3.6.1.4.1.11.2.3.9.1.1.2.19" 55#define HPJD_GD_PAPER_OUTPUT ".1.3.6.1.4.1.11.2.3.9.1.1.2.19"
57#define HPJD_GD_STATUS_DISPLAY ".1.3.6.1.4.1.11.2.3.9.1.1.3" 56#define HPJD_GD_STATUS_DISPLAY ".1.3.6.1.4.1.11.2.3.9.1.1.3"
58 57
59#define ONLINE 0 58#define ONLINE 0
60#define OFFLINE 1 59#define OFFLINE 1
61
62int process_arguments (int, char **);
63int validate_arguments (void);
64void print_help (void);
65void print_usage (void);
66 60
67char *community = NULL; 61typedef struct {
68char *address = NULL; 62 int errorcode;
69unsigned int port = 0; 63 check_hpjd_config config;
70int check_paper_out = 1; 64} check_hpjd_config_wrapper;
65static check_hpjd_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
66static void print_help(void);
67void print_usage(void);
71 68
72int 69int main(int argc, char **argv) {
73main (int argc, char **argv) 70 setlocale(LC_ALL, "");
74{ 71 bindtextdomain(PACKAGE, LOCALEDIR);
75 char command_line[1024]; 72 textdomain(PACKAGE);
76 int result = STATE_UNKNOWN;
77 int line;
78 char input_buffer[MAX_INPUT_BUFFER];
79 char query_string[512];
80 char *errmsg;
81 char *temp_buffer;
82 int line_status = ONLINE;
83 int paper_status = 0;
84 int intervention_required = 0;
85 int peripheral_error = 0;
86 int paper_jam = 0;
87 int paper_out = 0;
88 int toner_low = 0;
89 int page_punt = 0;
90 int memory_out = 0;
91 int door_open = 0;
92 int paper_output = 0;
93 char display_message[MAX_INPUT_BUFFER];
94 73
95 errmsg = malloc(MAX_INPUT_BUFFER); 74 /* Parse extra opts if any */
75 argv = np_extra_opts(&argc, argv, progname);
96 76
97 setlocale (LC_ALL, ""); 77 check_hpjd_config_wrapper tmp_config = process_arguments(argc, argv);
98 bindtextdomain (PACKAGE, LOCALEDIR);
99 textdomain (PACKAGE);
100 78
101 /* Parse extra opts if any */ 79 if (tmp_config.errorcode == ERROR) {
102 argv=np_extra_opts (&argc, argv, progname); 80 usage4(_("Could not parse arguments"));
81 }
103 82
104 if (process_arguments (argc, argv) == ERROR) 83 const check_hpjd_config config = tmp_config.config;
105 usage4 (_("Could not parse arguments"));
106 84
85 char query_string[512];
107 /* removed ' 2>1' at end of command 10/27/1999 - EG */ 86 /* removed ' 2>1' at end of command 10/27/1999 - EG */
108 /* create the query string */ 87 /* create the query string */
109 sprintf 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,
110 (query_string, 89 HPJD_INTERVENTION_REQUIRED, HPJD_GD_PERIPHERAL_ERROR, HPJD_GD_PAPER_JAM, HPJD_GD_PAPER_OUT, HPJD_GD_TONER_LOW,
111 "%s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0", 90 HPJD_GD_PAGE_PUNT, HPJD_GD_MEMORY_OUT, HPJD_GD_DOOR_OPEN, HPJD_GD_PAPER_OUTPUT, HPJD_GD_STATUS_DISPLAY);
112 HPJD_LINE_STATUS,
113 HPJD_PAPER_STATUS,
114 HPJD_INTERVENTION_REQUIRED,
115 HPJD_GD_PERIPHERAL_ERROR,
116 HPJD_GD_PAPER_JAM,
117 HPJD_GD_PAPER_OUT,
118 HPJD_GD_TONER_LOW,
119 HPJD_GD_PAGE_PUNT,
120 HPJD_GD_MEMORY_OUT,
121 HPJD_GD_DOOR_OPEN, HPJD_GD_PAPER_OUTPUT, HPJD_GD_STATUS_DISPLAY);
122 91
123 /* get the command to run */ 92 /* get the command to run */
124 sprintf (command_line, "%s -OQa -m : -v 1 -c %s %s:%u %s", 93 char command_line[1024];
125 PATH_TO_SNMPGET, 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);
126 community,
127 address,
128 port,
129 query_string);
130 95
131 /* run the command */ 96 /* run the command */
132 child_process = spopen (command_line); 97 child_process = spopen(command_line);
133 if (child_process == NULL) { 98 if (child_process == NULL) {
134 printf (_("Could not open pipe: %s\n"), command_line); 99 printf(_("Could not open pipe: %s\n"), command_line);
135 return STATE_UNKNOWN; 100 return STATE_UNKNOWN;
136 } 101 }
137 102
138 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); 103 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
139 if (child_stderr == NULL) { 104 if (child_stderr == NULL) {
140 printf (_("Could not open stderr for %s\n"), command_line); 105 printf(_("Could not open stderr for %s\n"), command_line);
141 } 106 }
142 107
143 result = STATE_OK; 108 mp_state_enum result = STATE_OK;
144 109
145 line = 0; 110 int line_status = ONLINE;
146 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) { 111 int paper_status = 0;
112 int intervention_required = 0;
113 int peripheral_error = 0;
114 int paper_jam = 0;
115 int paper_out = 0;
116 int toner_low = 0;
117 int page_punt = 0;
118 int memory_out = 0;
119 int door_open = 0;
120 int paper_output = 0;
121 char display_message[MAX_INPUT_BUFFER];
122
123 char input_buffer[MAX_INPUT_BUFFER];
124 char *errmsg = malloc(MAX_INPUT_BUFFER);
125 int line = 0;
147 126
127 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
148 /* strip the newline character from the end of the input */ 128 /* strip the newline character from the end of the input */
149 if (input_buffer[strlen (input_buffer) - 1] == '\n') 129 if (input_buffer[strlen(input_buffer) - 1] == '\n') {
150 input_buffer[strlen (input_buffer) - 1] = 0; 130 input_buffer[strlen(input_buffer) - 1] = 0;
131 }
151 132
152 line++; 133 line++;
153 134
154 temp_buffer = strtok (input_buffer, "="); 135 char *temp_buffer = strtok(input_buffer, "=");
155 temp_buffer = strtok (NULL, "="); 136 temp_buffer = strtok(NULL, "=");
156 137
157 if (temp_buffer == NULL && line < 13) { 138 if (temp_buffer == NULL && line < 13) {
158 139 result = STATE_UNKNOWN;
159 result = STATE_UNKNOWN; 140 strcpy(errmsg, input_buffer);
160 strcpy (errmsg, input_buffer);
161
162 } else { 141 } else {
163
164 switch (line) { 142 switch (line) {
165 143 case 1: /* 1st line should contain the line status */
166 case 1: /* 1st line should contain the line status */ 144 line_status = atoi(temp_buffer);
167 line_status = atoi (temp_buffer);
168 break; 145 break;
169 case 2: /* 2nd line should contain the paper status */ 146 case 2: /* 2nd line should contain the paper status */
170 paper_status = atoi (temp_buffer); 147 paper_status = atoi(temp_buffer);
171 break; 148 break;
172 case 3: /* 3rd line should be intervention required */ 149 case 3: /* 3rd line should be intervention required */
173 intervention_required = atoi (temp_buffer); 150 intervention_required = atoi(temp_buffer);
174 break; 151 break;
175 case 4: /* 4th line should be peripheral error */ 152 case 4: /* 4th line should be peripheral error */
176 peripheral_error = atoi (temp_buffer); 153 peripheral_error = atoi(temp_buffer);
177 break; 154 break;
178 case 5: /* 5th line should contain the paper jam status */ 155 case 5: /* 5th line should contain the paper jam status */
179 paper_jam = atoi (temp_buffer); 156 paper_jam = atoi(temp_buffer);
180 break; 157 break;
181 case 6: /* 6th line should contain the paper out status */ 158 case 6: /* 6th line should contain the paper out status */
182 paper_out = atoi (temp_buffer); 159 paper_out = atoi(temp_buffer);
183 break; 160 break;
184 case 7: /* 7th line should contain the toner low status */ 161 case 7: /* 7th line should contain the toner low status */
185 toner_low = atoi (temp_buffer); 162 toner_low = atoi(temp_buffer);
186 break; 163 break;
187 case 8: /* did data come too slow for engine */ 164 case 8: /* did data come too slow for engine */
188 page_punt = atoi (temp_buffer); 165 page_punt = atoi(temp_buffer);
189 break; 166 break;
190 case 9: /* did we run out of memory */ 167 case 9: /* did we run out of memory */
191 memory_out = atoi (temp_buffer); 168 memory_out = atoi(temp_buffer);
192 break; 169 break;
193 case 10: /* is there a door open */ 170 case 10: /* is there a door open */
194 door_open = atoi (temp_buffer); 171 door_open = atoi(temp_buffer);
195 break; 172 break;
196 case 11: /* is output tray full */ 173 case 11: /* is output tray full */
197 paper_output = atoi (temp_buffer); 174 paper_output = atoi(temp_buffer);
198 break; 175 break;
199 case 12: /* display panel message */ 176 case 12: /* display panel message */
200 strcpy (display_message, temp_buffer + 1); 177 strcpy(display_message, temp_buffer + 1);
201 break; 178 break;
202 default: /* fold multiline message */ 179 default: /* fold multiline message */
203 strncat (display_message, input_buffer, 180 strncat(display_message, input_buffer, sizeof(display_message) - strlen(display_message) - 1);
204 sizeof (display_message) - strlen (display_message) - 1);
205 } 181 }
206
207 } 182 }
208 183
209 /* break out of the read loop if we encounter an error */ 184 /* break out of the read loop if we encounter an error */
210 if (result != STATE_OK) 185 if (result != STATE_OK) {
211 break; 186 break;
187 }
212 } 188 }
213 189
214 /* WARNING if output found on stderr */ 190 /* WARNING if output found on stderr */
215 if (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) { 191 if (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
216 result = max_state (result, STATE_WARNING); 192 result = max_state(result, STATE_WARNING);
217 /* remove CRLF */ 193 /* remove CRLF */
218 if (input_buffer[strlen (input_buffer) - 1] == '\n') 194 if (input_buffer[strlen(input_buffer) - 1] == '\n') {
219 input_buffer[strlen (input_buffer) - 1] = 0; 195 input_buffer[strlen(input_buffer) - 1] = 0;
220 sprintf (errmsg, "%s", input_buffer ); 196 }
221 197 sprintf(errmsg, "%s", input_buffer);
222 } 198 }
223 199
224 /* close stderr */ 200 /* close stderr */
225 (void) fclose (child_stderr); 201 (void)fclose(child_stderr);
226 202
227 /* close the pipe */ 203 /* close the pipe */
228 if (spclose (child_process)) 204 if (spclose(child_process)) {
229 result = max_state (result, STATE_WARNING); 205 result = max_state(result, STATE_WARNING);
206 }
230 207
231 /* if there wasn't any output, display an error */ 208 /* if there wasn't any output, display an error */
232 if (line == 0) { 209 if (line == 0) {
233
234 /* might not be the problem, but most likely is. */ 210 /* might not be the problem, but most likely is. */
235 result = STATE_UNKNOWN ; 211 result = STATE_UNKNOWN;
236 xasprintf (&errmsg, "%s : Timeout from host %s\n", errmsg, address ); 212 xasprintf(&errmsg, "%s : Timeout from host %s\n", errmsg, config.address);
237
238 } 213 }
239 214
240 /* if we had no read errors, check the printer status results... */ 215 /* if we had no read errors, check the printer status results... */
@@ -242,201 +217,171 @@ main (int argc, char **argv)
242 217
243 if (paper_jam) { 218 if (paper_jam) {
244 result = STATE_WARNING; 219 result = STATE_WARNING;
245 strcpy (errmsg, _("Paper Jam")); 220 strcpy(errmsg, _("Paper Jam"));
246 } 221 } else if (paper_out) {
247 else if (paper_out) { 222 if (config.check_paper_out) {
248 if (check_paper_out)
249 result = STATE_WARNING; 223 result = STATE_WARNING;
250 strcpy (errmsg, _("Out of Paper")); 224 }
251 } 225 strcpy(errmsg, _("Out of Paper"));
252 else if (line_status == OFFLINE) { 226 } else if (line_status == OFFLINE) {
253 if (strcmp (errmsg, "POWERSAVE ON") != 0) { 227 if (strcmp(errmsg, "POWERSAVE ON") != 0) {
254 result = STATE_WARNING; 228 result = STATE_WARNING;
255 strcpy (errmsg, _("Printer Offline")); 229 strcpy(errmsg, _("Printer Offline"));
256 } 230 }
257 } 231 } else if (peripheral_error) {
258 else if (peripheral_error) {
259 result = STATE_WARNING; 232 result = STATE_WARNING;
260 strcpy (errmsg, _("Peripheral Error")); 233 strcpy(errmsg, _("Peripheral Error"));
261 } 234 } else if (intervention_required) {
262 else if (intervention_required) {
263 result = STATE_WARNING; 235 result = STATE_WARNING;
264 strcpy (errmsg, _("Intervention Required")); 236 strcpy(errmsg, _("Intervention Required"));
265 } 237 } else if (toner_low) {
266 else if (toner_low) {
267 result = STATE_WARNING; 238 result = STATE_WARNING;
268 strcpy (errmsg, _("Toner Low")); 239 strcpy(errmsg, _("Toner Low"));
269 } 240 } else if (memory_out) {
270 else if (memory_out) {
271 result = STATE_WARNING; 241 result = STATE_WARNING;
272 strcpy (errmsg, _("Insufficient Memory")); 242 strcpy(errmsg, _("Insufficient Memory"));
273 } 243 } else if (door_open) {
274 else if (door_open) {
275 result = STATE_WARNING; 244 result = STATE_WARNING;
276 strcpy (errmsg, _("A Door is Open")); 245 strcpy(errmsg, _("A Door is Open"));
277 } 246 } else if (paper_output) {
278 else if (paper_output) {
279 result = STATE_WARNING; 247 result = STATE_WARNING;
280 strcpy (errmsg, _("Output Tray is Full")); 248 strcpy(errmsg, _("Output Tray is Full"));
281 } 249 } else if (page_punt) {
282 else if (page_punt) {
283 result = STATE_WARNING; 250 result = STATE_WARNING;
284 strcpy (errmsg, _("Data too Slow for Engine")); 251 strcpy(errmsg, _("Data too Slow for Engine"));
285 } 252 } else if (paper_status) {
286 else if (paper_status) {
287 result = STATE_WARNING; 253 result = STATE_WARNING;
288 strcpy (errmsg, _("Unknown Paper Error")); 254 strcpy(errmsg, _("Unknown Paper Error"));
289 } 255 }
290 } 256 }
291 257
292 if (result == STATE_OK) 258 if (result == STATE_OK) {
293 printf (_("Printer ok - (%s)\n"), display_message); 259 printf(_("Printer ok - (%s)\n"), display_message);
294 260 } else if (result == STATE_UNKNOWN) {
295 else if (result == STATE_UNKNOWN) { 261 printf("%s\n", errmsg);
296
297 printf ("%s\n", errmsg);
298
299 /* if printer could not be reached, escalate to critical */ 262 /* if printer could not be reached, escalate to critical */
300 if (strstr (errmsg, "Timeout")) 263 if (strstr(errmsg, "Timeout")) {
301 result = STATE_CRITICAL; 264 result = STATE_CRITICAL;
265 }
266 } else if (result == STATE_WARNING) {
267 printf("%s (%s)\n", errmsg, display_message);
302 } 268 }
303 269
304 else if (result == STATE_WARNING) 270 exit(result);
305 printf ("%s (%s)\n", errmsg, display_message);
306
307 return result;
308} 271}
309 272
310
311/* process command-line arguments */ 273/* process command-line arguments */
312int 274check_hpjd_config_wrapper process_arguments(int argc, char **argv) {
313process_arguments (int argc, char **argv) 275 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
314{ 276 {"community", required_argument, 0, 'C'},
315 int c; 277 /* {"critical", required_argument,0,'c'}, */
316 278 /* {"warning", required_argument,0,'w'}, */
317 int option = 0; 279 {"port", required_argument, 0, 'p'},
318 static struct option longopts[] = { 280 {"version", no_argument, 0, 'V'},
319 {"hostname", required_argument, 0, 'H'}, 281 {"help", no_argument, 0, 'h'},
320 {"community", required_argument, 0, 'C'}, 282 {0, 0, 0, 0}};
321/* {"critical", required_argument,0,'c'}, */ 283
322/* {"warning", required_argument,0,'w'}, */ 284 check_hpjd_config_wrapper result = {
323 {"port", required_argument,0,'p'}, 285 .errorcode = OK,
324 {"version", no_argument, 0, 'V'}, 286 .config = check_hpjd_config_init(),
325 {"help", no_argument, 0, 'h'},
326 {0, 0, 0, 0}
327 }; 287 };
328 288
329 if (argc < 2) 289 if (argc < 2) {
330 return ERROR; 290 result.errorcode = ERROR;
331 291 return result;
292 }
332 293
333 while (1) { 294 int option = 0;
334 c = getopt_long (argc, argv, "+hVH:C:p:D", longopts, &option); 295 while (true) {
296 int option_index = getopt_long(argc, argv, "+hVH:C:p:D", longopts, &option);
335 297
336 if (c == -1 || c == EOF || c == 1) 298 if (option_index == -1 || option_index == EOF || option_index == 1) {
337 break; 299 break;
300 }
338 301
339 switch (c) { 302 switch (option_index) {
340 case 'H': /* hostname */ 303 case 'H': /* hostname */
341 if (is_host (optarg)) { 304 if (is_host(optarg)) {
342 address = strscpy(address, optarg) ; 305 result.config.address = strscpy(result.config.address, optarg);
343 } 306 } else {
344 else { 307 usage2(_("Invalid hostname/address"), optarg);
345 usage2 (_("Invalid hostname/address"), optarg);
346 } 308 }
347 break; 309 break;
348 case 'C': /* community */ 310 case 'C': /* community */
349 community = strscpy (community, optarg); 311 result.config.community = strscpy(result.config.community, optarg);
350 break; 312 break;
351 case 'p': 313 case 'p':
352 if (!is_intpos(optarg)) 314 if (!is_intpos(optarg)) {
353 usage2 (_("Port must be a positive short integer"), optarg); 315 usage2(_("Port must be a positive short integer"), optarg);
354 else 316 } else {
355 port = atoi(optarg); 317 result.config.port = atoi(optarg);
318 }
356 break; 319 break;
357 case 'D': /* disable paper out check*/ 320 case 'D': /* disable paper out check*/
358 check_paper_out = 0; 321 result.config.check_paper_out = false;
359 break; 322 break;
360 case 'V': /* version */ 323 case 'V': /* version */
361 print_revision (progname, NP_VERSION); 324 print_revision(progname, NP_VERSION);
362 exit (STATE_UNKNOWN); 325 exit(STATE_UNKNOWN);
363 case 'h': /* help */ 326 case 'h': /* help */
364 print_help (); 327 print_help();
365 exit (STATE_UNKNOWN); 328 exit(STATE_UNKNOWN);
366 case '?': /* help */ 329 case '?': /* help */
367 usage5 (); 330 usage5();
368 } 331 }
369 } 332 }
370 333
371 c = optind; 334 int c = optind;
372 if (address == NULL) { 335 if (result.config.address == NULL) {
373 if (is_host (argv[c])) { 336 if (is_host(argv[c])) {
374 address = argv[c++]; 337 result.config.address = argv[c++];
375 } 338 } else {
376 else { 339 usage2(_("Invalid hostname/address"), argv[c]);
377 usage2 (_("Invalid hostname/address"), argv[c]);
378 } 340 }
379 } 341 }
380 342
381 if (community == NULL) { 343 if (result.config.community == NULL) {
382 if (argv[c] != NULL ) 344 if (argv[c] != NULL) {
383 community = argv[c]; 345 result.config.community = argv[c];
384 else 346 } else {
385 community = strdup (DEFAULT_COMMUNITY); 347 result.config.community = strdup(DEFAULT_COMMUNITY);
386 } 348 }
387
388 if (port == 0) {
389 port = atoi(DEFAULT_PORT);
390 } 349 }
391 350
392 return validate_arguments (); 351 return result;
393}
394
395
396int
397validate_arguments (void)
398{
399 return OK;
400} 352}
401 353
354void print_help(void) {
355 print_revision(progname, NP_VERSION);
402 356
403void 357 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
404print_help (void) 358 printf(COPYRIGHT, copyright, email);
405{
406 print_revision (progname, NP_VERSION);
407
408 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
409 printf (COPYRIGHT, copyright, email);
410 359
411 printf ("%s\n", _("This plugin tests the STATUS of an HP printer with a JetDirect card.")); 360 printf("%s\n", _("This plugin tests the STATUS of an HP printer with a JetDirect card."));
412 printf ("%s\n", _("Net-snmp must be installed on the computer running the plugin.")); 361 printf("%s\n", _("Net-snmp must be installed on the computer running the plugin."));
413 362
414 printf ("\n\n"); 363 printf("\n\n");
415 364
416 print_usage (); 365 print_usage();
417 366
418 printf (UT_HELP_VRSN); 367 printf(UT_HELP_VRSN);
419 printf (UT_EXTRA_OPTS); 368 printf(UT_EXTRA_OPTS);
420 369
421 printf (" %s\n", "-C, --community=STRING"); 370 printf(" %s\n", "-C, --community=STRING");
422 printf (" %s", _("The SNMP community name ")); 371 printf(" %s", _("The SNMP community name "));
423 printf (_("(default=%s)"), DEFAULT_COMMUNITY); 372 printf(_("(default=%s)"), DEFAULT_COMMUNITY);
424 printf ("\n"); 373 printf("\n");
425 printf (" %s\n", "-p, --port=STRING"); 374 printf(" %s\n", "-p, --port=STRING");
426 printf (" %s", _("Specify the port to check ")); 375 printf(" %s", _("Specify the port to check "));
427 printf (_("(default=%s)"), DEFAULT_PORT); 376 printf(_("(default=%s)"), DEFAULT_PORT);
428 printf ("\n"); 377 printf("\n");
429 printf (" %s\n", "-D"); 378 printf(" %s\n", "-D");
430 printf (" %s", _("Disable paper check ")); 379 printf(" %s", _("Disable paper check "));
431 380
432 printf (UT_SUPPORT); 381 printf(UT_SUPPORT);
433} 382}
434 383
435 384void print_usage(void) {
436 385 printf("%s\n", _("Usage:"));
437void 386 printf("%s -H host [-C community] [-p port] [-D]\n", progname);
438print_usage (void)
439{
440 printf ("%s\n", _("Usage:"));
441 printf ("%s -H host [-C community] [-p port] [-D]\n", progname);
442} 387}
diff --git a/plugins/check_hpjd.d/config.h b/plugins/check_hpjd.d/config.h
new file mode 100644
index 00000000..e36b7972
--- /dev/null
+++ b/plugins/check_hpjd.d/config.h
@@ -0,0 +1,25 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5#include <stdlib.h>
6
7#define DEFAULT_PORT "161"
8
9typedef struct {
10 char *address;
11 char *community;
12 unsigned int port;
13 bool check_paper_out;
14
15} check_hpjd_config;
16
17check_hpjd_config check_hpjd_config_init() {
18 check_hpjd_config tmp = {
19 .address = NULL,
20 .community = NULL,
21 .port = (unsigned int)atoi(DEFAULT_PORT),
22 .check_paper_out = true,
23 };
24 return tmp;
25}
diff --git a/plugins/check_http.c b/plugins/check_http.c
index cdf768c9..8e0c15ec 100644
--- a/plugins/check_http.c
+++ b/plugins/check_http.c
@@ -3,7 +3,7 @@
3* Monitoring check_http plugin 3* Monitoring check_http plugin
4* 4*
5* License: GPL 5* License: GPL
6* Copyright (c) 1999-2013 Monitoring Plugins Development Team 6* Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7*
8* Description: 8* Description:
9* 9*
@@ -32,7 +32,7 @@
32*****************************************************************************/ 32*****************************************************************************/
33 33
34const char *progname = "check_http"; 34const char *progname = "check_http";
35const char *copyright = "1999-2022"; 35const char *copyright = "1999-2024";
36const char *email = "devel@monitoring-plugins.org"; 36const char *email = "devel@monitoring-plugins.org";
37 37
38// Do NOT sort those headers, it will break the build 38// Do NOT sort those headers, it will break the build
@@ -1724,6 +1724,16 @@ print_help (void)
1724 printf ("%s\n", _("strings and regular expressions, check connection times, and report on")); 1724 printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
1725 printf ("%s\n", _("certificate expiration times.")); 1725 printf ("%s\n", _("certificate expiration times."));
1726 1726
1727 printf ("\n");
1728 printf ("%s\n", _("ATTENTION!"));
1729 printf ("\n");
1730 printf ("%s\n", _("THIS PLUGIN IS DEPRECATED. The functionality was reimplemented by the"));
1731 printf ("%s\n", _("check_curl plugin, which can be used as a drop-in replacement. You should"));
1732 printf ("%s\n", _("migrate your checks over to check_curl, because check_http is going to be"));
1733 printf ("%s\n", _("removed sooner than later. Just replace check_http with check_curl in your"));
1734 printf ("%s\n", _("check command definitions."));
1735 printf ("%s\n", _("Report issues to: https://github.com/monitoring-plugins/monitoring-plugins/issues"));
1736
1727 printf ("\n\n"); 1737 printf ("\n\n");
1728 1738
1729 print_usage (); 1739 print_usage ();
@@ -1805,7 +1815,7 @@ print_help (void)
1805 printf (" %s\n", "--invert-regex"); 1815 printf (" %s\n", "--invert-regex");
1806 printf (" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)")); 1816 printf (" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)"));
1807 printf (" %s\n", _("can be changed with --state--regex)")); 1817 printf (" %s\n", _("can be changed with --state--regex)"));
1808 printf (" %s\n", "--regex-state=STATE"); 1818 printf (" %s\n", "--state-regex=STATE");
1809 printf (" %s\n", _("Return STATE if regex is found, OK if not\n")); 1819 printf (" %s\n", _("Return STATE if regex is found, OK if not\n"));
1810 1820
1811 printf (" %s\n", "-a, --authorization=AUTH_PAIR"); 1821 printf (" %s\n", "-a, --authorization=AUTH_PAIR");
diff --git a/plugins/check_ide_smart.c b/plugins/check_ide_smart.c
index 3872e341..16fe3d01 100644
--- a/plugins/check_ide_smart.c
+++ b/plugins/check_ide_smart.c
@@ -1,240 +1,211 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_ide_smart plugin 3 * Monitoring check_ide_smart plugin
4* ide-smart 1.3 - IDE S.M.A.R.T. checking tool 4 * ide-smart 1.3 - IDE S.M.A.R.T. checking tool
5* 5 *
6* License: GPL 6 * License: GPL
7* Copyright (C) 1998-1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org> 7 * Copyright (C) 1998-1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>
8* 1998 Gadi Oxman <gadio@netvision.net.il> 8 * 1998 Gadi Oxman <gadio@netvision.net.il>
9* Copyright (c) 2000 Robert Dale <rdale@digital-mission.com> 9 * Copyright (c) 2000 Robert Dale <rdale@digital-mission.com>
10* Copyright (c) 2000-2007 Monitoring Plugins Development Team 10 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
11* 11 *
12* Description: 12 * Description:
13* 13 *
14* This file contains the check_ide_smart plugin 14 * This file contains the check_ide_smart plugin
15* 15 *
16* This plugin checks a local hard drive with the (Linux specific) SMART 16 * This plugin checks a local hard drive with the (Linux specific) SMART
17* interface 17 * interface
18* 18 *
19* 19 *
20* This program is free software: you can redistribute it and/or modify 20 * This program is free software: you can redistribute it and/or modify
21* it under the terms of the GNU General Public License as published by 21 * it under the terms of the GNU General Public License as published by
22* the Free Software Foundation, either version 3 of the License, or 22 * the Free Software Foundation, either version 3 of the License, or
23* (at your option) any later version. 23 * (at your option) any later version.
24* 24 *
25* This program is distributed in the hope that it will be useful, 25 * This program is distributed in the hope that it will be useful,
26* but WITHOUT ANY WARRANTY; without even the implied warranty of 26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28* GNU General Public License for more details. 28 * GNU General Public License for more details.
29* 29 *
30* You should have received a copy of the GNU General Public License 30 * You should have received a copy of the GNU General Public License
31* along with this program. If not, see <http://www.gnu.org/licenses/>. 31 * along with this program. If not, see <http://www.gnu.org/licenses/>.
32* 32 *
33* 33 *
34*****************************************************************************/ 34 *****************************************************************************/
35 35
36const char *progname = "check_ide_smart"; 36const char *progname = "check_ide_smart";
37const char *copyright = "1998-2007"; 37const char *copyright = "1998-2024";
38const char *email = "devel@monitoring-plugins.org"; 38const char *email = "devel@monitoring-plugins.org";
39 39
40#include "common.h" 40#include "common.h"
41#include "utils.h" 41#include "utils.h"
42 42
43void print_help (void); 43static void print_help(void);
44void print_usage (void); 44void print_usage(void);
45 45
46#include <sys/stat.h> 46#include <sys/stat.h>
47#include <sys/ioctl.h> 47#include <sys/ioctl.h>
48#include <fcntl.h> 48#include <fcntl.h>
49#ifdef __linux__ 49#ifdef __linux__
50#include <linux/hdreg.h> 50# include <linux/hdreg.h>
51#include <linux/types.h> 51# include <linux/types.h>
52 52
53#define OPEN_MODE O_RDONLY 53# define OPEN_MODE O_RDONLY
54#endif /* __linux__ */ 54#endif /* __linux__ */
55#ifdef __NetBSD__ 55#ifdef __NetBSD__
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 */ 59# include <sys/scsiio.h>
60#include <sys/scsiio.h> 60# include <sys/ataio.h>
61#include <sys/ataio.h> 61# include <dev/ata/atareg.h>
62#include <dev/ata/atareg.h> 62# include <dev/ic/wdcreg.h>
63#include <dev/ic/wdcreg.h> 63
64 64# define SMART_ENABLE WDSM_ENABLE_OPS
65#define SMART_ENABLE WDSM_ENABLE_OPS 65# define SMART_DISABLE WDSM_DISABLE_OPS
66#define SMART_DISABLE WDSM_DISABLE_OPS 66# define SMART_IMMEDIATE_OFFLINE WDSM_EXEC_OFFL_IMM
67#define SMART_IMMEDIATE_OFFLINE WDSM_EXEC_OFFL_IMM 67# define SMART_AUTO_OFFLINE 0xdb /* undefined in NetBSD headers */
68#define SMART_AUTO_OFFLINE 0xdb /* undefined in NetBSD headers */ 68
69 69# define OPEN_MODE O_RDWR
70#define OPEN_MODE O_RDWR
71#endif /* __NetBSD__ */ 70#endif /* __NetBSD__ */
72#include <errno.h> 71#include <errno.h>
73 72
74#define NR_ATTRIBUTES 30 73#define NR_ATTRIBUTES 30
75 74
76#define PREFAILURE 2 75#define PREFAILURE 2
77#define ADVISORY 1 76#define ADVISORY 1
78#define OPERATIONAL 0 77#define OPERATIONAL 0
79#define UNKNOWN -1 78#define UNKNOWN -1
80 79
81typedef struct threshold_s 80typedef struct threshold_s {
82{ 81 uint8_t id;
83 __u8 id; 82 uint8_t threshold;
84 __u8 threshold; 83 uint8_t reserved[10];
85 __u8 reserved[10]; 84} __attribute__((packed)) threshold_t;
86}
87__attribute__ ((packed)) threshold_t;
88 85
89typedef struct thresholds_s 86typedef struct thresholds_s {
90{ 87 uint16_t revision;
91 __u16 revision;
92 threshold_t thresholds[NR_ATTRIBUTES]; 88 threshold_t thresholds[NR_ATTRIBUTES];
93 __u8 reserved[18]; 89 uint8_t reserved[18];
94 __u8 vendor[131]; 90 uint8_t vendor[131];
95 __u8 checksum; 91 uint8_t checksum;
96} 92} __attribute__((packed)) thresholds_t;
97__attribute__ ((packed)) thresholds_t; 93
98 94typedef struct value_s {
99typedef struct value_s 95 uint8_t id;
100{ 96 uint16_t status;
101 __u8 id; 97 uint8_t value;
102 __u16 status; 98 uint8_t vendor[8];
103 __u8 value; 99} __attribute__((packed)) value_t;
104 __u8 vendor[8]; 100
105} 101typedef struct values_s {
106__attribute__ ((packed)) value_t; 102 uint16_t revision;
107
108typedef struct values_s
109{
110 __u16 revision;
111 value_t values[NR_ATTRIBUTES]; 103 value_t values[NR_ATTRIBUTES];
112 __u8 offline_status; 104 uint8_t offline_status;
113 __u8 vendor1; 105 uint8_t vendor1;
114 __u16 offline_timeout; 106 uint16_t offline_timeout;
115 __u8 vendor2; 107 uint8_t vendor2;
116 __u8 offline_capability; 108 uint8_t offline_capability;
117 __u16 smart_capability; 109 uint16_t smart_capability;
118 __u8 reserved[16]; 110 uint8_t reserved[16];
119 __u8 vendor[125]; 111 uint8_t vendor[125];
120 __u8 checksum; 112 uint8_t checksum;
121} 113} __attribute__((packed)) values_t;
122__attribute__ ((packed)) values_t; 114
123 115static struct {
124struct 116 uint8_t value;
125{
126 __u8 value;
127 char *text; 117 char *text;
128} 118} offline_status_text[] = {{0x00, "NeverStarted"}, {0x02, "Completed"}, {0x04, "Suspended"}, {0x05, "Aborted"}, {0x06, "Failed"}, {0, 0}};
129 119
130offline_status_text[] = 120static struct {
131 { 121 uint8_t value;
132 {0x00, "NeverStarted"},
133 {0x02, "Completed"},
134 {0x04, "Suspended"},
135 {0x05, "Aborted"},
136 {0x06, "Failed"},
137 {0, 0}
138 };
139
140struct
141{
142 __u8 value;
143 char *text; 122 char *text;
144} 123} smart_command[] = {{SMART_ENABLE, "SMART_ENABLE"},
145 124 {SMART_DISABLE, "SMART_DISABLE"},
146smart_command[] = 125 {SMART_IMMEDIATE_OFFLINE, "SMART_IMMEDIATE_OFFLINE"},
147 { 126 {SMART_AUTO_OFFLINE, "SMART_AUTO_OFFLINE"}};
148 {SMART_ENABLE, "SMART_ENABLE"}, 127
149 {SMART_DISABLE, "SMART_DISABLE"}, 128/* Index to smart_command table, keep in order */
150 {SMART_IMMEDIATE_OFFLINE, "SMART_IMMEDIATE_OFFLINE"}, 129enum SmartCommand {
151 {SMART_AUTO_OFFLINE, "SMART_AUTO_OFFLINE"} 130 SMART_CMD_ENABLE,
152 }; 131 SMART_CMD_DISABLE,
153 132 SMART_CMD_IMMEDIATE_OFFLINE,
154 133 SMART_CMD_AUTO_OFFLINE
155/* Index to smart_command table, keep in order */ 134};
156enum SmartCommand 135
157 { SMART_CMD_ENABLE, 136static char *get_offline_text(int);
158 SMART_CMD_DISABLE, 137static int smart_read_values(int, values_t *);
159 SMART_CMD_IMMEDIATE_OFFLINE, 138static int nagios(values_t *, thresholds_t *);
160 SMART_CMD_AUTO_OFFLINE 139static void print_value(value_t *, threshold_t *);
161 }; 140static void print_values(values_t *, thresholds_t *);
162 141static int smart_cmd_simple(int, enum SmartCommand, uint8_t, bool);
163char *get_offline_text (int); 142static int smart_read_thresholds(int, thresholds_t *);
164int smart_read_values (int, values_t *); 143static bool verbose = false;
165int nagios (values_t *, thresholds_t *); 144
166void print_value (value_t *, threshold_t *); 145int main(int argc, char *argv[]) {
167void print_values (values_t *, thresholds_t *);
168int smart_cmd_simple (int, enum SmartCommand, __u8, bool);
169int smart_read_thresholds (int, thresholds_t *);
170bool verbose = false;
171
172int
173main (int argc, char *argv[])
174{
175 char *device = NULL; 146 char *device = NULL;
176 int o, longindex; 147 int o;
148 int longindex;
177 int retval = 0; 149 int retval = 0;
178 150
179 thresholds_t thresholds; 151 thresholds_t thresholds;
180 values_t values; 152 values_t values;
181 int fd; 153 int fd;
182 154
183 static struct option longopts[] = { 155 static struct option longopts[] = {{"device", required_argument, 0, 'd'},
184 {"device", required_argument, 0, 'd'}, 156 {"immediate", no_argument, 0, 'i'},
185 {"immediate", no_argument, 0, 'i'}, 157 {"quiet-check", no_argument, 0, 'q'},
186 {"quiet-check", no_argument, 0, 'q'}, 158 {"auto-on", no_argument, 0, '1'},
187 {"auto-on", no_argument, 0, '1'}, 159 {"auto-off", no_argument, 0, '0'},
188 {"auto-off", no_argument, 0, '0'}, 160 {"nagios", no_argument, 0, 'n'}, /* DEPRECATED, but we still accept it */
189 {"nagios", no_argument, 0, 'n'}, /* DEPRECATED, but we still accept it */ 161 {"help", no_argument, 0, 'h'},
190 {"help", no_argument, 0, 'h'}, 162 {"version", no_argument, 0, 'V'},
191 {"version", no_argument, 0, 'V'}, 163 {0, 0, 0, 0}};
192 {0, 0, 0, 0}
193 };
194 164
195 /* Parse extra opts if any */ 165 /* Parse extra opts if any */
196 argv=np_extra_opts (&argc, argv, progname); 166 argv = np_extra_opts(&argc, argv, progname);
197 167
198 setlocale (LC_ALL, ""); 168 setlocale(LC_ALL, "");
199 bindtextdomain (PACKAGE, LOCALEDIR); 169 bindtextdomain(PACKAGE, LOCALEDIR);
200 textdomain (PACKAGE); 170 textdomain(PACKAGE);
201 171
202 while (true) { 172 while (true) {
203
204 o = getopt_long (argc, argv, "+d:iq10nhVv", longopts, &longindex);
205 173
206 if (o == -1 || o == EOF || o == 1) 174 o = getopt_long(argc, argv, "+d:iq10nhVv", longopts, &longindex);
175
176 if (o == -1 || o == EOF || o == 1) {
207 break; 177 break;
178 }
208 179
209 switch (o) { 180 switch (o) {
210 case 'd': 181 case 'd':
211 device = optarg; 182 device = optarg;
212 break; 183 break;
213 case 'q': 184 case 'q':
214 fprintf (stderr, "%s\n", _("DEPRECATION WARNING: the -q switch (quiet output) is no longer \"quiet\".")); 185 fprintf(stderr, "%s\n", _("DEPRECATION WARNING: the -q switch (quiet output) is no longer \"quiet\"."));
215 fprintf (stderr, "%s\n", _("Nagios-compatible output is now always returned.")); 186 fprintf(stderr, "%s\n", _("Nagios-compatible output is now always returned."));
216 break; 187 break;
217 case 'i': 188 case 'i':
218 case '1': 189 case '1':
219 case '0': 190 case '0':
220 printf ("%s\n", _("SMART commands are broken and have been disabled (See Notes in --help).")); 191 printf("%s\n", _("SMART commands are broken and have been disabled (See Notes in --help)."));
221 return STATE_CRITICAL; 192 return STATE_CRITICAL;
222 break; 193 break;
223 case 'n': 194 case 'n':
224 fprintf (stderr, "%s\n", _("DEPRECATION WARNING: the -n switch (Nagios-compatible output) is now the")); 195 fprintf(stderr, "%s\n", _("DEPRECATION WARNING: the -n switch (Nagios-compatible output) is now the"));
225 fprintf (stderr, "%s\n", _("default and will be removed from future releases.")); 196 fprintf(stderr, "%s\n", _("default and will be removed from future releases."));
226 break; 197 break;
227 case 'v': /* verbose */ 198 case 'v': /* verbose */
228 verbose = true; 199 verbose = true;
229 break; 200 break;
230 case 'h': 201 case 'h':
231 print_help (); 202 print_help();
232 return STATE_UNKNOWN; 203 return STATE_UNKNOWN;
233 case 'V': 204 case 'V':
234 print_revision (progname, NP_VERSION); 205 print_revision(progname, NP_VERSION);
235 return STATE_UNKNOWN; 206 return STATE_UNKNOWN;
236 default: 207 default:
237 usage5 (); 208 usage5();
238 } 209 }
239 } 210 }
240 211
@@ -243,36 +214,34 @@ main (int argc, char *argv[])
243 } 214 }
244 215
245 if (!device) { 216 if (!device) {
246 print_help (); 217 print_help();
247 return STATE_UNKNOWN; 218 return STATE_UNKNOWN;
248 } 219 }
249 220
250 fd = open (device, OPEN_MODE); 221 fd = open(device, OPEN_MODE);
251 222
252 if (fd < 0) { 223 if (fd < 0) {
253 printf (_("CRITICAL - Couldn't open device %s: %s\n"), device, strerror (errno)); 224 printf(_("CRITICAL - Couldn't open device %s: %s\n"), device, strerror(errno));
254 return STATE_CRITICAL; 225 return STATE_CRITICAL;
255 } 226 }
256 227
257 if (smart_cmd_simple (fd, SMART_CMD_ENABLE, 0, false)) { 228 if (smart_cmd_simple(fd, SMART_CMD_ENABLE, 0, false)) {
258 printf (_("CRITICAL - SMART_CMD_ENABLE\n")); 229 printf(_("CRITICAL - SMART_CMD_ENABLE\n"));
259 return STATE_CRITICAL; 230 return STATE_CRITICAL;
260 } 231 }
261 232
262 smart_read_values (fd, &values); 233 smart_read_values(fd, &values);
263 smart_read_thresholds (fd, &thresholds); 234 smart_read_thresholds(fd, &thresholds);
264 retval = nagios (&values, &thresholds); 235 retval = nagios(&values, &thresholds);
265 if (verbose) print_values (&values, &thresholds); 236 if (verbose) {
237 print_values(&values, &thresholds);
238 }
266 239
267 close (fd); 240 close(fd);
268 return retval; 241 return retval;
269} 242}
270 243
271 244char *get_offline_text(int status) {
272
273char *
274get_offline_text (int status)
275{
276 int i; 245 int i;
277 for (i = 0; offline_status_text[i].text; i++) { 246 for (i = 0; offline_status_text[i].text; i++) {
278 if (offline_status_text[i].value == status) { 247 if (offline_status_text[i].value == status) {
@@ -282,24 +251,20 @@ get_offline_text (int status)
282 return "UNKNOWN"; 251 return "UNKNOWN";
283} 252}
284 253
285 254int smart_read_values(int fd, values_t *values) {
286
287int
288smart_read_values (int fd, values_t * values)
289{
290#ifdef __linux__ 255#ifdef __linux__
291 int e; 256 int e;
292 __u8 args[4 + 512]; 257 uint8_t args[4 + 512];
293 args[0] = WIN_SMART; 258 args[0] = WIN_SMART;
294 args[1] = 0; 259 args[1] = 0;
295 args[2] = SMART_READ_VALUES; 260 args[2] = SMART_READ_VALUES;
296 args[3] = 1; 261 args[3] = 1;
297 if (ioctl (fd, HDIO_DRIVE_CMD, &args)) { 262 if (ioctl(fd, HDIO_DRIVE_CMD, &args)) {
298 e = errno; 263 e = errno;
299 printf (_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror (errno)); 264 printf(_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror(errno));
300 return e; 265 return e;
301 } 266 }
302 memcpy (values, args + 4, 512); 267 memcpy(values, args + 4, 512);
303#endif /* __linux__ */ 268#endif /* __linux__ */
304#ifdef __NetBSD__ 269#ifdef __NetBSD__
305 struct atareq req; 270 struct atareq req;
@@ -317,13 +282,14 @@ smart_read_values (int fd, values_t * values)
317 req.cylinder = WDSMART_CYL; 282 req.cylinder = WDSMART_CYL;
318 283
319 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) { 284 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
320 if (req.retsts != ATACMD_OK) 285 if (req.retsts != ATACMD_OK) {
321 errno = ENODEV; 286 errno = ENODEV;
287 }
322 } 288 }
323 289
324 if (errno != 0) { 290 if (errno != 0) {
325 int e = errno; 291 int e = errno;
326 printf (_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror (errno)); 292 printf(_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror(errno));
327 return e; 293 return e;
328 } 294 }
329 295
@@ -332,13 +298,9 @@ smart_read_values (int fd, values_t * values)
332 return 0; 298 return 0;
333} 299}
334 300
335 301int nagios(values_t *p, thresholds_t *t) {
336 302 value_t *value = p->values;
337int 303 threshold_t *threshold = t->thresholds;
338nagios (values_t * p, thresholds_t * t)
339{
340 value_t * value = p->values;
341 threshold_t * threshold = t->thresholds;
342 int status = OPERATIONAL; 304 int status = OPERATIONAL;
343 int prefailure = 0; 305 int prefailure = 0;
344 int advisory = 0; 306 int advisory = 0;
@@ -353,13 +315,11 @@ nagios (values_t * p, thresholds_t * t)
353 if (value->status & 1) { 315 if (value->status & 1) {
354 status = PREFAILURE; 316 status = PREFAILURE;
355 ++prefailure; 317 ++prefailure;
356 } 318 } else {
357 else {
358 status = ADVISORY; 319 status = ADVISORY;
359 ++advisory; 320 ++advisory;
360 } 321 }
361 } 322 } else {
362 else {
363 ++passed; 323 ++passed;
364 } 324 }
365 ++total; 325 ++total;
@@ -369,96 +329,66 @@ nagios (values_t * p, thresholds_t * t)
369 } 329 }
370 switch (status) { 330 switch (status) {
371 case PREFAILURE: 331 case PREFAILURE:
372 printf (_("CRITICAL - %d Harddrive PreFailure%cDetected! %d/%d tests failed.\n"), 332 printf(_("CRITICAL - %d Harddrive PreFailure%cDetected! %d/%d tests failed.\n"), prefailure, prefailure > 1 ? 's' : ' ', failed,
373 prefailure, 333 total);
374 prefailure > 1 ? 's' : ' ', 334 status = STATE_CRITICAL;
375 failed,
376 total);
377 status=STATE_CRITICAL;
378 break; 335 break;
379 case ADVISORY: 336 case ADVISORY:
380 printf (_("WARNING - %d Harddrive Advisor%s Detected. %d/%d tests failed.\n"), 337 printf(_("WARNING - %d Harddrive Advisor%s Detected. %d/%d tests failed.\n"), advisory, advisory > 1 ? "ies" : "y", failed, total);
381 advisory, 338 status = STATE_WARNING;
382 advisory > 1 ? "ies" : "y",
383 failed,
384 total);
385 status=STATE_WARNING;
386 break; 339 break;
387 case OPERATIONAL: 340 case OPERATIONAL:
388 printf (_("OK - Operational (%d/%d tests passed)\n"), passed, total); 341 printf(_("OK - Operational (%d/%d tests passed)\n"), passed, total);
389 status=STATE_OK; 342 status = STATE_OK;
390 break; 343 break;
391 default: 344 default:
392 printf (_("ERROR - Status '%d' unknown. %d/%d tests passed\n"), status, 345 printf(_("ERROR - Status '%d' unknown. %d/%d tests passed\n"), status, passed, total);
393 passed, total);
394 status = STATE_UNKNOWN; 346 status = STATE_UNKNOWN;
395 break; 347 break;
396 } 348 }
397 return status; 349 return status;
398} 350}
399 351
400 352void print_value(value_t *p, threshold_t *t) {
401 353 printf("Id=%3d, Status=%2d {%s , %s}, Value=%3d, Threshold=%3d, %s\n", p->id, p->status, p->status & 1 ? "PreFailure" : "Advisory ",
402void 354 p->status & 2 ? "OnLine " : "OffLine", p->value, t->threshold, p->value >= t->threshold ? "Passed" : "Failed");
403print_value (value_t * p, threshold_t * t)
404{
405 printf ("Id=%3d, Status=%2d {%s , %s}, Value=%3d, Threshold=%3d, %s\n",
406 p->id, p->status, p->status & 1 ? "PreFailure" : "Advisory ",
407 p->status & 2 ? "OnLine " : "OffLine", p->value, t->threshold,
408 p->value >= t->threshold ? "Passed" : "Failed");
409} 355}
410 356
411 357void print_values(values_t *p, thresholds_t *t) {
412 358 value_t *value = p->values;
413void 359 threshold_t *threshold = t->thresholds;
414print_values (values_t * p, thresholds_t * t)
415{
416 value_t * value = p->values;
417 threshold_t * threshold = t->thresholds;
418 int i; 360 int i;
419 for (i = 0; i < NR_ATTRIBUTES; i++) { 361 for (i = 0; i < NR_ATTRIBUTES; i++) {
420 if (value->id && threshold->id && value->id == threshold->id) { 362 if (value->id && threshold->id && value->id == threshold->id) {
421 print_value (value++, threshold++); 363 print_value(value++, threshold++);
422 } 364 }
423 } 365 }
424 printf 366 printf(_("OffLineStatus=%d {%s}, AutoOffLine=%s, OffLineTimeout=%d minutes\n"), p->offline_status,
425 (_("OffLineStatus=%d {%s}, AutoOffLine=%s, OffLineTimeout=%d minutes\n"), 367 get_offline_text(p->offline_status & 0x7f), (p->offline_status & 0x80 ? "Yes" : "No"), p->offline_timeout / 60);
426 p->offline_status, 368 printf(_("OffLineCapability=%d {%s %s %s}\n"), p->offline_capability, p->offline_capability & 1 ? "Immediate" : "",
427 get_offline_text (p->offline_status & 0x7f), 369 p->offline_capability & 2 ? "Auto" : "", p->offline_capability & 4 ? "AbortOnCmd" : "SuspendOnCmd");
428 (p->offline_status & 0x80 ? "Yes" : "No"), 370 printf(_("SmartRevision=%d, CheckSum=%d, SmartCapability=%d {%s %s}\n"), p->revision, p->checksum, p->smart_capability,
429 p->offline_timeout / 60); 371 p->smart_capability & 1 ? "SaveOnStandBy" : "", p->smart_capability & 2 ? "AutoSave" : "");
430 printf
431 (_("OffLineCapability=%d {%s %s %s}\n"),
432 p->offline_capability,
433 p->offline_capability & 1 ? "Immediate" : "",
434 p->offline_capability & 2 ? "Auto" : "",
435 p->offline_capability & 4 ? "AbortOnCmd" : "SuspendOnCmd");
436 printf
437 (_("SmartRevision=%d, CheckSum=%d, SmartCapability=%d {%s %s}\n"),
438 p->revision,
439 p->checksum,
440 p->smart_capability,
441 p->smart_capability & 1 ? "SaveOnStandBy" : "",
442 p->smart_capability & 2 ? "AutoSave" : "");
443} 372}
444 373
445 374int smart_cmd_simple(int fd, enum SmartCommand command, uint8_t val0, bool show_error) {
446int smart_cmd_simple (int fd, enum SmartCommand command, __u8 val0, bool show_error) {
447 int e = STATE_UNKNOWN; 375 int e = STATE_UNKNOWN;
448#ifdef __linux__ 376#ifdef __linux__
449 __u8 args[4]; 377 uint8_t args[4];
450 args[0] = WIN_SMART; 378 args[0] = WIN_SMART;
451 args[1] = val0; 379 args[1] = val0;
452 args[2] = smart_command[command].value; 380 args[2] = smart_command[command].value;
453 args[3] = 0; 381 args[3] = 0;
454 if (ioctl (fd, HDIO_DRIVE_CMD, &args)) { 382 if (ioctl(fd, HDIO_DRIVE_CMD, &args)) {
455 e = STATE_CRITICAL; 383 e = STATE_CRITICAL;
456 if (show_error) 384 if (show_error) {
457 printf (_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror (errno)); 385 printf(_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror(errno));
386 }
458 } else { 387 } else {
459 e = STATE_OK; 388 e = STATE_OK;
460 if (show_error) 389 if (show_error) {
461 printf (_("OK - Command sent (%s)\n"), smart_command[command].text); 390 printf(_("OK - Command sent (%s)\n"), smart_command[command].text);
391 }
462 } 392 }
463 393
464#endif /* __linux__ */ 394#endif /* __linux__ */
@@ -474,44 +404,44 @@ int smart_cmd_simple (int fd, enum SmartCommand command, __u8 val0, bool show_er
474 req.sec_count = val0; 404 req.sec_count = val0;
475 405
476 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) { 406 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
477 if (req.retsts != ATACMD_OK) 407 if (req.retsts != ATACMD_OK) {
478 errno = ENODEV; 408 errno = ENODEV;
479 if (req.cylinder != WDSMART_CYL) 409 }
410 if (req.cylinder != WDSMART_CYL) {
480 errno = ENODEV; 411 errno = ENODEV;
412 }
481 } 413 }
482 414
483 if (errno != 0) { 415 if (errno != 0) {
484 e = STATE_CRITICAL; 416 e = STATE_CRITICAL;
485 if (show_error) 417 if (show_error) {
486 printf (_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror (errno)); 418 printf(_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror(errno));
419 }
487 } else { 420 } else {
488 e = STATE_OK; 421 e = STATE_OK;
489 if (show_error) 422 if (show_error) {
490 printf (_("OK - Command sent (%s)\n"), smart_command[command].text); 423 printf(_("OK - Command sent (%s)\n"), smart_command[command].text);
424 }
491 } 425 }
492 426
493#endif /* __NetBSD__ */ 427#endif /* __NetBSD__ */
494 return e; 428 return e;
495} 429}
496 430
497 431int smart_read_thresholds(int fd, thresholds_t *thresholds) {
498
499int
500smart_read_thresholds (int fd, thresholds_t * thresholds)
501{
502#ifdef __linux__ 432#ifdef __linux__
503 int e; 433 int e;
504 __u8 args[4 + 512]; 434 uint8_t args[4 + 512];
505 args[0] = WIN_SMART; 435 args[0] = WIN_SMART;
506 args[1] = 0; 436 args[1] = 0;
507 args[2] = SMART_READ_THRESHOLDS; 437 args[2] = SMART_READ_THRESHOLDS;
508 args[3] = 1; 438 args[3] = 1;
509 if (ioctl (fd, HDIO_DRIVE_CMD, &args)) { 439 if (ioctl(fd, HDIO_DRIVE_CMD, &args)) {
510 e = errno; 440 e = errno;
511 printf (_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror (errno)); 441 printf(_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror(errno));
512 return e; 442 return e;
513 } 443 }
514 memcpy (thresholds, args + 4, 512); 444 memcpy(thresholds, args + 4, 512);
515#endif /* __linux__ */ 445#endif /* __linux__ */
516#ifdef __NetBSD__ 446#ifdef __NetBSD__
517 struct atareq req; 447 struct atareq req;
@@ -529,13 +459,14 @@ smart_read_thresholds (int fd, thresholds_t * thresholds)
529 req.cylinder = WDSMART_CYL; 459 req.cylinder = WDSMART_CYL;
530 460
531 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) { 461 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
532 if (req.retsts != ATACMD_OK) 462 if (req.retsts != ATACMD_OK) {
533 errno = ENODEV; 463 errno = ENODEV;
464 }
534 } 465 }
535 466
536 if (errno != 0) { 467 if (errno != 0) {
537 int e = errno; 468 int e = errno;
538 printf (_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror (errno)); 469 printf(_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror(errno));
539 return e; 470 return e;
540 } 471 }
541 472
@@ -544,45 +475,43 @@ smart_read_thresholds (int fd, thresholds_t * thresholds)
544 return 0; 475 return 0;
545} 476}
546 477
478void print_help(void) {
479 print_revision(progname, NP_VERSION);
547 480
548void 481 printf("(C) 1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>\n");
549print_help (void) 482 printf("Plugin implementation - 1999 Robert Dale <rdale@digital-mission.com>\n");
550{ 483 printf(COPYRIGHT, copyright, email);
551 print_revision (progname, NP_VERSION);
552
553 printf ("(C) 1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>\n");
554 printf ("Plugin implementation - 1999 Robert Dale <rdale@digital-mission.com>\n");
555 printf (COPYRIGHT, copyright, email);
556 484
557 printf (_("This plugin checks a local hard drive with the (Linux specific) SMART interface [http://smartlinux.sourceforge.net/smart/index.php].")); 485 printf(_("This plugin checks a local hard drive with the (Linux specific) SMART interface "
486 "[http://smartlinux.sourceforge.net/smart/index.php]."));
558 487
559 printf ("\n\n"); 488 printf("\n\n");
560 489
561 print_usage (); 490 print_usage();
562 491
563 printf (UT_HELP_VRSN); 492 printf(UT_HELP_VRSN);
564 printf (UT_EXTRA_OPTS); 493 printf(UT_EXTRA_OPTS);
565 494
566 printf (" %s\n", "-d, --device=DEVICE"); 495 printf(" %s\n", "-d, --device=DEVICE");
567 printf (" %s\n", _("Select device DEVICE")); 496 printf(" %s\n", _("Select device DEVICE"));
568 printf (" %s\n", _("Note: if the device is specified without this option, any further option will")); 497 printf(" %s\n", _("Note: if the device is specified without this option, any further option will"));
569 printf (" %s\n", _("be ignored.")); 498 printf(" %s\n", _("be ignored."));
570 499
571 printf (UT_VERBOSE); 500 printf(UT_VERBOSE);
572 501
573 printf ("\n"); 502 printf("\n");
574 printf ("%s\n", _("Notes:")); 503 printf("%s\n", _("Notes:"));
575 printf (" %s\n", _("The SMART command modes (-i/--immediate, -0/--auto-off and -1/--auto-on) were")); 504 printf(" %s\n", _("The SMART command modes (-i/--immediate, -0/--auto-off and -1/--auto-on) were"));
576 printf (" %s\n", _("broken in an underhand manner and have been disabled. You can use smartctl")); 505 printf(" %s\n", _("broken in an underhand manner and have been disabled. You can use smartctl"));
577 printf (" %s\n", _("instead:")); 506 printf(" %s\n", _("instead:"));
578 printf (" %s\n", _("-0/--auto-off: use \"smartctl --offlineauto=off\"")); 507 printf(" %s\n", _("-0/--auto-off: use \"smartctl --offlineauto=off\""));
579 printf (" %s\n", _("-1/--auto-on: use \"smartctl --offlineauto=on\"")); 508 printf(" %s\n", _("-1/--auto-on: use \"smartctl --offlineauto=on\""));
580 printf (" %s\n", _("-i/--immediate: use \"smartctl --test=offline\"")); 509 printf(" %s\n", _("-i/--immediate: use \"smartctl --test=offline\""));
581 510
582 printf (UT_SUPPORT); 511 printf(UT_SUPPORT);
583} 512}
584 513
585 /* todo : add to the long nanual as example 514/* todo : add to the long nanual as example
586 * 515 *
587 * Run with: check_ide-smart --nagios [-d] <DRIVE> 516 * Run with: check_ide-smart --nagios [-d] <DRIVE>
588 * Where DRIVE is an IDE drive, ie. /dev/hda, /dev/hdb, /dev/hdc 517 * Where DRIVE is an IDE drive, ie. /dev/hda, /dev/hdb, /dev/hdc
@@ -593,10 +522,7 @@ print_help (void)
593 * - Returns -1 not too often 522 * - Returns -1 not too often
594 */ 523 */
595 524
596 525void print_usage(void) {
597void 526 printf("%s\n", _("Usage:"));
598print_usage (void) 527 printf("%s [-d <device>] [-v]", progname);
599{
600 printf ("%s\n", _("Usage:"));
601 printf ("%s [-d <device>] [-v]", progname);
602} 528}
diff --git a/plugins/check_ldap.c b/plugins/check_ldap.c
index 868ffc1e..597644bd 100644
--- a/plugins/check_ldap.c
+++ b/plugins/check_ldap.c
@@ -1,242 +1,211 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_ldap plugin 3 * Monitoring check_ldap plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2008 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_ldap plugin 10 * This file contains the check_ldap plugin
11* 11 *
12* 12 *
13* This program is free software: you can redistribute it and/or modify 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 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 15 * the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16 * (at your option) any later version.
17* 17 *
18* This program is distributed in the hope that it will be useful, 18 * This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21 * GNU General Public License for more details.
22* 22 *
23* You should have received a copy of the GNU General Public License 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/>. 24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25 *
26* 26 *
27*****************************************************************************/ 27 *****************************************************************************/
28 28
29/* progname may be check_ldaps */ 29/* progname may be check_ldaps */
30char *progname = "check_ldap"; 30char *progname = "check_ldap";
31const char *copyright = "2000-2008"; 31const char *copyright = "2000-2024";
32const char *email = "devel@monitoring-plugins.org"; 32const char *email = "devel@monitoring-plugins.org";
33 33
34#include "common.h" 34#include "common.h"
35#include "netutils.h" 35#include "netutils.h"
36#include "utils.h" 36#include "utils.h"
37#include "check_ldap.d/config.h"
37 38
39#include "states.h"
38#include <lber.h> 40#include <lber.h>
39#define LDAP_DEPRECATED 1 41#define LDAP_DEPRECATED 1
40#include <ldap.h> 42#include <ldap.h>
41 43
42enum { 44enum {
43 UNDEFINED = 0,
44#ifdef HAVE_LDAP_SET_OPTION
45 DEFAULT_PROTOCOL = 2,
46#endif
47 DEFAULT_PORT = 389 45 DEFAULT_PORT = 389
48}; 46};
49 47
50int process_arguments (int, char **); 48typedef struct {
51int validate_arguments (void); 49 int errorcode;
52void print_help (void); 50 check_ldap_config config;
53void print_usage (void); 51} check_ldap_config_wrapper;
54 52static check_ldap_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
55char ld_defattr[] = "(objectclass=*)"; 53static check_ldap_config_wrapper validate_arguments(check_ldap_config_wrapper /*config_wrapper*/);
56char *ld_attr = ld_defattr;
57char *ld_host = NULL;
58char *ld_base = NULL;
59char *ld_passwd = NULL;
60char *ld_binddn = NULL;
61int ld_port = -1;
62#ifdef HAVE_LDAP_SET_OPTION
63int ld_protocol = DEFAULT_PROTOCOL;
64#endif
65#ifndef LDAP_OPT_SUCCESS
66# define LDAP_OPT_SUCCESS LDAP_SUCCESS
67#endif
68double warn_time = UNDEFINED;
69double crit_time = UNDEFINED;
70thresholds *entries_thresholds = NULL;
71struct timeval tv;
72char* warn_entries = NULL;
73char* crit_entries = NULL;
74bool starttls = false;
75bool ssl_on_connect = false;
76bool verbose = false;
77
78/* for ldap tls */
79
80char *SERVICE = "LDAP";
81
82int
83main (int argc, char *argv[])
84{
85
86 LDAP *ld;
87 LDAPMessage *result;
88
89 /* should be int result = STATE_UNKNOWN; */
90
91 int status = STATE_UNKNOWN;
92 long microsec;
93 double elapsed_time;
94
95 /* for ldap tls */
96 54
97 int tls; 55static void print_help(void);
98 int version=3; 56void print_usage(void);
99 57
100 int status_entries = STATE_OK; 58#ifndef LDAP_OPT_SUCCESS
101 int num_entries = 0; 59# define LDAP_OPT_SUCCESS LDAP_SUCCESS
60#endif
61static int verbose = 0;
102 62
103 setlocale (LC_ALL, ""); 63int main(int argc, char *argv[]) {
104 bindtextdomain (PACKAGE, LOCALEDIR); 64 setlocale(LC_ALL, "");
105 textdomain (PACKAGE); 65 bindtextdomain(PACKAGE, LOCALEDIR);
66 textdomain(PACKAGE);
106 67
107 if (strstr(argv[0],"check_ldaps")) { 68 if (strstr(argv[0], "check_ldaps")) {
108 xasprintf (&progname, "check_ldaps"); 69 xasprintf(&progname, "check_ldaps");
109 } 70 }
110 71
111 /* Parse extra opts if any */ 72 /* Parse extra opts if any */
112 argv=np_extra_opts (&argc, argv, progname); 73 argv = np_extra_opts(&argc, argv, progname);
113 74
114 if (process_arguments (argc, argv) == ERROR) 75 check_ldap_config_wrapper tmp_config = process_arguments(argc, argv);
115 usage4 (_("Could not parse arguments")); 76 if (tmp_config.errorcode == ERROR) {
77 usage4(_("Could not parse arguments"));
78 }
116 79
117 if (strstr(argv[0],"check_ldaps") && ! starttls && ! ssl_on_connect) 80 const check_ldap_config config = tmp_config.config;
118 starttls = true;
119 81
120 /* initialize alarm signal handling */ 82 /* initialize alarm signal handling */
121 signal (SIGALRM, socket_timeout_alarm_handler); 83 signal(SIGALRM, socket_timeout_alarm_handler);
122 84
123 /* set socket timeout */ 85 /* set socket timeout */
124 alarm (socket_timeout); 86 alarm(socket_timeout);
125 87
126 /* get the start time */ 88 /* get the start time */
127 gettimeofday (&tv, NULL); 89 struct timeval start_time;
90 gettimeofday(&start_time, NULL);
128 91
92 LDAP *ldap_connection;
129 /* initialize ldap */ 93 /* initialize ldap */
130#ifdef HAVE_LDAP_INIT 94#ifdef HAVE_LDAP_INIT
131 if (!(ld = ldap_init (ld_host, ld_port))) { 95 if (!(ldap_connection = ldap_init(config.ld_host, config.ld_port))) {
132 printf ("Could not connect to the server at port %i\n", ld_port); 96 printf("Could not connect to the server at port %i\n", config.ld_port);
133 return STATE_CRITICAL; 97 return STATE_CRITICAL;
134 } 98 }
135#else 99#else
136 if (!(ld = ldap_open (ld_host, ld_port))) { 100 if (!(ld = ldap_open(config.ld_host, config.ld_port))) {
137 if (verbose) 101 if (verbose) {
138 ldap_perror(ld, "ldap_open"); 102 ldap_perror(ldap_connection, "ldap_open");
139 printf (_("Could not connect to the server at port %i\n"), ld_port); 103 }
104 printf(_("Could not connect to the server at port %i\n"), config.ld_port);
140 return STATE_CRITICAL; 105 return STATE_CRITICAL;
141 } 106 }
142#endif /* HAVE_LDAP_INIT */ 107#endif /* HAVE_LDAP_INIT */
143 108
144#ifdef HAVE_LDAP_SET_OPTION 109#ifdef HAVE_LDAP_SET_OPTION
145 /* set ldap options */ 110 /* set ldap options */
146 if (ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &ld_protocol) != 111 if (ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &config.ld_protocol) != LDAP_OPT_SUCCESS) {
147 LDAP_OPT_SUCCESS ) { 112 printf(_("Could not set protocol version %d\n"), config.ld_protocol);
148 printf(_("Could not set protocol version %d\n"), ld_protocol);
149 return STATE_CRITICAL; 113 return STATE_CRITICAL;
150 } 114 }
151#endif 115#endif
152 116
153 if (ld_port == LDAPS_PORT || ssl_on_connect) { 117 int version = 3;
154 xasprintf (&SERVICE, "LDAPS"); 118 int tls;
119 if (config.ld_port == LDAPS_PORT || config.ssl_on_connect) {
155#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS) 120#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)
156 /* ldaps: set option tls */ 121 /* ldaps: set option tls */
157 tls = LDAP_OPT_X_TLS_HARD; 122 tls = LDAP_OPT_X_TLS_HARD;
158 123
159 if (ldap_set_option (ld, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS) 124 if (ldap_set_option(ldap_connection, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS) {
160 { 125 if (verbose) {
161 if (verbose) 126 ldap_perror(ldap_connection, "ldaps_option");
162 ldap_perror(ld, "ldaps_option"); 127 }
163 printf (_("Could not init TLS at port %i!\n"), ld_port); 128 printf(_("Could not init TLS at port %i!\n"), config.ld_port);
164 return STATE_CRITICAL; 129 return STATE_CRITICAL;
165 } 130 }
166#else 131#else
167 printf (_("TLS not supported by the libraries!\n")); 132 printf(_("TLS not supported by the libraries!\n"));
168 return STATE_CRITICAL; 133 return STATE_CRITICAL;
169#endif /* LDAP_OPT_X_TLS */ 134#endif /* LDAP_OPT_X_TLS */
170 } else if (starttls) { 135 } else if (config.starttls) {
171 xasprintf (&SERVICE, "LDAP-TLS");
172#if defined(HAVE_LDAP_SET_OPTION) && defined(HAVE_LDAP_START_TLS_S) 136#if defined(HAVE_LDAP_SET_OPTION) && defined(HAVE_LDAP_START_TLS_S)
173 /* ldap with startTLS: set option version */ 137 /* ldap with startTLS: set option version */
174 if (ldap_get_option(ld,LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS ) 138 if (ldap_get_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS) {
175 { 139 if (version < LDAP_VERSION3) {
176 if (version < LDAP_VERSION3)
177 {
178 version = LDAP_VERSION3; 140 version = LDAP_VERSION3;
179 ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version); 141 ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version);
180 } 142 }
181 } 143 }
182 /* call start_tls */ 144 /* call start_tls */
183 if (ldap_start_tls_s(ld, NULL, NULL) != LDAP_SUCCESS) 145 if (ldap_start_tls_s(ldap_connection, NULL, NULL) != LDAP_SUCCESS) {
184 { 146 if (verbose) {
185 if (verbose) 147 ldap_perror(ldap_connection, "ldap_start_tls");
186 ldap_perror(ld, "ldap_start_tls"); 148 }
187 printf (_("Could not init startTLS at port %i!\n"), ld_port); 149 printf(_("Could not init startTLS at port %i!\n"), config.ld_port);
188 return STATE_CRITICAL; 150 return STATE_CRITICAL;
189 } 151 }
190#else 152#else
191 printf (_("startTLS not supported by the library, needs LDAPv3!\n")); 153 printf(_("startTLS not supported by the library, needs LDAPv3!\n"));
192 return STATE_CRITICAL; 154 return STATE_CRITICAL;
193#endif /* HAVE_LDAP_START_TLS_S */ 155#endif /* HAVE_LDAP_START_TLS_S */
194 } 156 }
195 157
196 /* bind to the ldap server */ 158 /* bind to the ldap server */
197 if (ldap_bind_s (ld, ld_binddn, ld_passwd, LDAP_AUTH_SIMPLE) != 159 if (ldap_bind_s(ldap_connection, config.ld_binddn, config.ld_passwd, LDAP_AUTH_SIMPLE) != LDAP_SUCCESS) {
198 LDAP_SUCCESS) { 160 if (verbose) {
199 if (verbose) 161 ldap_perror(ldap_connection, "ldap_bind");
200 ldap_perror(ld, "ldap_bind"); 162 }
201 printf (_("Could not bind to the LDAP server\n")); 163 printf(_("Could not bind to the LDAP server\n"));
202 return STATE_CRITICAL; 164 return STATE_CRITICAL;
203 } 165 }
204 166
167 LDAPMessage *result;
168 int num_entries = 0;
205 /* do a search of all objectclasses in the base dn */ 169 /* do a search of all objectclasses in the base dn */
206 if (ldap_search_s (ld, ld_base, (crit_entries!=NULL || warn_entries!=NULL) ? LDAP_SCOPE_SUBTREE : LDAP_SCOPE_BASE, ld_attr, NULL, 0, &result) 170 if (ldap_search_s(ldap_connection, config.ld_base,
207 != LDAP_SUCCESS) { 171 (config.crit_entries != NULL || config.warn_entries != NULL) ? LDAP_SCOPE_SUBTREE : LDAP_SCOPE_BASE, config.ld_attr,
208 if (verbose) 172 NULL, 0, &result) != LDAP_SUCCESS) {
209 ldap_perror(ld, "ldap_search"); 173 if (verbose) {
210 printf (_("Could not search/find objectclasses in %s\n"), ld_base); 174 ldap_perror(ldap_connection, "ldap_search");
175 }
176 printf(_("Could not search/find objectclasses in %s\n"), config.ld_base);
211 return STATE_CRITICAL; 177 return STATE_CRITICAL;
212 } else if (crit_entries!=NULL || warn_entries!=NULL) { 178 }
213 num_entries = ldap_count_entries(ld, result); 179
180 if (config.crit_entries != NULL || config.warn_entries != NULL) {
181 num_entries = ldap_count_entries(ldap_connection, result);
214 } 182 }
215 183
216 /* unbind from the ldap server */ 184 /* unbind from the ldap server */
217 ldap_unbind (ld); 185 ldap_unbind(ldap_connection);
218 186
219 /* reset the alarm handler */ 187 /* reset the alarm handler */
220 alarm (0); 188 alarm(0);
221 189
222 /* calculate the elapsed time and compare to thresholds */ 190 /* calculate the elapsed time and compare to thresholds */
223 191
224 microsec = deltime (tv); 192 long microsec = deltime(start_time);
225 elapsed_time = (double)microsec / 1.0e6; 193 double elapsed_time = (double)microsec / 1.0e6;
226 194 mp_state_enum status = STATE_UNKNOWN;
227 if (crit_time!=UNDEFINED && elapsed_time>crit_time) 195 if (config.crit_time_set && elapsed_time > config.crit_time) {
228 status = STATE_CRITICAL; 196 status = STATE_CRITICAL;
229 else if (warn_time!=UNDEFINED && elapsed_time>warn_time) 197 } else if (config.warn_time_set && elapsed_time > config.warn_time) {
230 status = STATE_WARNING; 198 status = STATE_WARNING;
231 else 199 } else {
232 status = STATE_OK; 200 status = STATE_OK;
201 }
233 202
234 if(entries_thresholds != NULL) { 203 if (config.entries_thresholds != NULL) {
235 if (verbose) { 204 if (verbose) {
236 printf ("entries found: %d\n", num_entries); 205 printf("entries found: %d\n", num_entries);
237 print_thresholds("entry thresholds", entries_thresholds); 206 print_thresholds("entry thresholds", config.entries_thresholds);
238 } 207 }
239 status_entries = get_status(num_entries, entries_thresholds); 208 mp_state_enum status_entries = get_status(num_entries, config.entries_thresholds);
240 if (status_entries == STATE_CRITICAL) { 209 if (status_entries == STATE_CRITICAL) {
241 status = STATE_CRITICAL; 210 status = STATE_CRITICAL;
242 } else if (status != STATE_CRITICAL) { 211 } else if (status != STATE_CRITICAL) {
@@ -245,273 +214,272 @@ main (int argc, char *argv[])
245 } 214 }
246 215
247 /* print out the result */ 216 /* print out the result */
248 if (crit_entries!=NULL || warn_entries!=NULL) { 217 if (config.crit_entries != NULL || config.warn_entries != NULL) {
249 printf (_("LDAP %s - found %d entries in %.3f seconds|%s %s\n"), 218 printf(_("LDAP %s - found %d entries in %.3f seconds|%s %s\n"), state_text(status), num_entries, elapsed_time,
250 state_text (status), 219 fperfdata("time", elapsed_time, "s", config.warn_time_set, config.warn_time, config.crit_time_set, config.crit_time, true, 0,
251 num_entries, 220 false, 0),
252 elapsed_time, 221 sperfdata("entries", (double)num_entries, "", config.warn_entries, config.crit_entries, true, 0.0, false, 0.0));
253 fperfdata ("time", elapsed_time, "s",
254 (int)warn_time, warn_time,
255 (int)crit_time, crit_time,
256 true, 0, false, 0),
257 sperfdata ("entries", (double)num_entries, "",
258 warn_entries,
259 crit_entries,
260 true, 0.0, false, 0.0));
261 } else { 222 } else {
262 printf (_("LDAP %s - %.3f seconds response time|%s\n"), 223 printf(_("LDAP %s - %.3f seconds response time|%s\n"), state_text(status), elapsed_time,
263 state_text (status), 224 fperfdata("time", elapsed_time, "s", config.warn_time_set, config.warn_time, config.crit_time_set, config.crit_time, true, 0,
264 elapsed_time, 225 false, 0));
265 fperfdata ("time", elapsed_time, "s",
266 (int)warn_time, warn_time,
267 (int)crit_time, crit_time,
268 true, 0, false, 0));
269 } 226 }
270 227
271 return status; 228 exit(status);
272} 229}
273 230
274/* process command-line arguments */ 231/* process command-line arguments */
275int 232check_ldap_config_wrapper process_arguments(int argc, char **argv) {
276process_arguments (int argc, char **argv)
277{
278 int c;
279
280 int option = 0;
281 /* initialize the long option struct */ 233 /* initialize the long option struct */
282 static struct option longopts[] = { 234 static struct option longopts[] = {{"help", no_argument, 0, 'h'},
283 {"help", no_argument, 0, 'h'}, 235 {"version", no_argument, 0, 'V'},
284 {"version", no_argument, 0, 'V'}, 236 {"timeout", required_argument, 0, 't'},
285 {"timeout", required_argument, 0, 't'}, 237 {"hostname", required_argument, 0, 'H'},
286 {"hostname", required_argument, 0, 'H'}, 238 {"base", required_argument, 0, 'b'},
287 {"base", required_argument, 0, 'b'}, 239 {"attr", required_argument, 0, 'a'},
288 {"attr", required_argument, 0, 'a'}, 240 {"bind", required_argument, 0, 'D'},
289 {"bind", required_argument, 0, 'D'}, 241 {"pass", required_argument, 0, 'P'},
290 {"pass", required_argument, 0, 'P'},
291#ifdef HAVE_LDAP_SET_OPTION 242#ifdef HAVE_LDAP_SET_OPTION
292 {"ver2", no_argument, 0, '2'}, 243 {"ver2", no_argument, 0, '2'},
293 {"ver3", no_argument, 0, '3'}, 244 {"ver3", no_argument, 0, '3'},
294#endif 245#endif
295 {"starttls", no_argument, 0, 'T'}, 246 {"starttls", no_argument, 0, 'T'},
296 {"ssl", no_argument, 0, 'S'}, 247 {"ssl", no_argument, 0, 'S'},
297 {"use-ipv4", no_argument, 0, '4'}, 248 {"use-ipv4", no_argument, 0, '4'},
298 {"use-ipv6", no_argument, 0, '6'}, 249 {"use-ipv6", no_argument, 0, '6'},
299 {"port", required_argument, 0, 'p'}, 250 {"port", required_argument, 0, 'p'},
300 {"warn", required_argument, 0, 'w'}, 251 {"warn", required_argument, 0, 'w'},
301 {"crit", required_argument, 0, 'c'}, 252 {"crit", required_argument, 0, 'c'},
302 {"warn-entries", required_argument, 0, 'W'}, 253 {"warn-entries", required_argument, 0, 'W'},
303 {"crit-entries", required_argument, 0, 'C'}, 254 {"crit-entries", required_argument, 0, 'C'},
304 {"verbose", no_argument, 0, 'v'}, 255 {"verbose", no_argument, 0, 'v'},
305 {0, 0, 0, 0} 256 {0, 0, 0, 0}};
257
258 check_ldap_config_wrapper result = {
259 .errorcode = OK,
260 .config = check_ldap_config_init(),
306 }; 261 };
307 262
308 if (argc < 2) 263 if (argc < 2) {
309 return ERROR; 264 result.errorcode = ERROR;
265 return result;
266 }
310 267
311 for (c = 1; c < argc; c++) { 268 for (int index = 1; index < argc; index++) {
312 if (strcmp ("-to", argv[c]) == 0) 269 if (strcmp("-to", argv[index]) == 0) {
313 strcpy (argv[c], "-t"); 270 strcpy(argv[index], "-t");
271 }
314 } 272 }
315 273
274 int option = 0;
316 while (true) { 275 while (true) {
317 c = getopt_long (argc, argv, "hvV234TS6t:c:w:H:b:p:a:D:P:C:W:", longopts, &option); 276 int option_index = getopt_long(argc, argv, "hvV234TS6t:c:w:H:b:p:a:D:P:C:W:", longopts, &option);
318 277
319 if (c == -1 || c == EOF) 278 if (option_index == -1 || option_index == EOF) {
320 break; 279 break;
280 }
321 281
322 switch (c) { 282 switch (option_index) {
323 case 'h': /* help */ 283 case 'h': /* help */
324 print_help (); 284 print_help();
325 exit (STATE_UNKNOWN); 285 exit(STATE_UNKNOWN);
326 case 'V': /* version */ 286 case 'V': /* version */
327 print_revision (progname, NP_VERSION); 287 print_revision(progname, NP_VERSION);
328 exit (STATE_UNKNOWN); 288 exit(STATE_UNKNOWN);
329 case 't': /* timeout period */ 289 case 't': /* timeout period */
330 if (!is_intnonneg (optarg)) 290 if (!is_intnonneg(optarg)) {
331 usage2 (_("Timeout interval must be a positive integer"), optarg); 291 usage2(_("Timeout interval must be a positive integer"), optarg);
332 else 292 } else {
333 socket_timeout = atoi (optarg); 293 socket_timeout = atoi(optarg);
294 }
334 break; 295 break;
335 case 'H': 296 case 'H':
336 ld_host = optarg; 297 result.config.ld_host = optarg;
337 break; 298 break;
338 case 'b': 299 case 'b':
339 ld_base = optarg; 300 result.config.ld_base = optarg;
340 break; 301 break;
341 case 'p': 302 case 'p':
342 ld_port = atoi (optarg); 303 result.config.ld_port = atoi(optarg);
343 break; 304 break;
344 case 'a': 305 case 'a':
345 ld_attr = optarg; 306 result.config.ld_attr = optarg;
346 break; 307 break;
347 case 'D': 308 case 'D':
348 ld_binddn = optarg; 309 result.config.ld_binddn = optarg;
349 break; 310 break;
350 case 'P': 311 case 'P':
351 ld_passwd = optarg; 312 result.config.ld_passwd = optarg;
352 break; 313 break;
353 case 'w': 314 case 'w':
354 warn_time = strtod (optarg, NULL); 315 result.config.warn_time_set = true;
316 result.config.warn_time = strtod(optarg, NULL);
355 break; 317 break;
356 case 'c': 318 case 'c':
357 crit_time = strtod (optarg, NULL); 319 result.config.crit_time_set = true;
320 result.config.crit_time = strtod(optarg, NULL);
358 break; 321 break;
359 case 'W': 322 case 'W':
360 warn_entries = optarg; 323 result.config.warn_entries = optarg;
361 break; 324 break;
362 case 'C': 325 case 'C':
363 crit_entries = optarg; 326 result.config.crit_entries = optarg;
364 break; 327 break;
365#ifdef HAVE_LDAP_SET_OPTION 328#ifdef HAVE_LDAP_SET_OPTION
366 case '2': 329 case '2':
367 ld_protocol = 2; 330 result.config.ld_protocol = 2;
368 break; 331 break;
369 case '3': 332 case '3':
370 ld_protocol = 3; 333 result.config.ld_protocol = 3;
371 break; 334 break;
372#endif 335#endif // HAVE_LDAP_SET_OPTION
373 case '4': 336 case '4':
374 address_family = AF_INET; 337 address_family = AF_INET;
375 break; 338 break;
376 case 'v': 339 case 'v':
377 verbose = true; 340 verbose++;
378 break; 341 break;
379 case 'T': 342 case 'T':
380 if (! ssl_on_connect) 343 if (!result.config.ssl_on_connect) {
381 starttls = true; 344 result.config.starttls = true;
382 else 345 } else {
383 usage_va(_("%s cannot be combined with %s"), "-T/--starttls", "-S/--ssl"); 346 usage_va(_("%s cannot be combined with %s"), "-T/--starttls", "-S/--ssl");
347 }
384 break; 348 break;
385 case 'S': 349 case 'S':
386 if (! starttls) { 350 if (!result.config.starttls) {
387 ssl_on_connect = true; 351 result.config.ssl_on_connect = true;
388 if (ld_port == -1) 352 if (result.config.ld_port == -1) {
389 ld_port = LDAPS_PORT; 353 result.config.ld_port = LDAPS_PORT;
390 } else 354 }
355 } else {
391 usage_va(_("%s cannot be combined with %s"), "-S/--ssl", "-T/--starttls"); 356 usage_va(_("%s cannot be combined with %s"), "-S/--ssl", "-T/--starttls");
357 }
392 break; 358 break;
393 case '6': 359 case '6':
394#ifdef USE_IPV6 360#ifdef USE_IPV6
395 address_family = AF_INET6; 361 address_family = AF_INET6;
396#else 362#else
397 usage (_("IPv6 support not available\n")); 363 usage(_("IPv6 support not available\n"));
398#endif 364#endif
399 break; 365 break;
400 default: 366 default:
401 usage5 (); 367 usage5();
402 } 368 }
403 } 369 }
404 370
405 c = optind; 371 int index = optind;
406 if (ld_host == NULL && is_host(argv[c])) 372 if ((result.config.ld_host == NULL) && is_host(argv[index])) {
407 ld_host = strdup (argv[c++]); 373 result.config.ld_host = strdup(argv[index++]);
374 }
408 375
409 if (ld_base == NULL && argv[c]) 376 if ((result.config.ld_base == NULL) && argv[index]) {
410 ld_base = strdup (argv[c++]); 377 result.config.ld_base = strdup(argv[index++]);
378 }
411 379
412 if (ld_port == -1) 380 if (result.config.ld_port == -1) {
413 ld_port = DEFAULT_PORT; 381 result.config.ld_port = DEFAULT_PORT;
382 }
414 383
415 return validate_arguments (); 384 if (strstr(argv[0], "check_ldaps") && !result.config.starttls && !result.config.ssl_on_connect) {
385 result.config.starttls = true;
386 }
387
388 return validate_arguments(result);
416} 389}
417 390
391check_ldap_config_wrapper validate_arguments(check_ldap_config_wrapper config_wrapper) {
392 if (config_wrapper.config.ld_host == NULL || strlen(config_wrapper.config.ld_host) == 0) {
393 usage4(_("Please specify the host name\n"));
394 }
418 395
419int 396 if (config_wrapper.config.ld_base == NULL) {
420validate_arguments () 397 usage4(_("Please specify the LDAP base\n"));
421{ 398 }
422 if (ld_host==NULL || strlen(ld_host)==0)
423 usage4 (_("Please specify the host name\n"));
424 399
425 if (ld_base==NULL) 400 if (config_wrapper.config.crit_entries != NULL || config_wrapper.config.warn_entries != NULL) {
426 usage4 (_("Please specify the LDAP base\n")); 401 set_thresholds(&config_wrapper.config.entries_thresholds, config_wrapper.config.warn_entries, config_wrapper.config.crit_entries);
402 }
427 403
428 if (crit_entries!=NULL || warn_entries!=NULL) { 404 if (config_wrapper.config.ld_passwd == NULL) {
429 set_thresholds(&entries_thresholds, 405 config_wrapper.config.ld_passwd = getenv("LDAP_PASSWORD");
430 warn_entries, crit_entries);
431 } 406 }
432 if (ld_passwd==NULL)
433 ld_passwd = getenv("LDAP_PASSWORD");
434 407
435 return OK; 408 return config_wrapper;
436} 409}
437 410
438 411void print_help(void) {
439void
440print_help (void)
441{
442 char *myport; 412 char *myport;
443 xasprintf (&myport, "%d", DEFAULT_PORT); 413 xasprintf(&myport, "%d", DEFAULT_PORT);
444 414
445 print_revision (progname, NP_VERSION); 415 print_revision(progname, NP_VERSION);
446 416
447 printf ("Copyright (c) 1999 Didi Rieder (adrieder@sbox.tu-graz.ac.at)\n"); 417 printf("Copyright (c) 1999 Didi Rieder (adrieder@sbox.tu-graz.ac.at)\n");
448 printf (COPYRIGHT, copyright, email); 418 printf(COPYRIGHT, copyright, email);
449 419
450 printf ("\n\n"); 420 printf("\n\n");
451 421
452 print_usage (); 422 print_usage();
453 423
454 printf (UT_HELP_VRSN); 424 printf(UT_HELP_VRSN);
455 printf (UT_EXTRA_OPTS); 425 printf(UT_EXTRA_OPTS);
456 426
457 printf (UT_HOST_PORT, 'p', myport); 427 printf(UT_HOST_PORT, 'p', myport);
458 428
459 printf (UT_IPv46); 429 printf(UT_IPv46);
460 430
461 printf (" %s\n", "-a [--attr]"); 431 printf(" %s\n", "-a [--attr]");
462 printf (" %s\n", _("ldap attribute to search (default: \"(objectclass=*)\"")); 432 printf(" %s\n", _("ldap attribute to search (default: \"(objectclass=*)\""));
463 printf (" %s\n", "-b [--base]"); 433 printf(" %s\n", "-b [--base]");
464 printf (" %s\n", _("ldap base (eg. ou=my unit, o=my org, c=at")); 434 printf(" %s\n", _("ldap base (eg. ou=my unit, o=my org, c=at"));
465 printf (" %s\n", "-D [--bind]"); 435 printf(" %s\n", "-D [--bind]");
466 printf (" %s\n", _("ldap bind DN (if required)")); 436 printf(" %s\n", _("ldap bind DN (if required)"));
467 printf (" %s\n", "-P [--pass]"); 437 printf(" %s\n", "-P [--pass]");
468 printf (" %s\n", _("ldap password (if required, or set the password through environment variable 'LDAP_PASSWORD')")); 438 printf(" %s\n", _("ldap password (if required, or set the password through environment variable 'LDAP_PASSWORD')"));
469 printf (" %s\n", "-T [--starttls]"); 439 printf(" %s\n", "-T [--starttls]");
470 printf (" %s\n", _("use starttls mechanism introduced in protocol version 3")); 440 printf(" %s\n", _("use starttls mechanism introduced in protocol version 3"));
471 printf (" %s\n", "-S [--ssl]"); 441 printf(" %s\n", "-S [--ssl]");
472 printf (" %s %i\n", _("use ldaps (ldap v2 ssl method). this also sets the default port to"), LDAPS_PORT); 442 printf(" %s %i\n", _("use ldaps (ldap v2 ssl method). this also sets the default port to"), LDAPS_PORT);
473 443
474#ifdef HAVE_LDAP_SET_OPTION 444#ifdef HAVE_LDAP_SET_OPTION
475 printf (" %s\n", "-2 [--ver2]"); 445 printf(" %s\n", "-2 [--ver2]");
476 printf (" %s\n", _("use ldap protocol version 2")); 446 printf(" %s\n", _("use ldap protocol version 2"));
477 printf (" %s\n", "-3 [--ver3]"); 447 printf(" %s\n", "-3 [--ver3]");
478 printf (" %s\n", _("use ldap protocol version 3")); 448 printf(" %s\n", _("use ldap protocol version 3"));
479 printf (" (%s %d)\n", _("default protocol version:"), DEFAULT_PROTOCOL); 449 printf(" (%s %d)\n", _("default protocol version:"), DEFAULT_PROTOCOL);
480#endif 450#endif
481 451
482 printf (UT_WARN_CRIT); 452 printf(UT_WARN_CRIT);
483 453
484 printf (" %s\n", "-W [--warn-entries]"); 454 printf(" %s\n", "-W [--warn-entries]");
485 printf (" %s\n", _("Number of found entries to result in warning status")); 455 printf(" %s\n", _("Number of found entries to result in warning status"));
486 printf (" %s\n", "-C [--crit-entries]"); 456 printf(" %s\n", "-C [--crit-entries]");
487 printf (" %s\n", _("Number of found entries to result in critical status")); 457 printf(" %s\n", _("Number of found entries to result in critical status"));
488 458
489 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 459 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
490 460
491 printf (UT_VERBOSE); 461 printf(UT_VERBOSE);
492 462
493 printf ("\n"); 463 printf("\n");
494 printf ("%s\n", _("Notes:")); 464 printf("%s\n", _("Notes:"));
495 printf (" %s\n", _("If this plugin is called via 'check_ldaps', method 'STARTTLS' will be")); 465 printf(" %s\n", _("If this plugin is called via 'check_ldaps', method 'STARTTLS' will be"));
496 printf (_(" implied (using default port %i) unless --port=636 is specified. In that case\n"), DEFAULT_PORT); 466 printf(_(" implied (using default port %i) unless --port=636 is specified. In that case\n"), DEFAULT_PORT);
497 printf (" %s\n", _("'SSL on connect' will be used no matter how the plugin was called.")); 467 printf(" %s\n", _("'SSL on connect' will be used no matter how the plugin was called."));
498 printf (" %s\n", _("This detection is deprecated, please use 'check_ldap' with the '--starttls' or '--ssl' flags")); 468 printf(" %s\n", _("This detection is deprecated, please use 'check_ldap' with the '--starttls' or '--ssl' flags"));
499 printf (" %s\n", _("to define the behaviour explicitly instead.")); 469 printf(" %s\n", _("to define the behaviour explicitly instead."));
500 printf (" %s\n", _("The parameters --warn-entries and --crit-entries are optional.")); 470 printf(" %s\n", _("The parameters --warn-entries and --crit-entries are optional."));
501 471
502 printf (UT_SUPPORT); 472 printf(UT_SUPPORT);
503} 473}
504 474
505void 475void print_usage(void) {
506print_usage (void) 476 printf("%s\n", _("Usage:"));
507{ 477 printf(" %s -H <host> -b <base_dn> [-p <port>] [-a <attr>] [-D <binddn>]", progname);
508 printf ("%s\n", _("Usage:")); 478 printf("\n [-P <password>] [-w <warn_time>] [-c <crit_time>] [-t timeout]%s\n",
509 printf (" %s -H <host> -b <base_dn> [-p <port>] [-a <attr>] [-D <binddn>]",progname);
510 printf ("\n [-P <password>] [-w <warn_time>] [-c <crit_time>] [-t timeout]%s\n",
511#ifdef HAVE_LDAP_SET_OPTION 479#ifdef HAVE_LDAP_SET_OPTION
512 "\n [-2|-3] [-4|-6]" 480 "\n [-2|-3] [-4|-6]"
513#else 481#else
514 "" 482 ""
515#endif 483#endif
516 ); 484 );
517} 485}
diff --git a/plugins/check_ldap.d/config.h b/plugins/check_ldap.d/config.h
new file mode 100644
index 00000000..c8a40610
--- /dev/null
+++ b/plugins/check_ldap.d/config.h
@@ -0,0 +1,60 @@
1#pragma once
2
3#include "../../config.h"
4#include "thresholds.h"
5#include <stddef.h>
6
7static char ld_defattr[] = "(objectclass=*)";
8
9enum {
10#ifdef HAVE_LDAP_SET_OPTION
11 DEFAULT_PROTOCOL = 2,
12#endif
13};
14
15typedef struct {
16 char *ld_host;
17 char *ld_base;
18 char *ld_passwd;
19 char *ld_binddn;
20 char *ld_attr;
21 int ld_port;
22 bool starttls;
23 bool ssl_on_connect;
24#ifdef HAVE_LDAP_SET_OPTION
25 int ld_protocol;
26#endif
27
28 char *warn_entries;
29 char *crit_entries;
30 thresholds *entries_thresholds;
31 bool warn_time_set;
32 double warn_time;
33 bool crit_time_set;
34 double crit_time;
35} check_ldap_config;
36
37check_ldap_config check_ldap_config_init() {
38 check_ldap_config tmp = {
39 .ld_host = NULL,
40 .ld_base = NULL,
41 .ld_passwd = NULL,
42 .ld_binddn = NULL,
43 .ld_attr = ld_defattr,
44 .ld_port = -1,
45 .starttls = false,
46 .ssl_on_connect = false,
47#ifdef HAVE_LDAP_SET_OPTION
48 .ld_protocol = DEFAULT_PROTOCOL,
49#endif
50
51 .warn_entries = NULL,
52 .crit_entries = NULL,
53 .entries_thresholds = NULL,
54 .warn_time_set = false,
55 .warn_time = 0,
56 .crit_time_set = false,
57 .crit_time = 0,
58 };
59 return tmp;
60}
diff --git a/plugins/check_load.c b/plugins/check_load.c
index 1431d130..2925bff3 100644
--- a/plugins/check_load.c
+++ b/plugins/check_load.c
@@ -1,350 +1,423 @@
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 } 131 }
136 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); 132
137 if (child_stderr == NULL) { 133 const check_load_config config = tmp_config.config;
138 printf (_("Could not open stderr for %s\n"), PATH_TO_UPTIME); 134
135 double load_values[3] = {0, 0, 0};
136
137 // this should be getloadavg from gnulib, should work everywhereâ„¢
138 int error = getloadavg(load_values, 3);
139 if (error != 3) {
140 die(STATE_UNKNOWN, _("Failed to retrieve load values"));
139 } 141 }
140 fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process); 142
141 if(strstr(input_buffer, "load average:")) { 143 mp_check overall = mp_check_init();
142 sscanf (input_buffer, "%*[^l]load average: %lf, %lf, %lf", &la1, &la5, &la15); 144 if (config.output_format_set) {
143 } 145 mp_set_format(config.output_format);
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 } 146 }
157#endif 147
158 148 bool is_using_scaled_load_values = false;
159 if ((la[0] < 0.0) || (la[1] < 0.0) || (la[2] < 0.0)) { 149 long numcpus;
160#ifdef HAVE_GETLOADAVG 150 if (config.take_into_account_cpus && ((numcpus = GET_NUMBER_OF_CPUS()) > 0)) {
161 printf (_("Error in getloadavg()\n")); 151 is_using_scaled_load_values = true;
162#else 152
163 printf (_("Error processing %s\n"), PATH_TO_UPTIME); 153 double scaled_la[3] = {
164#endif 154 load_values[0] / numcpus,
165 return STATE_UNKNOWN; 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", pd_value_to_string(pd_scaled_load1.value));
172 mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc1);
173
174 mp_perfdata pd_scaled_load5 = perfdata_init();
175 pd_scaled_load5.label = "scaled_load5";
176 pd_scaled_load5 = mp_set_pd_value(pd_scaled_load5, scaled_la[1]);
177 pd_scaled_load5 = mp_pd_set_thresholds(pd_scaled_load5, config.th_load[1]);
178
179 mp_subcheck scaled_load_sc5 = mp_subcheck_init();
180 scaled_load_sc5 = mp_set_subcheck_state(scaled_load_sc5, mp_get_pd_status(pd_scaled_load5));
181 mp_add_perfdata_to_subcheck(&scaled_load_sc5, pd_scaled_load5);
182 xasprintf(&scaled_load_sc5.output, "5 Minutes: %s", pd_value_to_string(pd_scaled_load5.value));
183 mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc5);
184
185 mp_perfdata pd_scaled_load15 = perfdata_init();
186 pd_scaled_load15.label = "scaled_load15";
187 pd_scaled_load15 = mp_set_pd_value(pd_scaled_load15, scaled_la[2]);
188 pd_scaled_load15 = mp_pd_set_thresholds(pd_scaled_load15, config.th_load[2]);
189
190 mp_subcheck scaled_load_sc15 = mp_subcheck_init();
191 scaled_load_sc15 = mp_set_subcheck_state(scaled_load_sc15, mp_get_pd_status(pd_scaled_load15));
192 mp_add_perfdata_to_subcheck(&scaled_load_sc15, pd_scaled_load15);
193 xasprintf(&scaled_load_sc15.output, "15 Minutes: %s", pd_value_to_string(pd_scaled_load15.value));
194 mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc15);
195
196 mp_add_subcheck_to_check(&overall, scaled_load_sc);
166 } 197 }
167 198
168 /* we got this far, so assume OK until we've measured */ 199 mp_subcheck load_sc = mp_subcheck_init();
169 result = STATE_OK; 200 load_sc = mp_set_subcheck_default_state(load_sc, STATE_OK);
201 load_sc.output = "Total Load";
170 202
171 xasprintf(&status_line, _("load average: %.2f, %.2f, %.2f"), la1, la5, la15); 203 mp_perfdata pd_load1 = perfdata_init();
172 xasprintf(&status_line, ("total %s"), status_line); 204 pd_load1.label = "load1";
205 pd_load1 = mp_set_pd_value(pd_load1, load_values[0]);
206 if (!is_using_scaled_load_values) {
207 pd_load1 = mp_pd_set_thresholds(pd_load1, config.th_load[0]);
208 }
173 209
210 mp_subcheck load_sc1 = mp_subcheck_init();
211 load_sc1 = mp_set_subcheck_state(load_sc1, mp_get_pd_status(pd_load1));
212 mp_add_perfdata_to_subcheck(&load_sc1, pd_load1);
213 xasprintf(&load_sc1.output, "1 Minute: %s", pd_value_to_string(pd_load1.value));
214 mp_add_subcheck_to_subcheck(&load_sc, load_sc1);
215
216 mp_perfdata pd_load5 = perfdata_init();
217 pd_load5.label = "load5";
218 pd_load5 = mp_set_pd_value(pd_load5, load_values[1]);
219 if (!is_using_scaled_load_values) {
220 pd_load5 = mp_pd_set_thresholds(pd_load5, config.th_load[1]);
221 }
174 222
175 double scaled_la[3] = { 0.0, 0.0, 0.0 }; 223 mp_subcheck load_sc5 = mp_subcheck_init();
176 bool is_using_scaled_load_values = false; 224 load_sc5 = mp_set_subcheck_state(load_sc5, mp_get_pd_status(pd_load5));
225 mp_add_perfdata_to_subcheck(&load_sc5, pd_load5);
226 xasprintf(&load_sc5.output, "5 Minutes: %s", pd_value_to_string(pd_load5.value));
227 mp_add_subcheck_to_subcheck(&load_sc, load_sc5);
228
229 mp_perfdata pd_load15 = perfdata_init();
230 pd_load15.label = "load15";
231 pd_load15 = mp_set_pd_value(pd_load15, load_values[2]);
232 if (!is_using_scaled_load_values) {
233 pd_load15 = mp_pd_set_thresholds(pd_load15, config.th_load[2]);
234 }
177 235
178 if (take_into_account_cpus == true && (numcpus = GET_NUMBER_OF_CPUS()) > 0) { 236 mp_subcheck load_sc15 = mp_subcheck_init();
179 is_using_scaled_load_values = true; 237 load_sc15 = mp_set_subcheck_state(load_sc15, mp_get_pd_status(pd_load15));
238 mp_add_perfdata_to_subcheck(&load_sc15, pd_load15);
239 xasprintf(&load_sc15.output, "15 Minutes: %s", pd_value_to_string(pd_load15.value));
240 mp_add_subcheck_to_subcheck(&load_sc, load_sc15);
180 241
181 scaled_la[0] = la[0] / numcpus; 242 mp_add_subcheck_to_check(&overall, load_sc);
182 scaled_la[1] = la[1] / numcpus;
183 scaled_la[2] = la[2] / numcpus;
184 243
185 char *tmp = NULL; 244 if (config.n_procs_to_show > 0) {
186 xasprintf(&tmp, _("load average: %.2f, %.2f, %.2f"), scaled_la[0], scaled_la[1], scaled_la[2]); 245 mp_subcheck top_proc_sc = mp_subcheck_init();
187 xasprintf(&status_line, "scaled %s - %s", tmp, status_line); 246 top_proc_sc = mp_set_subcheck_state(top_proc_sc, STATE_OK);
188 } 247 top_processes_result top_proc = print_top_consuming_processes(config.n_procs_to_show);
248 xasprintf(&top_proc_sc.output, "Top %lu CPU time consuming processes", config.n_procs_to_show);
189 249
190 for(i = 0; i < 3; i++) { 250 if (top_proc.errorcode == OK) {
191 if (is_using_scaled_load_values) { 251 for (unsigned long i = 0; i < config.n_procs_to_show; i++) {
192 if(scaled_la[i] > cload[i]) { 252 xasprintf(&top_proc_sc.output, "%s\n%s", top_proc_sc.output, top_proc.top_processes[i]);
193 result = STATE_CRITICAL;
194 break;
195 }
196 else if(scaled_la[i] > wload[i]) result = STATE_WARNING;
197 } else {
198 if(la[i] > cload[i]) {
199 result = STATE_CRITICAL;
200 break;
201 } 253 }
202 else if(la[i] > wload[i]) result = STATE_WARNING;
203 } 254 }
204 }
205 255
206 printf("LOAD %s - %s|", state_text(result), status_line); 256 mp_add_subcheck_to_check(&overall, top_proc_sc);
207 for(i = 0; i < 3; i++) {
208 if (is_using_scaled_load_values) {
209 printf("load%d=%.3f;;;0; ", nums[i], la[i]);
210 printf("scaled_load%d=%.3f;%.3f;%.3f;0; ", nums[i], scaled_la[i], wload[i], cload[i]);
211 } else {
212 printf("load%d=%.3f;%.3f;%.3f;0; ", nums[i], la[i], wload[i], cload[i]);
213 }
214 } 257 }
215 258
216 putchar('\n'); 259 mp_exit(overall);
217 if (n_procs_to_show > 0) {
218 print_top_consuming_processes();
219 }
220 return result;
221} 260}
222 261
223
224/* process command-line arguments */ 262/* process command-line arguments */
225static int 263static check_load_config_wrapper process_arguments(int argc, char **argv) {
226process_arguments (int argc, char **argv) 264
227{ 265 enum {
228 int c = 0; 266 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 }; 267 };
240 268
241 if (argc < 2) 269 static struct option longopts[] = {{"warning", required_argument, 0, 'w'},
242 return ERROR; 270 {"critical", required_argument, 0, 'c'},
271 {"percpu", no_argument, 0, 'r'},
272 {"version", no_argument, 0, 'V'},
273 {"help", no_argument, 0, 'h'},
274 {"procs-to-show", required_argument, 0, 'n'},
275 {"output-format", required_argument, 0, output_format_index},
276 {0, 0, 0, 0}};
277
278 check_load_config_wrapper result = {
279 .errorcode = OK,
280 .config = check_load_config_init(),
281 };
243 282
244 while (1) { 283 if (argc < 2) {
245 c = getopt_long (argc, argv, "Vhrc:w:n:", longopts, &option); 284 result.errorcode = ERROR;
285 return result;
286 }
246 287
247 if (c == -1 || c == EOF) 288 while (true) {
248 break; 289 int option = 0;
290 int option_index = getopt_long(argc, argv, "Vhrc:w:n:", longopts, &option);
249 291
250 switch (c) { 292 if (option_index == -1 || option_index == EOF) {
251 case 'w': /* warning time threshold */
252 get_threshold(optarg, wload);
253 break; 293 break;
254 case 'c': /* critical time threshold */ 294 }
255 get_threshold(optarg, cload); 295
296 switch (option_index) {
297 case output_format_index: {
298 parsed_output_format parser = mp_parse_output_format(optarg);
299 if (!parser.parsing_success) {
300 printf("Invalid output format: %s\n", optarg);
301 exit(STATE_UNKNOWN);
302 }
303
304 result.config.output_format_set = true;
305 result.config.output_format = parser.output_format;
256 break; 306 break;
307 }
308 case 'w': /* warning time threshold */ {
309 parsed_thresholds warning_range = get_threshold(optarg);
310 result.config.th_load[0].warning = warning_range.load[0];
311 result.config.th_load[0].warning_is_set = true;
312
313 result.config.th_load[1].warning = warning_range.load[1];
314 result.config.th_load[1].warning_is_set = true;
315
316 result.config.th_load[2].warning = warning_range.load[2];
317 result.config.th_load[2].warning_is_set = true;
318 } break;
319 case 'c': /* critical time threshold */ {
320 parsed_thresholds critical_range = get_threshold(optarg);
321 result.config.th_load[0].critical = critical_range.load[0];
322 result.config.th_load[0].critical_is_set = true;
323
324 result.config.th_load[1].critical = critical_range.load[1];
325 result.config.th_load[1].critical_is_set = true;
326
327 result.config.th_load[2].critical = critical_range.load[2];
328 result.config.th_load[2].critical_is_set = true;
329 } break;
257 case 'r': /* Divide load average by number of CPUs */ 330 case 'r': /* Divide load average by number of CPUs */
258 take_into_account_cpus = true; 331 result.config.take_into_account_cpus = true;
259 break; 332 break;
260 case 'V': /* version */ 333 case 'V': /* version */
261 print_revision (progname, NP_VERSION); 334 print_revision(progname, NP_VERSION);
262 exit (STATE_UNKNOWN); 335 exit(STATE_UNKNOWN);
263 case 'h': /* help */ 336 case 'h': /* help */
264 print_help (); 337 print_help();
265 exit (STATE_UNKNOWN); 338 exit(STATE_UNKNOWN);
266 case 'n': 339 case 'n':
267 n_procs_to_show = atoi(optarg); 340 result.config.n_procs_to_show = (unsigned long)atol(optarg);
268 break; 341 break;
269 case '?': /* help */ 342 case '?': /* help */
270 usage5 (); 343 usage5();
271 } 344 }
272 } 345 }
273 346
274 c = optind; 347 int index = optind;
275 if (c == argc) 348 if (index == argc) {
276 return validate_arguments (); 349 return result;
350 }
277 351
278 /* handle the case if both arguments are missing, 352 /* handle the case if both arguments are missing,
279 * but not if only one is given without -c or -w flag */ 353 * but not if only one is given without -c or -w flag */
280 if(c - argc == 2) { 354 if (index - argc == 2) {
281 get_threshold(argv[c++], wload); 355 parsed_thresholds warning_range = get_threshold(argv[index++]);
282 get_threshold(argv[c++], cload); 356 result.config.th_load[0].warning = warning_range.load[0];
283 } 357 result.config.th_load[0].warning_is_set = true;
284 else if(c - argc == 1) { 358
285 get_threshold(argv[c++], cload); 359 result.config.th_load[1].warning = warning_range.load[1];
360 result.config.th_load[1].warning_is_set = true;
361
362 result.config.th_load[2].warning = warning_range.load[2];
363 result.config.th_load[2].warning_is_set = true;
364 parsed_thresholds critical_range = get_threshold(argv[index++]);
365 result.config.th_load[0].critical = critical_range.load[0];
366 result.config.th_load[0].critical_is_set = true;
367
368 result.config.th_load[1].critical = critical_range.load[1];
369 result.config.th_load[1].critical_is_set = true;
370
371 result.config.th_load[2].critical = critical_range.load[2];
372 result.config.th_load[2].critical_is_set = true;
373 } else if (index - argc == 1) {
374 parsed_thresholds critical_range = get_threshold(argv[index++]);
375 result.config.th_load[0].critical = critical_range.load[0];
376 result.config.th_load[0].critical_is_set = true;
377
378 result.config.th_load[1].critical = critical_range.load[1];
379 result.config.th_load[1].critical_is_set = true;
380
381 result.config.th_load[2].critical = critical_range.load[2];
382 result.config.th_load[2].critical_is_set = true;
286 } 383 }
287 384
288 return validate_arguments (); 385 return result;
289}
290
291
292static int
293validate_arguments (void)
294{
295 int i = 0;
296
297 /* match cload first, as it will give the most friendly error message
298 * if user hasn't given the -c switch properly */
299 for(i = 0; i < 3; i++) {
300 if(cload[i] < 0)
301 die (STATE_UNKNOWN, _("Critical threshold for %d-minute load average is not specified\n"), nums[i]);
302 if(wload[i] < 0)
303 die (STATE_UNKNOWN, _("Warning threshold for %d-minute load average is not specified\n"), nums[i]);
304 if(wload[i] > cload[i])
305 die (STATE_UNKNOWN, _("Parameter inconsistency: %d-minute \"warning load\" is greater than \"critical load\"\n"), nums[i]);
306 }
307
308 return OK;
309} 386}
310 387
388void print_help(void) {
389 print_revision(progname, NP_VERSION);
311 390
312void 391 printf("Copyright (c) 1999 Felipe Gustavo de Almeida <galmeida@linux.ime.usp.br>\n");
313print_help (void) 392 printf(COPYRIGHT, copyright, email);
314{
315 print_revision (progname, NP_VERSION);
316
317 printf ("Copyright (c) 1999 Felipe Gustavo de Almeida <galmeida@linux.ime.usp.br>\n");
318 printf (COPYRIGHT, copyright, email);
319 393
320 printf (_("This plugin tests the current system load average.")); 394 printf(_("This plugin tests the current system load average."));
321 395
322 printf ("\n\n"); 396 printf("\n\n");
323 397
324 print_usage (); 398 print_usage();
325 399
326 printf (UT_HELP_VRSN); 400 printf(UT_HELP_VRSN);
327 printf (UT_EXTRA_OPTS); 401 printf(UT_EXTRA_OPTS);
328 402
329 printf (" %s\n", "-w, --warning=WLOAD1,WLOAD5,WLOAD15"); 403 printf(" %s\n", "-w, --warning=WLOAD1,WLOAD5,WLOAD15");
330 printf (" %s\n", _("Exit with WARNING status if load average exceeds WLOADn")); 404 printf(" %s\n", _("Exit with WARNING status if load average exceeds WLOADn"));
331 printf (" %s\n", "-c, --critical=CLOAD1,CLOAD5,CLOAD15"); 405 printf(" %s\n", "-c, --critical=CLOAD1,CLOAD5,CLOAD15");
332 printf (" %s\n", _("Exit with CRITICAL status if load average exceed CLOADn")); 406 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\"")); 407 printf(" %s\n", _("the load average format is the same used by \"uptime\" and \"w\""));
334 printf (" %s\n", "-r, --percpu"); 408 printf(" %s\n", "-r, --percpu");
335 printf (" %s\n", _("Divide the load averages by the number of CPUs (when possible)")); 409 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"); 410 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.")); 411 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")); 412 printf(" %s\n", _("NUMBER_OF_PROCS=0 disables this feature. Default value is 0"));
339 413
340 printf (UT_SUPPORT); 414 printf(UT_OUTPUT_FORMAT);
415 printf(UT_SUPPORT);
341} 416}
342 417
343void 418void print_usage(void) {
344print_usage (void) 419 printf("%s\n", _("Usage:"));
345{ 420 printf("%s [-r] -w WLOAD1,WLOAD5,WLOAD15 -c CLOAD1,CLOAD5,CLOAD15 [-n NUMBER_OF_PROCS]\n", progname);
346 printf ("%s\n", _("Usage:"));
347 printf ("%s [-r] -w WLOAD1,WLOAD5,WLOAD15 -c CLOAD1,CLOAD5,CLOAD15 [-n NUMBER_OF_PROCS]\n", progname);
348} 421}
349 422
350#ifdef PS_USES_PROCPCPU 423#ifdef PS_USES_PROCPCPU
@@ -356,36 +429,51 @@ int cmpstringp(const void *p1, const void *p2) {
356 int procrss = 0; 429 int procrss = 0;
357 float procpcpu = 0; 430 float procpcpu = 0;
358 char procstat[8]; 431 char procstat[8];
359#ifdef PS_USES_PROCETIME 432# ifdef PS_USES_PROCETIME
360 char procetime[MAX_INPUT_BUFFER]; 433 char procetime[MAX_INPUT_BUFFER];
361#endif /* PS_USES_PROCETIME */ 434# endif /* PS_USES_PROCETIME */
362 char procprog[MAX_INPUT_BUFFER]; 435 char procprog[MAX_INPUT_BUFFER];
363 int pos; 436 int pos;
364 sscanf (* (char * const *) p1, PS_FORMAT, PS_VARLIST); 437 sscanf(*(char *const *)p1, PS_FORMAT, PS_VARLIST);
365 float procpcpu1 = procpcpu; 438 float procpcpu1 = procpcpu;
366 sscanf (* (char * const *) p2, PS_FORMAT, PS_VARLIST); 439 sscanf(*(char *const *)p2, PS_FORMAT, PS_VARLIST);
367 return procpcpu1 < procpcpu; 440 return procpcpu1 < procpcpu;
368} 441}
369#endif /* PS_USES_PROCPCPU */ 442#endif /* PS_USES_PROCPCPU */
370 443
371static int print_top_consuming_processes() { 444static top_processes_result print_top_consuming_processes(unsigned long n_procs_to_show) {
372 int i = 0; 445 top_processes_result result = {
373 struct output chld_out, chld_err; 446 .errorcode = OK,
374 if(np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0) != 0){ 447 };
448 struct output chld_out;
449 struct output chld_err;
450 if (np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0) != 0) {
375 fprintf(stderr, _("'%s' exited with non-zero status.\n"), PS_COMMAND); 451 fprintf(stderr, _("'%s' exited with non-zero status.\n"), PS_COMMAND);
376 return STATE_UNKNOWN; 452 result.errorcode = ERROR;
453 return result;
377 } 454 }
455
378 if (chld_out.lines < 2) { 456 if (chld_out.lines < 2) {
379 fprintf(stderr, _("some error occurred getting procs list.\n")); 457 fprintf(stderr, _("some error occurred getting procs list.\n"));
380 return STATE_UNKNOWN; 458 result.errorcode = ERROR;
459 return result;
381 } 460 }
461
382#ifdef PS_USES_PROCPCPU 462#ifdef PS_USES_PROCPCPU
383 qsort(chld_out.line + 1, chld_out.lines - 1, sizeof(char*), cmpstringp); 463 qsort(chld_out.line + 1, chld_out.lines - 1, sizeof(char *), cmpstringp);
384#endif /* PS_USES_PROCPCPU */ 464#endif /* PS_USES_PROCPCPU */
385 int lines_to_show = chld_out.lines < (size_t)(n_procs_to_show + 1) 465 unsigned long lines_to_show = chld_out.lines < (size_t)(n_procs_to_show + 1) ? chld_out.lines : n_procs_to_show + 1;
386 ? (int)chld_out.lines : n_procs_to_show + 1; 466
387 for (i = 0; i < lines_to_show; i += 1) { 467 result.top_processes = calloc(lines_to_show, sizeof(char *));
388 printf("%s\n", chld_out.line[i]); 468 if (result.top_processes == NULL) {
469 // Failed allocation
470 result.errorcode = ERROR;
471 return result;
389 } 472 }
390 return OK; 473
474 for (unsigned long i = 0; i < lines_to_show; i += 1) {
475 xasprintf(&result.top_processes[i], "%s", chld_out.line[i]);
476 }
477
478 return result;
391} 479}
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 826b77e9..5bd276dc 100644
--- a/plugins/check_mrtg.c
+++ b/plugins/check_mrtg.c
@@ -1,385 +1,368 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_mrtg plugin 3 * Monitoring check_mrtg plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2007 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_mrtg plugin 10 * This file contains the check_mrtg plugin
11* 11 *
12* This plugin will check either the average or maximum value of one of the 12 * This plugin will check either the average or maximum value of one of the
13* two variables recorded in an MRTG log file. 13 * two variables recorded in an MRTG log file.
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 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 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 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 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/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_mrtg"; 32const char *progname = "check_mrtg";
33const char *copyright = "1999-2007"; 33const char *copyright = "1999-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "common.h" 36#include "common.h"
37#include "utils.h" 37#include "utils.h"
38#include "check_mrtg.d/config.h"
38 39
39int process_arguments (int, char **); 40typedef struct {
40int validate_arguments (void); 41 int errorcode;
41void print_help (void); 42 check_mrtg_config config;
42void print_usage (void); 43} check_mrtg_config_wrapper;
43 44static check_mrtg_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
44char *log_file = NULL; 45static check_mrtg_config_wrapper validate_arguments(check_mrtg_config_wrapper /*config_wrapper*/);
45int expire_minutes = 0; 46
46bool use_average = true; 47static void print_help(void);
47int variable_number = -1; 48void print_usage(void);
48unsigned long value_warning_threshold = 0L;
49unsigned long value_critical_threshold = 0L;
50char *label;
51char *units;
52
53int
54main (int argc, char **argv)
55{
56 int result = STATE_OK;
57 FILE *fp;
58 int line;
59 char input_buffer[MAX_INPUT_BUFFER];
60 char *temp_buffer;
61 time_t current_time;
62 time_t timestamp = 0L;
63 unsigned long average_value_rate = 0L;
64 unsigned long maximum_value_rate = 0L;
65 unsigned long rate = 0L;
66 49
67 setlocale (LC_ALL, ""); 50int main(int argc, char **argv) {
68 bindtextdomain (PACKAGE, LOCALEDIR); 51 setlocale(LC_ALL, "");
69 textdomain (PACKAGE); 52 bindtextdomain(PACKAGE, LOCALEDIR);
53 textdomain(PACKAGE);
70 54
71 /* Parse extra opts if any */ 55 /* Parse extra opts if any */
72 argv=np_extra_opts (&argc, argv, progname); 56 argv = np_extra_opts(&argc, argv, progname);
73 57
74 if (process_arguments (argc, argv) == ERROR) 58 check_mrtg_config_wrapper tmp_config = process_arguments(argc, argv);
75 usage4 (_("Could not parse arguments\n")); 59 if (tmp_config.errorcode == ERROR) {
60 usage4(_("Could not parse arguments\n"));
61 }
62
63 const check_mrtg_config config = tmp_config.config;
76 64
77 /* open the MRTG log file for reading */ 65 /* open the MRTG log file for reading */
78 fp = fopen (log_file, "r"); 66 FILE *mtrg_log_file = fopen(config.log_file, "r");
79 if (fp == NULL) { 67 if (mtrg_log_file == NULL) {
80 printf (_("Unable to open MRTG log file\n")); 68 printf(_("Unable to open MRTG log file\n"));
81 return STATE_UNKNOWN; 69 return STATE_UNKNOWN;
82 } 70 }
83 71
84 line = 0; 72 time_t timestamp = 0;
85 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) { 73 unsigned long average_value_rate = 0;
86 74 unsigned long maximum_value_rate = 0;
75 char input_buffer[MAX_INPUT_BUFFER];
76 int line = 0;
77 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, mtrg_log_file)) {
87 line++; 78 line++;
88 79
89 /* skip the first line of the log file */ 80 /* skip the first line of the log file */
90 if (line == 1) 81 if (line == 1) {
91 continue; 82 continue;
83 }
92 84
93 /* break out of read loop if we've passed the number of entries we want to read */ 85 /* break out of read loop if we've passed the number of entries we want to read */
94 if (line > 2) 86 if (line > 2) {
95 break; 87 break;
88 }
96 89
97 /* grab the timestamp */ 90 /* grab the timestamp */
98 temp_buffer = strtok (input_buffer, " "); 91 char *temp_buffer = strtok(input_buffer, " ");
99 timestamp = strtoul (temp_buffer, NULL, 10); 92 timestamp = strtoul(temp_buffer, NULL, 10);
100 93
101 /* grab the average value 1 rate */ 94 /* grab the average value 1 rate */
102 temp_buffer = strtok (NULL, " "); 95 temp_buffer = strtok(NULL, " ");
103 if (variable_number == 1) 96 if (config.variable_number == 1) {
104 average_value_rate = strtoul (temp_buffer, NULL, 10); 97 average_value_rate = strtoul(temp_buffer, NULL, 10);
98 }
105 99
106 /* grab the average value 2 rate */ 100 /* grab the average value 2 rate */
107 temp_buffer = strtok (NULL, " "); 101 temp_buffer = strtok(NULL, " ");
108 if (variable_number == 2) 102 if (config.variable_number == 2) {
109 average_value_rate = strtoul (temp_buffer, NULL, 10); 103 average_value_rate = strtoul(temp_buffer, NULL, 10);
104 }
110 105
111 /* grab the maximum value 1 rate */ 106 /* grab the maximum value 1 rate */
112 temp_buffer = strtok (NULL, " "); 107 temp_buffer = strtok(NULL, " ");
113 if (variable_number == 1) 108 if (config.variable_number == 1) {
114 maximum_value_rate = strtoul (temp_buffer, NULL, 10); 109 maximum_value_rate = strtoul(temp_buffer, NULL, 10);
110 }
115 111
116 /* grab the maximum value 2 rate */ 112 /* grab the maximum value 2 rate */
117 temp_buffer = strtok (NULL, " "); 113 temp_buffer = strtok(NULL, " ");
118 if (variable_number == 2) 114 if (config.variable_number == 2) {
119 maximum_value_rate = strtoul (temp_buffer, NULL, 10); 115 maximum_value_rate = strtoul(temp_buffer, NULL, 10);
116 }
120 } 117 }
121 118
122 /* close the log file */ 119 /* close the log file */
123 fclose (fp); 120 fclose(mtrg_log_file);
124 121
125 /* if we couldn't read enough data, return an unknown error */ 122 /* if we couldn't read enough data, return an unknown error */
126 if (line <= 2) { 123 if (line <= 2) {
127 printf (_("Unable to process MRTG log file\n")); 124 printf(_("Unable to process MRTG log file\n"));
128 return STATE_UNKNOWN; 125 return STATE_UNKNOWN;
129 } 126 }
130 127
131 /* make sure the MRTG data isn't too old */ 128 /* make sure the MRTG data isn't too old */
132 time (&current_time); 129 time_t current_time;
133 if (expire_minutes > 0 130 time(&current_time);
134 && (current_time - timestamp) > (expire_minutes * 60)) { 131 if (config.expire_minutes > 0 && (current_time - timestamp) > (config.expire_minutes * 60)) {
135 printf (_("MRTG data has expired (%d minutes old)\n"), 132 printf(_("MRTG data has expired (%d minutes old)\n"), (int)((current_time - timestamp) / 60));
136 (int) ((current_time - timestamp) / 60));
137 return STATE_WARNING; 133 return STATE_WARNING;
138 } 134 }
139 135
136 unsigned long rate = 0L;
140 /* else check the incoming/outgoing rates */ 137 /* else check the incoming/outgoing rates */
141 if (use_average) 138 if (config.use_average) {
142 rate = average_value_rate; 139 rate = average_value_rate;
143 else 140 } else {
144 rate = maximum_value_rate; 141 rate = maximum_value_rate;
142 }
145 143
146 if (rate > value_critical_threshold) 144 int result = STATE_OK;
145 if (config.value_critical_threshold_set && rate > config.value_critical_threshold) {
147 result = STATE_CRITICAL; 146 result = STATE_CRITICAL;
148 else if (rate > value_warning_threshold) 147 } else if (config.value_warning_threshold_set && rate > config.value_warning_threshold) {
149 result = STATE_WARNING; 148 result = STATE_WARNING;
149 }
150 150
151 printf("%s. %s = %lu %s|%s\n", 151 printf("%s. %s = %lu %s|%s\n", (config.use_average) ? _("Avg") : _("Max"), config.label, rate, config.units,
152 (use_average) ? _("Avg") : _("Max"), 152 perfdata(config.label, (long)rate, config.units, config.value_warning_threshold_set, (long)config.value_warning_threshold,
153 label, rate, units, 153 config.value_critical_threshold_set, (long)config.value_critical_threshold, 0, 0, 0, 0));
154 perfdata(label, (long) rate, units,
155 (int) value_warning_threshold, (long) value_warning_threshold,
156 (int) value_critical_threshold, (long) value_critical_threshold,
157 0, 0, 0, 0));
158 154
159 return result; 155 return result;
160} 156}
161 157
162
163
164/* process command-line arguments */ 158/* process command-line arguments */
165int 159check_mrtg_config_wrapper process_arguments(int argc, char **argv) {
166process_arguments (int argc, char **argv)
167{
168 int c;
169
170 int option = 0;
171 static struct option longopts[] = { 160 static struct option longopts[] = {
172 {"logfile", required_argument, 0, 'F'}, 161 {"logfile", required_argument, 0, 'F'}, {"expires", required_argument, 0, 'e'}, {"aggregation", required_argument, 0, 'a'},
173 {"expires", required_argument, 0, 'e'}, 162 {"variable", required_argument, 0, 'v'}, {"critical", required_argument, 0, 'c'}, {"warning", required_argument, 0, 'w'},
174 {"aggregation", required_argument, 0, 'a'}, 163 {"label", required_argument, 0, 'l'}, {"units", required_argument, 0, 'u'}, {"variable", required_argument, 0, 'v'},
175 {"variable", required_argument, 0, 'v'}, 164 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
176 {"critical", required_argument, 0, 'c'}, 165
177 {"warning", required_argument, 0, 'w'}, 166 check_mrtg_config_wrapper result = {
178 {"label", required_argument, 0, 'l'}, 167 .errorcode = OK,
179 {"units", required_argument, 0, 'u'}, 168 .config = check_mrtg_config_init(),
180 {"variable", required_argument, 0, 'v'},
181 {"version", no_argument, 0, 'V'},
182 {"help", no_argument, 0, 'h'},
183 {0, 0, 0, 0}
184 }; 169 };
185 170
186 if (argc < 2) 171 if (argc < 2) {
187 return ERROR; 172 result.errorcode = ERROR;
173 return result;
174 }
188 175
189 for (c = 1; c < argc; c++) { 176 for (int i = 1; i < argc; i++) {
190 if (strcmp ("-to", argv[c]) == 0) 177 if (strcmp("-to", argv[i]) == 0) {
191 strcpy (argv[c], "-t"); 178 strcpy(argv[i], "-t");
192 else if (strcmp ("-wt", argv[c]) == 0) 179 } else if (strcmp("-wt", argv[i]) == 0) {
193 strcpy (argv[c], "-w"); 180 strcpy(argv[i], "-w");
194 else if (strcmp ("-ct", argv[c]) == 0) 181 } else if (strcmp("-ct", argv[i]) == 0) {
195 strcpy (argv[c], "-c"); 182 strcpy(argv[i], "-c");
183 }
196 } 184 }
197 185
186 int option_char;
187 int option = 0;
198 while (1) { 188 while (1) {
199 c = getopt_long (argc, argv, "hVF:e:a:v:c:w:l:u:", longopts, 189 option_char = getopt_long(argc, argv, "hVF:e:a:v:c:w:l:u:", longopts, &option);
200 &option);
201 190
202 if (c == -1 || c == EOF) 191 if (option_char == -1 || option_char == EOF) {
203 break; 192 break;
193 }
204 194
205 switch (c) { 195 switch (option_char) {
206 case 'F': /* input file */ 196 case 'F': /* input file */
207 log_file = optarg; 197 result.config.log_file = optarg;
208 break; 198 break;
209 case 'e': /* ups name */ 199 case 'e': /* ups name */
210 expire_minutes = atoi (optarg); 200 result.config.expire_minutes = atoi(optarg);
211 break; 201 break;
212 case 'a': /* port */ 202 case 'a': /* port */
213 if (!strcmp (optarg, "MAX")) 203 result.config.use_average = (bool)(strcmp(optarg, "MAX"));
214 use_average = false;
215 else
216 use_average = true;
217 break; 204 break;
218 case 'v': 205 case 'v':
219 variable_number = atoi (optarg); 206 result.config.variable_number = atoi(optarg);
220 if (variable_number < 1 || variable_number > 2) 207 if (result.config.variable_number < 1 || result.config.variable_number > 2) {
221 usage4 (_("Invalid variable number")); 208 usage4(_("Invalid variable number"));
209 }
222 break; 210 break;
223 case 'w': /* critical time threshold */ 211 case 'w': /* critical time threshold */
224 value_warning_threshold = strtoul (optarg, NULL, 10); 212 result.config.value_warning_threshold_set = true;
213 result.config.value_warning_threshold = strtoul(optarg, NULL, 10);
225 break; 214 break;
226 case 'c': /* warning time threshold */ 215 case 'c': /* warning time threshold */
227 value_critical_threshold = strtoul (optarg, NULL, 10); 216 result.config.value_critical_threshold_set = true;
217 result.config.value_critical_threshold = strtoul(optarg, NULL, 10);
228 break; 218 break;
229 case 'l': /* label */ 219 case 'l': /* label */
230 label = optarg; 220 result.config.label = optarg;
231 break; 221 break;
232 case 'u': /* timeout */ 222 case 'u': /* timeout */
233 units = optarg; 223 result.config.units = optarg;
234 break; 224 break;
235 case 'V': /* version */ 225 case 'V': /* version */
236 print_revision (progname, NP_VERSION); 226 print_revision(progname, NP_VERSION);
237 exit (STATE_UNKNOWN); 227 exit(STATE_UNKNOWN);
238 case 'h': /* help */ 228 case 'h': /* help */
239 print_help (); 229 print_help();
240 exit (STATE_UNKNOWN); 230 exit(STATE_UNKNOWN);
241 case '?': /* help */ 231 case '?': /* help */
242 usage5 (); 232 usage5();
243 } 233 }
244 } 234 }
245 235
246 c = optind; 236 option_char = optind;
247 if (log_file == NULL && argc > c) { 237 if (result.config.log_file == NULL && argc > option_char) {
248 log_file = argv[c++]; 238 result.config.log_file = argv[option_char++];
249 } 239 }
250 240
251 if (expire_minutes <= 0 && argc > c) { 241 if (result.config.expire_minutes <= 0 && argc > option_char) {
252 if (is_intpos (argv[c])) 242 if (is_intpos(argv[option_char])) {
253 expire_minutes = atoi (argv[c++]); 243 result.config.expire_minutes = atoi(argv[option_char++]);
254 else 244 } else {
255 die (STATE_UNKNOWN, 245 die(STATE_UNKNOWN, _("%s is not a valid expiration time\nUse '%s -h' for additional help\n"), argv[option_char], progname);
256 _("%s is not a valid expiration time\nUse '%s -h' for additional help\n"), 246 }
257 argv[c], progname);
258 } 247 }
259 248
260 if (argc > c && strcmp (argv[c], "MAX") == 0) { 249 if (argc > option_char && strcmp(argv[option_char], "MAX") == 0) {
261 use_average = false; 250 result.config.use_average = false;
262 c++; 251 option_char++;
263 } 252 } else if (argc > option_char && strcmp(argv[option_char], "AVG") == 0) {
264 else if (argc > c && strcmp (argv[c], "AVG") == 0) { 253 result.config.use_average = true;
265 use_average = true; 254 option_char++;
266 c++;
267 } 255 }
268 256
269 if (argc > c && variable_number == -1) { 257 if (argc > option_char && result.config.variable_number == -1) {
270 variable_number = atoi (argv[c++]); 258 result.config.variable_number = atoi(argv[option_char++]);
271 if (variable_number < 1 || variable_number > 2) { 259 if (result.config.variable_number < 1 || result.config.variable_number > 2) {
272 printf ("%s :", argv[c]); 260 printf("%s :", argv[option_char]);
273 usage (_("Invalid variable number\n")); 261 usage(_("Invalid variable number\n"));
274 } 262 }
275 } 263 }
276 264
277 if (argc > c && value_warning_threshold == 0) { 265 if (argc > option_char && !result.config.value_warning_threshold_set) {
278 value_warning_threshold = strtoul (argv[c++], NULL, 10); 266 result.config.value_warning_threshold_set = true;
267 result.config.value_warning_threshold = strtoul(argv[option_char++], NULL, 10);
279 } 268 }
280 269
281 if (argc > c && value_critical_threshold == 0) { 270 if (argc > option_char && !result.config.value_critical_threshold_set) {
282 value_critical_threshold = strtoul (argv[c++], NULL, 10); 271 result.config.value_critical_threshold_set = true;
272 result.config.value_critical_threshold = strtoul(argv[option_char++], NULL, 10);
283 } 273 }
284 274
285 if (argc > c && strlen (label) == 0) { 275 if (argc > option_char && strlen(result.config.label) == 0) {
286 label = argv[c++]; 276 result.config.label = argv[option_char++];
287 } 277 }
288 278
289 if (argc > c && strlen (units) == 0) { 279 if (argc > option_char && strlen(result.config.units) == 0) {
290 units = argv[c++]; 280 result.config.units = argv[option_char++];
291 } 281 }
292 282
293 return validate_arguments (); 283 return validate_arguments(result);
294} 284}
295 285
296int 286check_mrtg_config_wrapper validate_arguments(check_mrtg_config_wrapper config_wrapper) {
297validate_arguments (void) 287 if (config_wrapper.config.variable_number == -1) {
298{ 288 usage4(_("You must supply the variable number"));
299 if (variable_number == -1) 289 }
300 usage4 (_("You must supply the variable number"));
301 290
302 if (label == NULL) 291 if (config_wrapper.config.label == NULL) {
303 label = strdup ("value"); 292 config_wrapper.config.label = strdup("value");
293 }
304 294
305 if (units == NULL) 295 if (config_wrapper.config.units == NULL) {
306 units = strdup (""); 296 config_wrapper.config.units = strdup("");
297 }
307 298
308 return OK; 299 return config_wrapper;
309} 300}
310 301
311 302void print_help(void) {
312 303 print_revision(progname, NP_VERSION);
313void 304
314print_help (void) 305 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
315{ 306 printf(COPYRIGHT, copyright, email);
316 print_revision (progname, NP_VERSION); 307
317 308 printf("%s\n", _("This plugin will check either the average or maximum value of one of the"));
318 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 309 printf("%s\n", _("two variables recorded in an MRTG log file."));
319 printf (COPYRIGHT, copyright, email); 310
320 311 printf("\n\n");
321 printf ("%s\n", _("This plugin will check either the average or maximum value of one of the")); 312
322 printf ("%s\n", _("two variables recorded in an MRTG log file.")); 313 print_usage();
323 314
324 printf ("\n\n"); 315 printf(UT_HELP_VRSN);
325 316 printf(UT_EXTRA_OPTS);
326 print_usage (); 317
327 318 printf(" %s\n", "-F, --logfile=FILE");
328 printf (UT_HELP_VRSN); 319 printf(" %s\n", _("The MRTG log file containing the data you want to monitor"));
329 printf (UT_EXTRA_OPTS); 320 printf(" %s\n", "-e, --expires=MINUTES");
330 321 printf(" %s\n", _("Minutes before MRTG data is considered to be too old"));
331 printf (" %s\n", "-F, --logfile=FILE"); 322 printf(" %s\n", "-a, --aggregation=AVG|MAX");
332 printf (" %s\n", _("The MRTG log file containing the data you want to monitor")); 323 printf(" %s\n", _("Should we check average or maximum values?"));
333 printf (" %s\n", "-e, --expires=MINUTES"); 324 printf(" %s\n", "-v, --variable=INTEGER");
334 printf (" %s\n", _("Minutes before MRTG data is considered to be too old")); 325 printf(" %s\n", _("Which variable set should we inspect? (1 or 2)"));
335 printf (" %s\n", "-a, --aggregation=AVG|MAX"); 326 printf(" %s\n", "-w, --warning=INTEGER");
336 printf (" %s\n", _("Should we check average or maximum values?")); 327 printf(" %s\n", _("Threshold value for data to result in WARNING status"));
337 printf (" %s\n", "-v, --variable=INTEGER"); 328 printf(" %s\n", "-c, --critical=INTEGER");
338 printf (" %s\n", _("Which variable set should we inspect? (1 or 2)")); 329 printf(" %s\n", _("Threshold value for data to result in CRITICAL status"));
339 printf (" %s\n", "-w, --warning=INTEGER"); 330 printf(" %s\n", "-l, --label=STRING");
340 printf (" %s\n", _("Threshold value for data to result in WARNING status")); 331 printf(" %s\n", _("Type label for data (Examples: Conns, \"Processor Load\", In, Out)"));
341 printf (" %s\n", "-c, --critical=INTEGER"); 332 printf(" %s\n", "-u, --units=STRING");
342 printf (" %s\n", _("Threshold value for data to result in CRITICAL status")); 333 printf(" %s\n", _("Option units label for data (Example: Packets/Sec, Errors/Sec,"));
343 printf (" %s\n", "-l, --label=STRING"); 334 printf(" %s\n", _("\"Bytes Per Second\", \"%% Utilization\")"));
344 printf (" %s\n", _("Type label for data (Examples: Conns, \"Processor Load\", In, Out)")); 335
345 printf (" %s\n", "-u, --units=STRING"); 336 printf("\n");
346 printf (" %s\n", _("Option units label for data (Example: Packets/Sec, Errors/Sec,")); 337 printf(" %s\n", _("If the value exceeds the <vwl> threshold, a WARNING status is returned. If"));
347 printf (" %s\n", _("\"Bytes Per Second\", \"%% Utilization\")")); 338 printf(" %s\n", _("the value exceeds the <vcl> threshold, a CRITICAL status is returned. If"));
348 339 printf(" %s\n", _("the data in the log file is older than <expire_minutes> old, a WARNING"));
349 printf ("\n"); 340 printf(" %s\n", _("status is returned and a warning message is printed."));
350 printf (" %s\n", _("If the value exceeds the <vwl> threshold, a WARNING status is returned. If")); 341
351 printf (" %s\n", _("the value exceeds the <vcl> threshold, a CRITICAL status is returned. If")); 342 printf("\n");
352 printf (" %s\n", _("the data in the log file is older than <expire_minutes> old, a WARNING")); 343 printf(" %s\n", _("This plugin is useful for monitoring MRTG data that does not correspond to"));
353 printf (" %s\n", _("status is returned and a warning message is printed.")); 344 printf(" %s\n", _("bandwidth usage. (Use the check_mrtgtraf plugin for monitoring bandwidth)."));
354 345 printf(" %s\n", _("It can be used to monitor any kind of data that MRTG is monitoring - errors,"));
355 printf ("\n"); 346 printf(" %s\n", _("packets/sec, etc. I use MRTG in conjunction with the Novell NLM that allows"));
356 printf (" %s\n", _("This plugin is useful for monitoring MRTG data that does not correspond to")); 347 printf(" %s\n", _("me to track processor utilization, user connections, drive space, etc and"));
357 printf (" %s\n", _("bandwidth usage. (Use the check_mrtgtraf plugin for monitoring bandwidth).")); 348 printf(" %s\n\n", _("this plugin works well for monitoring that kind of data as well."));
358 printf (" %s\n", _("It can be used to monitor any kind of data that MRTG is monitoring - errors,")); 349
359 printf (" %s\n", _("packets/sec, etc. I use MRTG in conjunction with the Novell NLM that allows")); 350 printf("%s\n", _("Notes:"));
360 printf (" %s\n", _("me to track processor utilization, user connections, drive space, etc and")); 351 printf(" %s\n", _("- This plugin only monitors one of the two variables stored in the MRTG log"));
361 printf (" %s\n\n", _("this plugin works well for monitoring that kind of data as well.")); 352 printf(" %s\n", _("file. If you want to monitor both values you will have to define two"));
362 353 printf(" %s\n", _("commands with different values for the <variable> argument. Of course,"));
363 printf ("%s\n", _("Notes:")); 354 printf(" %s\n", _("you can always hack the code to make this plugin work for you..."));
364 printf (" %s\n", _("- This plugin only monitors one of the two variables stored in the MRTG log")); 355 printf(" %s\n", _("- MRTG stands for the Multi Router Traffic Grapher. It can be downloaded from"));
365 printf (" %s\n", _("file. If you want to monitor both values you will have to define two")); 356 printf(" %s\n", "http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html");
366 printf (" %s\n", _("commands with different values for the <variable> argument. Of course,")); 357
367 printf (" %s\n", _("you can always hack the code to make this plugin work for you...")); 358 printf(UT_SUPPORT);
368 printf (" %s\n", _("- MRTG stands for the Multi Router Traffic Grapher. It can be downloaded from"));
369 printf (" %s\n", "http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html");
370
371 printf (UT_SUPPORT);
372} 359}
373 360
374
375
376/* original command line: 361/* original command line:
377 <log_file> <expire_minutes> <AVG|MAX> <variable> <vwl> <vcl> <label> [units] */ 362 <log_file> <expire_minutes> <AVG|MAX> <variable> <vwl> <vcl> <label> [units] */
378 363
379void 364void print_usage(void) {
380print_usage (void) 365 printf("%s\n", _("Usage:"));
381{ 366 printf("%s -F log_file -a <AVG | MAX> -v variable -w warning -c critical\n", progname);
382 printf ("%s\n", _("Usage:")); 367 printf("[-l label] [-u units] [-e expire_minutes] [-t timeout] [-v]\n");
383 printf ("%s -F log_file -a <AVG | MAX> -v variable -w warning -c critical\n",progname);
384 printf ("[-l label] [-u units] [-e expire_minutes] [-t timeout] [-v]\n");
385} 368}
diff --git a/plugins/check_mrtg.d/config.h b/plugins/check_mrtg.d/config.h
new file mode 100644
index 00000000..96b849a2
--- /dev/null
+++ b/plugins/check_mrtg.d/config.h
@@ -0,0 +1,36 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5#include <stdlib.h>
6
7typedef struct {
8 bool use_average;
9 int variable_number;
10 int expire_minutes;
11 char *label;
12 char *units;
13 char *log_file;
14
15 bool value_warning_threshold_set;
16 unsigned long value_warning_threshold;
17 bool value_critical_threshold_set;
18 unsigned long value_critical_threshold;
19} check_mrtg_config;
20
21check_mrtg_config check_mrtg_config_init() {
22 check_mrtg_config tmp = {
23 .use_average = true,
24 .variable_number = -1,
25 .expire_minutes = 0,
26 .label = NULL,
27 .units = NULL,
28 .log_file = NULL,
29
30 .value_warning_threshold_set = false,
31 .value_warning_threshold = 0,
32 .value_critical_threshold_set = false,
33 .value_critical_threshold = 0,
34 };
35 return tmp;
36}
diff --git a/plugins/check_mrtgtraf.c b/plugins/check_mrtgtraf.c
index bd25d47d..8c7cf8aa 100644
--- a/plugins/check_mrtgtraf.c
+++ b/plugins/check_mrtgtraf.c
@@ -1,381 +1,352 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_mrtgtraf plugin 3 * Monitoring check_mrtgtraf plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2007 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_mtrgtraf plugin 10 * This file contains the check_mtrgtraf plugin
11* 11 *
12* This plugin will check the incoming/outgoing transfer rates of a router 12 * This plugin will check the incoming/outgoing transfer rates of a router
13* switch, etc recorded in an MRTG log. 13 * switch, etc recorded in an MRTG log.
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 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 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 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 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/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
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 "common.h" 37#include "common.h"
33#include "utils.h" 38#include "utils.h"
34 39
35const char *progname = "check_mrtgtraf"; 40typedef struct {
36const char *copyright = "1999-2007"; 41 int errorcode;
37const char *email = "devel@monitoring-plugins.org"; 42 check_mrtgtraf_config config;
43} check_mrtgtraf_config_wrapper;
38 44
39int process_arguments (int, char **); 45static check_mrtgtraf_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
40int validate_arguments (void); 46static void print_help(void);
41void print_help(void);
42void print_usage(void); 47void print_usage(void);
43 48
44char *log_file = NULL; 49int main(int argc, char **argv) {
45int expire_minutes = -1; 50 setlocale(LC_ALL, "");
46bool use_average = true; 51 bindtextdomain(PACKAGE, LOCALEDIR);
47unsigned long incoming_warning_threshold = 0L; 52 textdomain(PACKAGE);
48unsigned long incoming_critical_threshold = 0L;
49unsigned long outgoing_warning_threshold = 0L;
50unsigned long outgoing_critical_threshold = 0L;
51 53
54 /* Parse extra opts if any */
55 argv = np_extra_opts(&argc, argv, progname);
56
57 check_mrtgtraf_config_wrapper tmp_config = process_arguments(argc, argv);
58 if (tmp_config.errorcode == ERROR) {
59 usage4(_("Could not parse arguments"));
60 }
61
62 const check_mrtgtraf_config config = tmp_config.config;
63
64 /* open the MRTG log file for reading */
65 FILE *mrtg_log_file_ptr = fopen(config.log_file, "r");
66 if (mrtg_log_file_ptr == NULL) {
67 usage4(_("Unable to open MRTG log file"));
68 }
52 69
53int
54main (int argc, char **argv)
55{
56 int result = STATE_OK;
57 FILE *fp;
58 int line;
59 char input_buffer[MAX_INPUT_BUFFER];
60 char *temp_buffer;
61 time_t current_time;
62 char *error_message;
63 time_t timestamp = 0L; 70 time_t timestamp = 0L;
71 char input_buffer[MAX_INPUT_BUFFER];
64 unsigned long average_incoming_rate = 0L; 72 unsigned long average_incoming_rate = 0L;
65 unsigned long average_outgoing_rate = 0L; 73 unsigned long average_outgoing_rate = 0L;
66 unsigned long maximum_incoming_rate = 0L; 74 unsigned long maximum_incoming_rate = 0L;
67 unsigned long maximum_outgoing_rate = 0L; 75 unsigned long maximum_outgoing_rate = 0L;
68 unsigned long incoming_rate = 0L; 76 int line = 0;
69 unsigned long outgoing_rate = 0L; 77 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, mrtg_log_file_ptr)) {
70 double adjusted_incoming_rate = 0.0;
71 double adjusted_outgoing_rate = 0.0;
72 char incoming_speed_rating[8];
73 char outgoing_speed_rating[8];
74
75 setlocale (LC_ALL, "");
76 bindtextdomain (PACKAGE, LOCALEDIR);
77 textdomain (PACKAGE);
78
79 /* Parse extra opts if any */
80 argv=np_extra_opts (&argc, argv, progname);
81
82 if (process_arguments (argc, argv) == ERROR)
83 usage4 (_("Could not parse arguments"));
84
85 /* open the MRTG log file for reading */
86 fp = fopen (log_file, "r");
87 if (fp == NULL)
88 usage4 (_("Unable to open MRTG log file"));
89
90 line = 0;
91 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
92 78
93 line++; 79 line++;
94 80
95 /* skip the first line of the log file */ 81 /* skip the first line of the log file */
96 if (line == 1) 82 if (line == 1) {
97 continue; 83 continue;
84 }
98 85
99 /* break out of read loop */ 86 /* break out of read loop */
100 /* if we've passed the number of entries we want to read */ 87 /* if we've passed the number of entries we want to read */
101 if (line > 2) 88 if (line > 2) {
102 break; 89 break;
90 }
103 91
104 /* grab the timestamp */ 92 /* grab the timestamp */
105 temp_buffer = strtok (input_buffer, " "); 93 char *temp_buffer = strtok(input_buffer, " ");
106 timestamp = strtoul (temp_buffer, NULL, 10); 94 timestamp = strtoul(temp_buffer, NULL, 10);
107 95
108 /* grab the average incoming transfer rate */ 96 /* grab the average incoming transfer rate */
109 temp_buffer = strtok (NULL, " "); 97 temp_buffer = strtok(NULL, " ");
110 average_incoming_rate = strtoul (temp_buffer, NULL, 10); 98 average_incoming_rate = strtoul(temp_buffer, NULL, 10);
111 99
112 /* grab the average outgoing transfer rate */ 100 /* grab the average outgoing transfer rate */
113 temp_buffer = strtok (NULL, " "); 101 temp_buffer = strtok(NULL, " ");
114 average_outgoing_rate = strtoul (temp_buffer, NULL, 10); 102 average_outgoing_rate = strtoul(temp_buffer, NULL, 10);
115 103
116 /* grab the maximum incoming transfer rate */ 104 /* grab the maximum incoming transfer rate */
117 temp_buffer = strtok (NULL, " "); 105 temp_buffer = strtok(NULL, " ");
118 maximum_incoming_rate = strtoul (temp_buffer, NULL, 10); 106 maximum_incoming_rate = strtoul(temp_buffer, NULL, 10);
119 107
120 /* grab the maximum outgoing transfer rate */ 108 /* grab the maximum outgoing transfer rate */
121 temp_buffer = strtok (NULL, " "); 109 temp_buffer = strtok(NULL, " ");
122 maximum_outgoing_rate = strtoul (temp_buffer, NULL, 10); 110 maximum_outgoing_rate = strtoul(temp_buffer, NULL, 10);
123 } 111 }
124 112
125 /* close the log file */ 113 /* close the log file */
126 fclose (fp); 114 fclose(mrtg_log_file_ptr);
127 115
128 /* if we couldn't read enough data, return an unknown error */ 116 /* if we couldn't read enough data, return an unknown error */
129 if (line <= 2) 117 if (line <= 2) {
130 usage4 (_("Unable to process MRTG log file")); 118 usage4(_("Unable to process MRTG log file"));
119 }
131 120
132 /* make sure the MRTG data isn't too old */ 121 /* make sure the MRTG data isn't too old */
133 time (&current_time); 122 time_t current_time;
134 if ((expire_minutes > 0) && 123 time(&current_time);
135 (current_time - timestamp) > (expire_minutes * 60)) 124 if ((config.expire_minutes > 0) && (current_time - timestamp) > (config.expire_minutes * 60)) {
136 die (STATE_WARNING, _("MRTG data has expired (%d minutes old)\n"), 125 die(STATE_WARNING, _("MRTG data has expired (%d minutes old)\n"), (int)((current_time - timestamp) / 60));
137 (int) ((current_time - timestamp) / 60)); 126 }
138 127
128 unsigned long incoming_rate = 0L;
129 unsigned long outgoing_rate = 0L;
139 /* else check the incoming/outgoing rates */ 130 /* else check the incoming/outgoing rates */
140 if (use_average) { 131 if (config.use_average) {
141 incoming_rate = average_incoming_rate; 132 incoming_rate = average_incoming_rate;
142 outgoing_rate = average_outgoing_rate; 133 outgoing_rate = average_outgoing_rate;
143 } 134 } else {
144 else {
145 incoming_rate = maximum_incoming_rate; 135 incoming_rate = maximum_incoming_rate;
146 outgoing_rate = maximum_outgoing_rate; 136 outgoing_rate = maximum_outgoing_rate;
147 } 137 }
148 138
139 double adjusted_incoming_rate = 0.0;
140 char incoming_speed_rating[8];
149 /* report incoming traffic in Bytes/sec */ 141 /* report incoming traffic in Bytes/sec */
150 if (incoming_rate < 1024) { 142 if (incoming_rate < 1024) {
151 strcpy (incoming_speed_rating, "B"); 143 strcpy(incoming_speed_rating, "B");
152 adjusted_incoming_rate = (double) incoming_rate; 144 adjusted_incoming_rate = (double)incoming_rate;
153 } 145 }
154 146
155 /* report incoming traffic in KBytes/sec */ 147 /* report incoming traffic in KBytes/sec */
156 else if (incoming_rate < (1024 * 1024)) { 148 else if (incoming_rate < (1024 * 1024)) {
157 strcpy (incoming_speed_rating, "KB"); 149 strcpy(incoming_speed_rating, "KB");
158 adjusted_incoming_rate = (double) (incoming_rate / 1024.0); 150 adjusted_incoming_rate = (double)(incoming_rate / 1024.0);
159 } 151 }
160 152
161 /* report incoming traffic in MBytes/sec */ 153 /* report incoming traffic in MBytes/sec */
162 else { 154 else {
163 strcpy (incoming_speed_rating, "MB"); 155 strcpy(incoming_speed_rating, "MB");
164 adjusted_incoming_rate = (double) (incoming_rate / 1024.0 / 1024.0); 156 adjusted_incoming_rate = (double)(incoming_rate / 1024.0 / 1024.0);
165 } 157 }
166 158
159 double adjusted_outgoing_rate = 0.0;
160 char outgoing_speed_rating[8];
167 /* report outgoing traffic in Bytes/sec */ 161 /* report outgoing traffic in Bytes/sec */
168 if (outgoing_rate < 1024) { 162 if (outgoing_rate < 1024) {
169 strcpy (outgoing_speed_rating, "B"); 163 strcpy(outgoing_speed_rating, "B");
170 adjusted_outgoing_rate = (double) outgoing_rate; 164 adjusted_outgoing_rate = (double)outgoing_rate;
171 } 165 }
172 166
173 /* report outgoing traffic in KBytes/sec */ 167 /* report outgoing traffic in KBytes/sec */
174 else if (outgoing_rate < (1024 * 1024)) { 168 else if (outgoing_rate < (1024 * 1024)) {
175 strcpy (outgoing_speed_rating, "KB"); 169 strcpy(outgoing_speed_rating, "KB");
176 adjusted_outgoing_rate = (double) (outgoing_rate / 1024.0); 170 adjusted_outgoing_rate = (double)(outgoing_rate / 1024.0);
177 } 171 }
178 172
179 /* report outgoing traffic in MBytes/sec */ 173 /* report outgoing traffic in MBytes/sec */
180 else { 174 else {
181 strcpy (outgoing_speed_rating, "MB"); 175 strcpy(outgoing_speed_rating, "MB");
182 adjusted_outgoing_rate = (double) (outgoing_rate / 1024.0 / 1024.0); 176 adjusted_outgoing_rate = (outgoing_rate / 1024.0 / 1024.0);
183 } 177 }
184 178
185 if (incoming_rate > incoming_critical_threshold 179 int result = STATE_OK;
186 || outgoing_rate > outgoing_critical_threshold) { 180 if (incoming_rate > config.incoming_critical_threshold || outgoing_rate > config.outgoing_critical_threshold) {
187 result = STATE_CRITICAL; 181 result = STATE_CRITICAL;
188 } 182 } else if (incoming_rate > config.incoming_warning_threshold || outgoing_rate > config.outgoing_warning_threshold) {
189 else if (incoming_rate > incoming_warning_threshold
190 || outgoing_rate > outgoing_warning_threshold) {
191 result = STATE_WARNING; 183 result = STATE_WARNING;
192 } 184 }
193 185
194 xasprintf (&error_message, _("%s. In = %0.1f %s/s, %s. Out = %0.1f %s/s|%s %s\n"), 186 char *error_message;
195 (use_average) ? _("Avg") : _("Max"), adjusted_incoming_rate, 187 xasprintf(&error_message, _("%s. In = %0.1f %s/s, %s. Out = %0.1f %s/s|%s %s\n"), (config.use_average) ? _("Avg") : _("Max"),
196 incoming_speed_rating, (use_average) ? _("Avg") : _("Max"), 188 adjusted_incoming_rate, incoming_speed_rating, (config.use_average) ? _("Avg") : _("Max"), adjusted_outgoing_rate,
197 adjusted_outgoing_rate, outgoing_speed_rating, 189 outgoing_speed_rating,
198 fperfdata("in", adjusted_incoming_rate, incoming_speed_rating, 190 fperfdata("in", adjusted_incoming_rate, incoming_speed_rating, (int)config.incoming_warning_threshold,
199 (int)incoming_warning_threshold, incoming_warning_threshold, 191 config.incoming_warning_threshold, (int)config.incoming_critical_threshold, config.incoming_critical_threshold,
200 (int)incoming_critical_threshold, incoming_critical_threshold, 192 true, 0, false, 0),
201 true, 0, false, 0), 193 fperfdata("out", adjusted_outgoing_rate, outgoing_speed_rating, (int)config.outgoing_warning_threshold,
202 fperfdata("out", adjusted_outgoing_rate, outgoing_speed_rating, 194 config.outgoing_warning_threshold, (int)config.outgoing_critical_threshold, config.outgoing_critical_threshold,
203 (int)outgoing_warning_threshold, outgoing_warning_threshold, 195 true, 0, false, 0));
204 (int)outgoing_critical_threshold, outgoing_critical_threshold, 196
205 true, 0, false, 0)); 197 printf(_("Traffic %s - %s\n"), state_text(result), error_message);
206
207 printf (_("Traffic %s - %s\n"), state_text(result), error_message);
208 198
209 return result; 199 return result;
210} 200}
211 201
212
213
214/* process command-line arguments */ 202/* process command-line arguments */
215int 203check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) {
216process_arguments (int argc, char **argv) 204 static struct option longopts[] = {{"filename", required_argument, 0, 'F'},
217{ 205 {"expires", required_argument, 0, 'e'},
218 int c; 206 {"aggregation", required_argument, 0, 'a'},
219 207 {"critical", required_argument, 0, 'c'},
220 int option = 0; 208 {"warning", required_argument, 0, 'w'},
221 static struct option longopts[] = { 209 {"version", no_argument, 0, 'V'},
222 {"filename", required_argument, 0, 'F'}, 210 {"help", no_argument, 0, 'h'},
223 {"expires", required_argument, 0, 'e'}, 211 {0, 0, 0, 0}};
224 {"aggregation", required_argument, 0, 'a'}, 212
225 {"critical", required_argument, 0, 'c'}, 213 check_mrtgtraf_config_wrapper result = {
226 {"warning", required_argument, 0, 'w'}, 214 .errorcode = OK,
227 {"version", no_argument, 0, 'V'}, 215 .config = check_mrtgtraf_config_init(),
228 {"help", no_argument, 0, 'h'},
229 {0, 0, 0, 0}
230 }; 216 };
217 if (argc < 2) {
218 result.errorcode = ERROR;
219 return result;
220 }
231 221
232 if (argc < 2) 222 for (int i = 1; i < argc; i++) {
233 return ERROR; 223 if (strcmp("-to", argv[i]) == 0) {
234 224 strcpy(argv[i], "-t");
235 for (c = 1; c < argc; c++) { 225 } else if (strcmp("-wt", argv[i]) == 0) {
236 if (strcmp ("-to", argv[c]) == 0) 226 strcpy(argv[i], "-w");
237 strcpy (argv[c], "-t"); 227 } else if (strcmp("-ct", argv[i]) == 0) {
238 else if (strcmp ("-wt", argv[c]) == 0) 228 strcpy(argv[i], "-c");
239 strcpy (argv[c], "-w"); 229 }
240 else if (strcmp ("-ct", argv[c]) == 0)
241 strcpy (argv[c], "-c");
242 } 230 }
243 231
244 while (1) { 232 int option_char;
245 c = getopt_long (argc, argv, "hVF:e:a:c:w:", longopts, &option); 233 int option = 0;
234 while (true) {
235 option_char = getopt_long(argc, argv, "hVF:e:a:c:w:", longopts, &option);
246 236
247 if (c == -1 || c == EOF) 237 if (option_char == -1 || option_char == EOF) {
248 break; 238 break;
239 }
249 240
250 switch (c) { 241 switch (option_char) {
251 case 'F': /* input file */ 242 case 'F': /* input file */
252 log_file = optarg; 243 result.config.log_file = optarg;
253 break; 244 break;
254 case 'e': /* expiration time */ 245 case 'e': /* expiration time */
255 expire_minutes = atoi (optarg); 246 result.config.expire_minutes = atoi(optarg);
256 break; 247 break;
257 case 'a': /* aggregation (AVE or MAX) */ 248 case 'a': /* aggregation (AVE or MAX) */
258 if (!strcmp (optarg, "MAX")) 249 result.config.use_average = (bool)(strcmp(optarg, "MAX"));
259 use_average = false;
260 else
261 use_average = true;
262 break; 250 break;
263 case 'c': /* warning threshold */ 251 case 'c': /* warning threshold */
264 sscanf (optarg, "%lu,%lu", &incoming_critical_threshold, 252 sscanf(optarg, "%lu,%lu", &result.config.incoming_critical_threshold, &result.config.outgoing_critical_threshold);
265 &outgoing_critical_threshold);
266 break; 253 break;
267 case 'w': /* critical threshold */ 254 case 'w': /* critical threshold */
268 sscanf (optarg, "%lu,%lu", &incoming_warning_threshold, 255 sscanf(optarg, "%lu,%lu", &result.config.incoming_warning_threshold, &result.config.outgoing_warning_threshold);
269 &outgoing_warning_threshold);
270 break; 256 break;
271 case 'V': /* version */ 257 case 'V': /* version */
272 print_revision (progname, NP_VERSION); 258 print_revision(progname, NP_VERSION);
273 exit (STATE_UNKNOWN); 259 exit(STATE_UNKNOWN);
274 case 'h': /* help */ 260 case 'h': /* help */
275 print_help (); 261 print_help();
276 exit (STATE_UNKNOWN); 262 exit(STATE_UNKNOWN);
277 case '?': /* help */ 263 case '?': /* help */
278 usage5 (); 264 usage5();
279 } 265 }
280 } 266 }
281 267
282 c = optind; 268 option_char = optind;
283 if (argc > c && log_file == NULL) { 269 if (argc > option_char && result.config.log_file == NULL) {
284 log_file = argv[c++]; 270 result.config.log_file = argv[option_char++];
285 } 271 }
286 272
287 if (argc > c && expire_minutes == -1) { 273 if (argc > option_char && result.config.expire_minutes == -1) {
288 expire_minutes = atoi (argv[c++]); 274 result.config.expire_minutes = atoi(argv[option_char++]);
289 } 275 }
290 276
291 if (argc > c && strcmp (argv[c], "MAX") == 0) { 277 if (argc > option_char && strcmp(argv[option_char], "MAX") == 0) {
292 use_average = false; 278 result.config.use_average = false;
293 c++; 279 option_char++;
294 } 280 } else if (argc > option_char && strcmp(argv[option_char], "AVG") == 0) {
295 else if (argc > c && strcmp (argv[c], "AVG") == 0) { 281 result.config.use_average = true;
296 use_average = true; 282 option_char++;
297 c++;
298 } 283 }
299 284
300 if (argc > c && incoming_warning_threshold == 0) { 285 if (argc > option_char && result.config.incoming_warning_threshold == 0) {
301 incoming_warning_threshold = strtoul (argv[c++], NULL, 10); 286 result.config.incoming_warning_threshold = strtoul(argv[option_char++], NULL, 10);
302 } 287 }
303 288
304 if (argc > c && incoming_critical_threshold == 0) { 289 if (argc > option_char && result.config.incoming_critical_threshold == 0) {
305 incoming_critical_threshold = strtoul (argv[c++], NULL, 10); 290 result.config.incoming_critical_threshold = strtoul(argv[option_char++], NULL, 10);
306 } 291 }
307 292
308 if (argc > c && outgoing_warning_threshold == 0) { 293 if (argc > option_char && result.config.outgoing_warning_threshold == 0) {
309 outgoing_warning_threshold = strtoul (argv[c++], NULL, 10); 294 result.config.outgoing_warning_threshold = strtoul(argv[option_char++], NULL, 10);
310 } 295 }
311
312 if (argc > c && outgoing_critical_threshold == 0) {
313 outgoing_critical_threshold = strtoul (argv[c++], NULL, 10);
314 }
315
316 return validate_arguments ();
317}
318 296
297 if (argc > option_char && result.config.outgoing_critical_threshold == 0) {
298 result.config.outgoing_critical_threshold = strtoul(argv[option_char++], NULL, 10);
299 }
319 300
320int 301 return result;
321validate_arguments (void)
322{
323 return OK;
324} 302}
325 303
326 304void print_help(void) {
327void 305 print_revision(progname, NP_VERSION);
328print_help (void) 306
329{ 307 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
330 print_revision (progname, NP_VERSION); 308 printf(COPYRIGHT, copyright, email);
331 309
332 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 310 printf("%s\n", _("This plugin will check the incoming/outgoing transfer rates of a router,"));
333 printf (COPYRIGHT, copyright, email); 311 printf("%s\n", _("switch, etc recorded in an MRTG log. If the newest log entry is older"));
334 312 printf("%s\n", _("than <expire_minutes>, a WARNING status is returned. If either the"));
335 printf ("%s\n", _("This plugin will check the incoming/outgoing transfer rates of a router,")); 313 printf("%s\n", _("incoming or outgoing rates exceed the <icl> or <ocl> thresholds (in"));
336 printf ("%s\n", _("switch, etc recorded in an MRTG log. If the newest log entry is older")); 314 printf("%s\n", _("Bytes/sec), a CRITICAL status results. If either of the rates exceed"));
337 printf ("%s\n", _("than <expire_minutes>, a WARNING status is returned. If either the")); 315 printf("%s\n", _("the <iwl> or <owl> thresholds (in Bytes/sec), a WARNING status results."));
338 printf ("%s\n", _("incoming or outgoing rates exceed the <icl> or <ocl> thresholds (in")); 316
339 printf ("%s\n", _("Bytes/sec), a CRITICAL status results. If either of the rates exceed")); 317 printf("\n\n");
340 printf ("%s\n", _("the <iwl> or <owl> thresholds (in Bytes/sec), a WARNING status results.")); 318
341 319 print_usage();
342 printf ("\n\n"); 320
343 321 printf(UT_HELP_VRSN);
344 print_usage (); 322 printf(UT_EXTRA_OPTS);
345 323
346 printf (UT_HELP_VRSN); 324 printf(" %s\n", "-F, --filename=STRING");
347 printf (UT_EXTRA_OPTS); 325 printf(" %s\n", _("File to read log from"));
348 326 printf(" %s\n", "-e, --expires=INTEGER");
349 printf (" %s\n", "-F, --filename=STRING"); 327 printf(" %s\n", _("Minutes after which log expires"));
350 printf (" %s\n", _("File to read log from")); 328 printf(" %s\n", "-a, --aggregation=(AVG|MAX)");
351 printf (" %s\n", "-e, --expires=INTEGER"); 329 printf(" %s\n", _("Test average or maximum"));
352 printf (" %s\n", _("Minutes after which log expires")); 330 printf(" %s\n", "-w, --warning");
353 printf (" %s\n", "-a, --aggregation=(AVG|MAX)"); 331 printf(" %s\n", _("Warning threshold pair <incoming>,<outgoing>"));
354 printf (" %s\n", _("Test average or maximum")); 332 printf(" %s\n", "-c, --critical");
355 printf (" %s\n", "-w, --warning"); 333 printf(" %s\n", _("Critical threshold pair <incoming>,<outgoing>"));
356 printf (" %s\n", _("Warning threshold pair <incoming>,<outgoing>")); 334
357 printf (" %s\n", "-c, --critical"); 335 printf("\n");
358 printf (" %s\n", _("Critical threshold pair <incoming>,<outgoing>")); 336 printf("%s\n", _("Notes:"));
359 337 printf(" %s\n", _("- MRTG stands for Multi Router Traffic Grapher. It can be downloaded from"));
360 printf ("\n"); 338 printf(" %s\n", " http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html");
361 printf ("%s\n", _("Notes:")); 339 printf(" %s\n", _("- While MRTG can monitor things other than traffic rates, this"));
362 printf (" %s\n", _("- MRTG stands for Multi Router Traffic Grapher. It can be downloaded from")); 340 printf(" %s\n", _(" plugin probably won't work with much else without modification."));
363 printf (" %s\n", " http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html"); 341 printf(" %s\n", _("- The calculated i/o rates are a little off from what MRTG actually"));
364 printf (" %s\n", _("- While MRTG can monitor things other than traffic rates, this")); 342 printf(" %s\n", _(" reports. I'm not sure why this is right now, but will look into it"));
365 printf (" %s\n", _(" plugin probably won't work with much else without modification.")); 343 printf(" %s\n", _(" for future enhancements of this plugin."));
366 printf (" %s\n", _("- The calculated i/o rates are a little off from what MRTG actually")); 344
367 printf (" %s\n", _(" reports. I'm not sure why this is right now, but will look into it")); 345 printf(UT_SUPPORT);
368 printf (" %s\n", _(" for future enhancements of this plugin."));
369
370 printf (UT_SUPPORT);
371} 346}
372 347
373 348void print_usage(void) {
374 349 printf(_("Usage"));
375void 350 printf(" %s -F <log_file> -a <AVG | MAX> -w <warning_pair>\n", progname);
376print_usage (void) 351 printf("-c <critical_pair> [-e expire_minutes]\n");
377{
378 printf (_("Usage"));
379 printf (" %s -F <log_file> -a <AVG | MAX> -w <warning_pair>\n",progname);
380 printf ("-c <critical_pair> [-e expire_minutes]\n");
381} 352}
diff --git a/plugins/check_mrtgtraf.d/config.h b/plugins/check_mrtgtraf.d/config.h
new file mode 100644
index 00000000..94929ff7
--- /dev/null
+++ b/plugins/check_mrtgtraf.d/config.h
@@ -0,0 +1,30 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5#include <stdlib.h>
6
7typedef struct {
8 char *log_file;
9 int expire_minutes;
10 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
16} check_mrtgtraf_config;
17
18check_mrtgtraf_config check_mrtgtraf_config_init() {
19 check_mrtgtraf_config tmp = {
20 .log_file = NULL,
21 .expire_minutes = -1,
22 .use_average = true,
23
24 .incoming_warning_threshold = 0,
25 .incoming_critical_threshold = 0,
26 .outgoing_warning_threshold = 0,
27 .outgoing_critical_threshold = 0,
28 };
29 return tmp;
30}
diff --git a/plugins/check_mysql.c b/plugins/check_mysql.c
index 15ec04c0..ca3422b5 100644
--- a/plugins/check_mysql.c
+++ b/plugins/check_mysql.c
@@ -1,267 +1,281 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_mysql plugin 3 * Monitoring check_mysql plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999 Didi Rieder (adrieder@sbox.tu-graz.ac.at) 6 * Copyright (c) 1999 Didi Rieder (adrieder@sbox.tu-graz.ac.at)
7* Copyright (c) 2000 Karl DeBisschop (kdebisschop@users.sourceforge.net) 7 * Copyright (c) 2000 Karl DeBisschop (kdebisschop@users.sourceforge.net)
8* Copyright (c) 1999-2011 Monitoring Plugins Development Team 8 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
9* 9 *
10* Description: 10 * Description:
11* 11 *
12* This file contains the check_mysql plugin 12 * This file contains the check_mysql plugin
13* 13 *
14* This program tests connections to a mysql server 14 * This program tests connections to a mysql server
15* 15 *
16* 16 *
17* This program is free software: you can redistribute it and/or modify 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 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 19 * the Free Software Foundation, either version 3 of the License, or
20* (at your option) any later version. 20 * (at your option) any later version.
21* 21 *
22* This program is distributed in the hope that it will be useful, 22 * This program is distributed in the hope that it will be useful,
23* but WITHOUT ANY WARRANTY; without even the implied warranty of 23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25* GNU General Public License for more details. 25 * GNU General Public License for more details.
26* 26 *
27* You should have received a copy of the GNU General Public License 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/>. 28 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29* 29 *
30* 30 *
31*****************************************************************************/ 31 *****************************************************************************/
32 32
33const char *progname = "check_mysql"; 33const char *progname = "check_mysql";
34const char *copyright = "1999-2011"; 34const char *copyright = "1999-2024";
35const char *email = "devel@monitoring-plugins.org"; 35const char *email = "devel@monitoring-plugins.org";
36 36
37#define SLAVERESULTSIZE 96 37#define REPLICA_RESULTSIZE 96
38 38
39#include "common.h" 39#include "common.h"
40#include "utils.h" 40#include "utils.h"
41#include "utils_base.h" 41#include "utils_base.h"
42#include "netutils.h" 42#include "netutils.h"
43#include "check_mysql.d/config.h"
43 44
44#include <mysql.h> 45#include <mysql.h>
45#include <mysqld_error.h> 46#include <mysqld_error.h>
46#include <errmsg.h> 47#include <errmsg.h>
47 48
48char *db_user = NULL; 49static int verbose = 0;
49char *db_host = NULL;
50char *db_socket = NULL;
51char *db_pass = NULL;
52char *db = NULL;
53char *ca_cert = NULL;
54char *ca_dir = NULL;
55char *cert = NULL;
56char *key = NULL;
57char *ciphers = NULL;
58bool ssl = false;
59char *opt_file = NULL;
60char *opt_group = NULL;
61unsigned int db_port = MYSQL_PORT;
62bool check_slave = false;
63bool ignore_auth = false;
64int verbose = 0;
65
66static double warning_time = 0;
67static double critical_time = 0;
68 50
69#define LENGTH_METRIC_UNIT 6 51#define LENGTH_METRIC_UNIT 6
70static const char *metric_unit[LENGTH_METRIC_UNIT] = { 52static const char *metric_unit[LENGTH_METRIC_UNIT] = {
71 "Open_files", 53 "Open_files", "Open_tables", "Qcache_free_memory", "Qcache_queries_in_cache", "Threads_connected", "Threads_running"};
72 "Open_tables",
73 "Qcache_free_memory",
74 "Qcache_queries_in_cache",
75 "Threads_connected",
76 "Threads_running"
77};
78 54
79#define LENGTH_METRIC_COUNTER 9 55#define LENGTH_METRIC_COUNTER 9
80static const char *metric_counter[LENGTH_METRIC_COUNTER] = { 56static const char *metric_counter[LENGTH_METRIC_COUNTER] = {
81 "Connections", 57 "Connections", "Qcache_hits", "Qcache_inserts", "Qcache_lowmem_prunes", "Qcache_not_cached", "Queries",
82 "Qcache_hits", 58 "Questions", "Table_locks_waited", "Uptime"};
83 "Qcache_inserts", 59
84 "Qcache_lowmem_prunes", 60#define MYSQLDUMP_THREADS_QUERY \
85 "Qcache_not_cached", 61 "SELECT COUNT(1) mysqldumpThreads FROM information_schema.processlist WHERE info LIKE 'SELECT /*!40001 SQL_NO_CACHE */%'"
86 "Queries", 62
87 "Questions", 63typedef struct {
88 "Table_locks_waited", 64 int errorcode;
89 "Uptime" 65 check_mysql_config config;
90}; 66} check_mysql_config_wrapper;
91 67static check_mysql_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
92#define MYSQLDUMP_THREADS_QUERY "SELECT COUNT(1) mysqldumpThreads FROM information_schema.processlist WHERE info LIKE 'SELECT /*!40001 SQL_NO_CACHE */%'" 68static check_mysql_config_wrapper validate_arguments(check_mysql_config_wrapper /*config_wrapper*/);
93 69static void print_help(void);
94thresholds *my_threshold = NULL; 70void print_usage(void);
95 71
96int process_arguments (int, char **); 72int main(int argc, char **argv) {
97int validate_arguments (void); 73 setlocale(LC_ALL, "");
98void print_help (void); 74 bindtextdomain(PACKAGE, LOCALEDIR);
99void print_usage (void); 75 textdomain(PACKAGE);
100
101int
102main (int argc, char **argv)
103{
104 76
105 MYSQL mysql; 77 /* Parse extra opts if any */
106 MYSQL_RES *res; 78 argv = np_extra_opts(&argc, argv, progname);
107 MYSQL_ROW row;
108
109 /* should be status */
110 79
111 char *result = NULL; 80 check_mysql_config_wrapper tmp_config = process_arguments(argc, argv);
112 char *error = NULL; 81 if (tmp_config.errorcode == ERROR) {
113 char slaveresult[SLAVERESULTSIZE] = { 0 }; 82 usage4(_("Could not parse arguments"));
114 char* perf; 83 }
115 84
116 perf = strdup (""); 85 const check_mysql_config config = tmp_config.config;
117 86
118 setlocale (LC_ALL, ""); 87 MYSQL mysql;
119 bindtextdomain (PACKAGE, LOCALEDIR); 88 /* initialize mysql */
120 textdomain (PACKAGE); 89 mysql_init(&mysql);
121 90
122 /* Parse extra opts if any */ 91 if (config.opt_file != NULL) {
123 argv=np_extra_opts (&argc, argv, progname); 92 mysql_options(&mysql, MYSQL_READ_DEFAULT_FILE, config.opt_file);
93 }
124 94
125 if (process_arguments (argc, argv) == ERROR) 95 if (config.opt_group != NULL) {
126 usage4 (_("Could not parse arguments")); 96 mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, config.opt_group);
97 } else {
98 mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "client");
99 }
127 100
128 /* initialize mysql */ 101 if (config.ssl) {
129 mysql_init (&mysql); 102 mysql_ssl_set(&mysql, config.key, config.cert, config.ca_cert, config.ca_dir, config.ciphers);
130 103 }
131 if (opt_file != NULL)
132 mysql_options(&mysql,MYSQL_READ_DEFAULT_FILE,opt_file);
133
134 if (opt_group != NULL)
135 mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,opt_group);
136 else
137 mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,"client");
138
139 if (ssl)
140 mysql_ssl_set(&mysql,key,cert,ca_cert,ca_dir,ciphers);
141 /* establish a connection to the server and error checking */ 104 /* establish a connection to the server and error checking */
142 if (!mysql_real_connect(&mysql,db_host,db_user,db_pass,db,db_port,db_socket,0)) { 105 if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db, config.db_port, config.db_socket, 0)) {
143 /* Depending on internally-selected auth plugin MySQL might return */ 106 /* Depending on internally-selected auth plugin MySQL might return */
144 /* ER_ACCESS_DENIED_NO_PASSWORD_ERROR or ER_ACCESS_DENIED_ERROR. */ 107 /* ER_ACCESS_DENIED_NO_PASSWORD_ERROR or ER_ACCESS_DENIED_ERROR. */
145 /* Semantically these errors are the same. */ 108 /* Semantically these errors are the same. */
146 if (ignore_auth && (mysql_errno (&mysql) == ER_ACCESS_DENIED_ERROR || mysql_errno (&mysql) == ER_ACCESS_DENIED_NO_PASSWORD_ERROR)) 109 if (config.ignore_auth &&
147 { 110 (mysql_errno(&mysql) == ER_ACCESS_DENIED_ERROR || mysql_errno(&mysql) == ER_ACCESS_DENIED_NO_PASSWORD_ERROR)) {
148 printf("MySQL OK - Version: %s (protocol %d)\n", 111 printf("MySQL OK - Version: %s (protocol %d)\n", mysql_get_server_info(&mysql), mysql_get_proto_info(&mysql));
149 mysql_get_server_info(&mysql), 112 mysql_close(&mysql);
150 mysql_get_proto_info(&mysql)
151 );
152 mysql_close (&mysql);
153 return STATE_OK; 113 return STATE_OK;
154 } 114 }
155 else if (mysql_errno (&mysql) == CR_UNKNOWN_HOST) 115
156 die (STATE_WARNING, "%s\n", mysql_error (&mysql)); 116 if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) {
157 else if (mysql_errno (&mysql) == CR_VERSION_ERROR) 117 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
158 die (STATE_WARNING, "%s\n", mysql_error (&mysql)); 118 } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) {
159 else if (mysql_errno (&mysql) == CR_OUT_OF_MEMORY) 119 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
160 die (STATE_WARNING, "%s\n", mysql_error (&mysql)); 120 } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) {
161 else if (mysql_errno (&mysql) == CR_IPSOCK_ERROR) 121 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
162 die (STATE_WARNING, "%s\n", mysql_error (&mysql)); 122 } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) {
163 else if (mysql_errno (&mysql) == CR_SOCKET_CREATE_ERROR) 123 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
164 die (STATE_WARNING, "%s\n", mysql_error (&mysql)); 124 } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) {
165 else 125 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
166 die (STATE_CRITICAL, "%s\n", mysql_error (&mysql)); 126 } else {
127 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql));
128 }
167 } 129 }
168 130
169 /* get the server stats */ 131 /* get the server stats */
170 result = strdup (mysql_stat (&mysql)); 132 char *result = strdup(mysql_stat(&mysql));
171 133
172 /* error checking once more */ 134 /* error checking once more */
173 if (mysql_error (&mysql)) { 135 if (mysql_error(&mysql)) {
174 if (mysql_errno (&mysql) == CR_SERVER_GONE_ERROR) 136 if (mysql_errno(&mysql) == CR_SERVER_GONE_ERROR) {
175 die (STATE_CRITICAL, "%s\n", mysql_error (&mysql)); 137 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql));
176 else if (mysql_errno (&mysql) == CR_SERVER_LOST) 138 } else if (mysql_errno(&mysql) == CR_SERVER_LOST) {
177 die (STATE_CRITICAL, "%s\n", mysql_error (&mysql)); 139 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql));
178 else if (mysql_errno (&mysql) == CR_UNKNOWN_ERROR) 140 } else if (mysql_errno(&mysql) == CR_UNKNOWN_ERROR) {
179 die (STATE_CRITICAL, "%s\n", mysql_error (&mysql)); 141 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql));
142 }
180 } 143 }
181 144
145 char *perf = strdup("");
146 char *error = NULL;
147 MYSQL_RES *res;
148 MYSQL_ROW row;
182 /* try to fetch some perf data */ 149 /* try to fetch some perf data */
183 if (mysql_query (&mysql, "show global status") == 0) { 150 if (mysql_query(&mysql, "show global status") == 0) {
184 if ( (res = mysql_store_result (&mysql)) == NULL) { 151 if ((res = mysql_store_result(&mysql)) == NULL) {
185 error = strdup(mysql_error(&mysql)); 152 error = strdup(mysql_error(&mysql));
186 mysql_close (&mysql); 153 mysql_close(&mysql);
187 die (STATE_CRITICAL, _("status store_result error: %s\n"), error); 154 die(STATE_CRITICAL, _("status store_result error: %s\n"), error);
188 } 155 }
189 156
190 while ( (row = mysql_fetch_row (res)) != NULL) { 157 while ((row = mysql_fetch_row(res)) != NULL) {
191 int i; 158 for (int i = 0; i < LENGTH_METRIC_UNIT; i++) {
192
193 for(i = 0; i < LENGTH_METRIC_UNIT; i++) {
194 if (strcmp(row[0], metric_unit[i]) == 0) { 159 if (strcmp(row[0], metric_unit[i]) == 0) {
195 xasprintf(&perf, "%s%s ", perf, perfdata(metric_unit[i], 160 xasprintf(&perf, "%s%s ", perf, perfdata(metric_unit[i], atol(row[1]), "", false, 0, false, 0, false, 0, false, 0));
196 atol(row[1]), "", false, 0, false, 0, false, 0, false, 0));
197 continue; 161 continue;
198 } 162 }
199 } 163 }
200 for(i = 0; i < LENGTH_METRIC_COUNTER; i++) { 164 for (int i = 0; i < LENGTH_METRIC_COUNTER; i++) {
201 if (strcmp(row[0], metric_counter[i]) == 0) { 165 if (strcmp(row[0], metric_counter[i]) == 0) {
202 xasprintf(&perf, "%s%s ", perf, perfdata(metric_counter[i], 166 xasprintf(&perf, "%s%s ", perf, perfdata(metric_counter[i], atol(row[1]), "c", false, 0, false, 0, false, 0, false, 0));
203 atol(row[1]), "c", false, 0, false, 0, false, 0, false, 0));
204 continue; 167 continue;
205 } 168 }
206 } 169 }
207 } 170 }
208 /* remove trailing space */ 171 /* remove trailing space */
209 if (strlen(perf) > 0) 172 if (strlen(perf) > 0) {
210 perf[strlen(perf) - 1] = '\0'; 173 perf[strlen(perf) - 1] = '\0';
174 }
211 } 175 }
212 176
213 if(check_slave) { 177 char replica_result[REPLICA_RESULTSIZE] = {0};
214 /* check the slave status */ 178 if (config.check_replica) {
215 if (mysql_query (&mysql, "show slave status") != 0) { 179 // Detect which version we are, on older version
180 // "show slave status" should work, on newer ones
181 // "show replica status"
182 // But first we have to find out whether this is
183 // MySQL or MariaDB since the version numbering scheme
184 // is different
185 bool use_deprecated_slave_status = false;
186 const char *server_version = mysql_get_server_info(&mysql);
187 unsigned long server_verion_int = mysql_get_server_version(&mysql);
188 unsigned long major_version = server_verion_int / 10000;
189 unsigned long minor_version = (server_verion_int % 10000) / 100;
190 unsigned long patch_version = (server_verion_int % 100);
191 if (verbose) {
192 printf("Found MariaDB: %s, main version: %lu, minor version: %lu, patch version: %lu\n", server_version, major_version,
193 minor_version, patch_version);
194 }
195
196 if (strstr(server_version, "MariaDB") != NULL) {
197 // Looks like MariaDB, new commands should be available after 10.5.1
198 if (major_version < 10) {
199 use_deprecated_slave_status = true;
200 } else if (major_version == 10) {
201 if (minor_version < 5) {
202 use_deprecated_slave_status = true;
203 } else if (minor_version == 5 && patch_version < 1) {
204 use_deprecated_slave_status = true;
205 }
206 }
207 } else if (strstr(server_version, "MySQL") != NULL) {
208 // Looks like MySQL
209 if (major_version < 8) {
210 use_deprecated_slave_status = true;
211 } else if (major_version == 10 && minor_version < 4) {
212 use_deprecated_slave_status = true;
213 }
214 } else {
215 printf("Not a known sever implementation: %s\n", server_version);
216 exit(STATE_UNKNOWN);
217 }
218
219 char *replica_query = NULL;
220 if (use_deprecated_slave_status) {
221 replica_query = "show slave status";
222 } else {
223 replica_query = "show replica status";
224 }
225
226 /* check the replica status */
227 if (mysql_query(&mysql, replica_query) != 0) {
216 error = strdup(mysql_error(&mysql)); 228 error = strdup(mysql_error(&mysql));
217 mysql_close (&mysql); 229 mysql_close(&mysql);
218 die (STATE_CRITICAL, _("slave query error: %s\n"), error); 230 die(STATE_CRITICAL, _("replica query error: %s\n"), error);
219 } 231 }
220 232
221 /* store the result */ 233 /* store the result */
222 if ( (res = mysql_store_result (&mysql)) == NULL) { 234 if ((res = mysql_store_result(&mysql)) == NULL) {
223 error = strdup(mysql_error(&mysql)); 235 error = strdup(mysql_error(&mysql));
224 mysql_close (&mysql); 236 mysql_close(&mysql);
225 die (STATE_CRITICAL, _("slave store_result error: %s\n"), error); 237 die(STATE_CRITICAL, _("replica store_result error: %s\n"), error);
226 } 238 }
227 239
228 /* Check there is some data */ 240 /* Check there is some data */
229 if (mysql_num_rows(res) == 0) { 241 if (mysql_num_rows(res) == 0) {
230 mysql_close(&mysql); 242 mysql_close(&mysql);
231 die (STATE_WARNING, "%s\n", _("No slaves defined")); 243 die(STATE_WARNING, "%s\n", _("No replicas defined"));
232 } 244 }
233 245
234 /* fetch the first row */ 246 /* fetch the first row */
235 if ( (row = mysql_fetch_row (res)) == NULL) { 247 if ((row = mysql_fetch_row(res)) == NULL) {
236 error = strdup(mysql_error(&mysql)); 248 error = strdup(mysql_error(&mysql));
237 mysql_free_result (res); 249 mysql_free_result(res);
238 mysql_close (&mysql); 250 mysql_close(&mysql);
239 die (STATE_CRITICAL, _("slave fetch row error: %s\n"), error); 251 die(STATE_CRITICAL, _("replica fetch row error: %s\n"), error);
240 } 252 }
241 253
242 if (mysql_field_count (&mysql) == 12) { 254 if (mysql_field_count(&mysql) == 12) {
243 /* mysql 3.23.x */ 255 /* mysql 3.23.x */
244 snprintf (slaveresult, SLAVERESULTSIZE, _("Slave running: %s"), row[6]); 256 snprintf(replica_result, REPLICA_RESULTSIZE, _("Replica running: %s"), row[6]);
245 if (strcmp (row[6], "Yes") != 0) { 257 if (strcmp(row[6], "Yes") != 0) {
246 mysql_free_result (res); 258 mysql_free_result(res);
247 mysql_close (&mysql); 259 mysql_close(&mysql);
248 die (STATE_CRITICAL, "%s\n", slaveresult); 260 die(STATE_CRITICAL, "%s\n", replica_result);
249 } 261 }
250 262
251 } else { 263 } else {
252 /* mysql 4.x.x and mysql 5.x.x */ 264 /* mysql 4.x.x and mysql 5.x.x */
253 int slave_io_field = -1 , slave_sql_field = -1, seconds_behind_field = -1, i, num_fields; 265 int replica_io_field = -1;
254 MYSQL_FIELD* fields; 266 int replica_sql_field = -1;
255 267 int seconds_behind_field = -1;
268 int num_fields;
269 MYSQL_FIELD *fields;
256 num_fields = mysql_num_fields(res); 270 num_fields = mysql_num_fields(res);
257 fields = mysql_fetch_fields(res); 271 fields = mysql_fetch_fields(res);
258 for(i = 0; i < num_fields; i++) { 272 for (int i = 0; i < num_fields; i++) {
259 if (strcmp(fields[i].name, "Slave_IO_Running") == 0) { 273 if (strcmp(fields[i].name, "Slave_IO_Running") == 0) {
260 slave_io_field = i; 274 replica_io_field = i;
261 continue; 275 continue;
262 } 276 }
263 if (strcmp(fields[i].name, "Slave_SQL_Running") == 0) { 277 if (strcmp(fields[i].name, "Slave_SQL_Running") == 0) {
264 slave_sql_field = i; 278 replica_sql_field = i;
265 continue; 279 continue;
266 } 280 }
267 if (strcmp(fields[i].name, "Seconds_Behind_Master") == 0) { 281 if (strcmp(fields[i].name, "Seconds_Behind_Master") == 0) {
@@ -270,175 +284,177 @@ main (int argc, char **argv)
270 } 284 }
271 } 285 }
272 286
273 /* Check if slave status is available */ 287 /* Check if replica status is available */
274 if ((slave_io_field < 0) || (slave_sql_field < 0) || (num_fields == 0)) { 288 if ((replica_io_field < 0) || (replica_sql_field < 0) || (num_fields == 0)) {
275 mysql_free_result (res); 289 mysql_free_result(res);
276 mysql_close (&mysql); 290 mysql_close(&mysql);
277 die (STATE_CRITICAL, "Slave status unavailable\n"); 291 die(STATE_CRITICAL, "Replica status unavailable\n");
278 } 292 }
279 293
280 /* Save slave status in slaveresult */ 294 /* Save replica status in replica_result */
281 snprintf (slaveresult, SLAVERESULTSIZE, "Slave IO: %s Slave SQL: %s Seconds Behind Master: %s", row[slave_io_field], row[slave_sql_field], seconds_behind_field!=-1?row[seconds_behind_field]:"Unknown"); 295 snprintf(replica_result, REPLICA_RESULTSIZE, "Replica IO: %s Replica SQL: %s Seconds Behind Master: %s", row[replica_io_field],
296 row[replica_sql_field], seconds_behind_field != -1 ? row[seconds_behind_field] : "Unknown");
282 297
283 /* Raise critical error if SQL THREAD or IO THREAD are stopped, but only if there are no mysqldump threads running */ 298 /* Raise critical error if SQL THREAD or IO THREAD are stopped, but only if there are no mysqldump threads running */
284 if (strcmp (row[slave_io_field], "Yes") != 0 || strcmp (row[slave_sql_field], "Yes") != 0) { 299 if (strcmp(row[replica_io_field], "Yes") != 0 || strcmp(row[replica_sql_field], "Yes") != 0) {
285 MYSQL_RES *res_mysqldump; 300 MYSQL_RES *res_mysqldump;
286 MYSQL_ROW row_mysqldump; 301 MYSQL_ROW row_mysqldump;
287 unsigned int mysqldump_threads = 0; 302 unsigned int mysqldump_threads = 0;
288 303
289 if (mysql_query (&mysql, MYSQLDUMP_THREADS_QUERY) == 0) { 304 if (mysql_query(&mysql, MYSQLDUMP_THREADS_QUERY) == 0) {
290 /* store the result */ 305 /* store the result */
291 if ( (res_mysqldump = mysql_store_result (&mysql)) != NULL) { 306 if ((res_mysqldump = mysql_store_result(&mysql)) != NULL) {
292 if (mysql_num_rows(res_mysqldump) == 1) { 307 if (mysql_num_rows(res_mysqldump) == 1) {
293 if ( (row_mysqldump = mysql_fetch_row (res_mysqldump)) != NULL) { 308 if ((row_mysqldump = mysql_fetch_row(res_mysqldump)) != NULL) {
294 mysqldump_threads = atoi(row_mysqldump[0]); 309 mysqldump_threads = atoi(row_mysqldump[0]);
295 } 310 }
296 } 311 }
297 /* free the result */ 312 /* free the result */
298 mysql_free_result (res_mysqldump); 313 mysql_free_result(res_mysqldump);
299 } 314 }
300 mysql_close (&mysql); 315 mysql_close(&mysql);
301 } 316 }
302 if (mysqldump_threads == 0) { 317 if (mysqldump_threads == 0) {
303 die (STATE_CRITICAL, "%s\n", slaveresult); 318 die(STATE_CRITICAL, "%s\n", replica_result);
304 } else { 319 } else {
305 strncat(slaveresult, " Mysqldump: in progress", SLAVERESULTSIZE-1); 320 strncat(replica_result, " Mysqldump: in progress", REPLICA_RESULTSIZE - 1);
306 } 321 }
307 } 322 }
308 323
309 if (verbose >=3) { 324 if (verbose >= 3) {
310 if (seconds_behind_field == -1) { 325 if (seconds_behind_field == -1) {
311 printf("seconds_behind_field not found\n"); 326 printf("seconds_behind_field not found\n");
312 } else { 327 } else {
313 printf ("seconds_behind_field(index %d)=%s\n", seconds_behind_field, row[seconds_behind_field]); 328 printf("seconds_behind_field(index %d)=%s\n", seconds_behind_field, row[seconds_behind_field]);
314 } 329 }
315 } 330 }
316 331
317 /* Check Seconds Behind against threshold */ 332 /* Check Seconds Behind against threshold */
318 if ((seconds_behind_field != -1) && (row[seconds_behind_field] != NULL && strcmp (row[seconds_behind_field], "NULL") != 0)) { 333 if ((seconds_behind_field != -1) && (row[seconds_behind_field] != NULL && strcmp(row[seconds_behind_field], "NULL") != 0)) {
319 double value = atof(row[seconds_behind_field]); 334 double value = atof(row[seconds_behind_field]);
320 int status; 335 int status;
321 336
322 status = get_status(value, my_threshold); 337 status = get_status(value, config.my_threshold);
323 338
324 xasprintf (&perf, "%s %s", perf, fperfdata ("seconds behind master", value, "s", 339 xasprintf(&perf, "%s %s", perf,
325 true, (double) warning_time, 340 fperfdata("seconds behind master", value, "s", true, (double)config.warning_time, true,
326 true, (double) critical_time, 341 (double)config.critical_time, false, 0, false, 0));
327 false, 0,
328 false, 0));
329 342
330 if (status == STATE_WARNING) { 343 if (status == STATE_WARNING) {
331 printf("SLOW_SLAVE %s: %s|%s\n", _("WARNING"), slaveresult, perf); 344 printf("SLOW_REPLICA %s: %s|%s\n", _("WARNING"), replica_result, perf);
332 exit(STATE_WARNING); 345 exit(STATE_WARNING);
333 } else if (status == STATE_CRITICAL) { 346 } else if (status == STATE_CRITICAL) {
334 printf("SLOW_SLAVE %s: %s|%s\n", _("CRITICAL"), slaveresult, perf); 347 printf("SLOW_REPLICA %s: %s|%s\n", _("CRITICAL"), replica_result, perf);
335 exit(STATE_CRITICAL); 348 exit(STATE_CRITICAL);
336 } 349 }
337 } 350 }
338 } 351 }
339 352
340 /* free the result */ 353 /* free the result */
341 mysql_free_result (res); 354 mysql_free_result(res);
342 } 355 }
343 356
344 /* close the connection */ 357 /* close the connection */
345 mysql_close (&mysql); 358 mysql_close(&mysql);
346 359
347 /* print out the result of stats */ 360 /* print out the result of stats */
348 if (check_slave) { 361 if (config.check_replica) {
349 printf ("%s %s|%s\n", result, slaveresult, perf); 362 printf("%s %s|%s\n", result, replica_result, perf);
350 } else { 363 } else {
351 printf ("%s|%s\n", result, perf); 364 printf("%s|%s\n", result, perf);
352 } 365 }
353 366
354 return STATE_OK; 367 return STATE_OK;
355} 368}
356 369
370#define CHECK_REPLICA_OPT CHAR_MAX + 1
357 371
358/* process command-line arguments */ 372/* process command-line arguments */
359int 373check_mysql_config_wrapper process_arguments(int argc, char **argv) {
360process_arguments (int argc, char **argv) 374 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
361{ 375 {"socket", required_argument, 0, 's'},
362 int c; 376 {"database", required_argument, 0, 'd'},
377 {"username", required_argument, 0, 'u'},
378 {"password", required_argument, 0, 'p'},
379 {"file", required_argument, 0, 'f'},
380 {"group", required_argument, 0, 'g'},
381 {"port", required_argument, 0, 'P'},
382 {"critical", required_argument, 0, 'c'},
383 {"warning", required_argument, 0, 'w'},
384 {"check-slave", no_argument, 0, 'S'},
385 {"check-replica", no_argument, 0, CHECK_REPLICA_OPT},
386 {"ignore-auth", no_argument, 0, 'n'},
387 {"verbose", no_argument, 0, 'v'},
388 {"version", no_argument, 0, 'V'},
389 {"help", no_argument, 0, 'h'},
390 {"ssl", no_argument, 0, 'l'},
391 {"ca-cert", optional_argument, 0, 'C'},
392 {"key", required_argument, 0, 'k'},
393 {"cert", required_argument, 0, 'a'},
394 {"ca-dir", required_argument, 0, 'D'},
395 {"ciphers", required_argument, 0, 'L'},
396 {0, 0, 0, 0}};
397
398 check_mysql_config_wrapper result = {
399 .errorcode = OK,
400 .config = check_mysql_config_init(),
401 };
402
403 if (argc < 1) {
404 result.errorcode = ERROR;
405 return result;
406 }
407
363 char *warning = NULL; 408 char *warning = NULL;
364 char *critical = NULL; 409 char *critical = NULL;
365 410
366 int option = 0; 411 int option = 0;
367 static struct option longopts[] = { 412 while (true) {
368 {"hostname", required_argument, 0, 'H'}, 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);
369 {"socket", required_argument, 0, 's'},
370 {"database", required_argument, 0, 'd'},
371 {"username", required_argument, 0, 'u'},
372 {"password", required_argument, 0, 'p'},
373 {"file", required_argument, 0, 'f'},
374 {"group", required_argument, 0, 'g'},
375 {"port", required_argument, 0, 'P'},
376 {"critical", required_argument, 0, 'c'},
377 {"warning", required_argument, 0, 'w'},
378 {"check-slave", no_argument, 0, 'S'},
379 {"ignore-auth", no_argument, 0, 'n'},
380 {"verbose", no_argument, 0, 'v'},
381 {"version", no_argument, 0, 'V'},
382 {"help", no_argument, 0, 'h'},
383 {"ssl", no_argument, 0, 'l'},
384 {"ca-cert", optional_argument, 0, 'C'},
385 {"key", required_argument,0,'k'},
386 {"cert", required_argument,0,'a'},
387 {"ca-dir", required_argument, 0, 'D'},
388 {"ciphers", required_argument, 0, 'L'},
389 {0, 0, 0, 0}
390 };
391 414
392 if (argc < 1) 415 if (option_index == -1 || option_index == EOF) {
393 return ERROR;
394
395 while (1) {
396 c = getopt_long (argc, argv, "hlvVnSP:p:u:d:H:s:c:w:a:k:C:D:L:f:g:", longopts, &option);
397
398 if (c == -1 || c == EOF)
399 break; 416 break;
417 }
400 418
401 switch (c) { 419 switch (option_index) {
402 case 'H': /* hostname */ 420 case 'H': /* hostname */
403 if (is_host (optarg)) { 421 if (is_host(optarg)) {
404 db_host = optarg; 422 result.config.db_host = optarg;
405 } 423 } else if (*optarg == '/') {
406 else if (*optarg == '/') { 424 result.config.db_socket = optarg;
407 db_socket = optarg; 425 } else {
408 } 426 usage2(_("Invalid hostname/address"), optarg);
409 else {
410 usage2 (_("Invalid hostname/address"), optarg);
411 } 427 }
412 break; 428 break;
413 case 's': /* socket */ 429 case 's': /* socket */
414 db_socket = optarg; 430 result.config.db_socket = optarg;
415 break; 431 break;
416 case 'd': /* database */ 432 case 'd': /* database */
417 db = optarg; 433 result.config.db = optarg;
418 break; 434 break;
419 case 'l': 435 case 'l':
420 ssl = true; 436 result.config.ssl = true;
421 break; 437 break;
422 case 'C': 438 case 'C':
423 ca_cert = optarg; 439 result.config.ca_cert = optarg;
424 break; 440 break;
425 case 'a': 441 case 'a':
426 cert = optarg; 442 result.config.cert = optarg;
427 break; 443 break;
428 case 'k': 444 case 'k':
429 key = optarg; 445 result.config.key = optarg;
430 break; 446 break;
431 case 'D': 447 case 'D':
432 ca_dir = optarg; 448 result.config.ca_dir = optarg;
433 break; 449 break;
434 case 'L': 450 case 'L':
435 ciphers = optarg; 451 result.config.ciphers = optarg;
436 break; 452 break;
437 case 'u': /* username */ 453 case 'u': /* username */
438 db_user = optarg; 454 result.config.db_user = optarg;
439 break; 455 break;
440 case 'p': /* authentication information: password */ 456 case 'p': /* authentication information: password */
441 db_pass = strdup(optarg); 457 result.config.db_pass = strdup(optarg);
442 458
443 /* Delete the password from process list */ 459 /* Delete the password from process list */
444 while (*optarg != '\0') { 460 while (*optarg != '\0') {
@@ -446,167 +462,163 @@ process_arguments (int argc, char **argv)
446 optarg++; 462 optarg++;
447 } 463 }
448 break; 464 break;
449 case 'f': /* client options file */ 465 case 'f': /* client options file */
450 opt_file = optarg; 466 result.config.opt_file = optarg;
451 break; 467 break;
452 case 'g': /* client options group */ 468 case 'g': /* client options group */
453 opt_group = optarg; 469 result.config.opt_group = optarg;
454 break; 470 break;
455 case 'P': /* critical time threshold */ 471 case 'P': /* critical time threshold */
456 db_port = atoi (optarg); 472 result.config.db_port = atoi(optarg);
457 break; 473 break;
458 case 'S': 474 case 'S':
459 check_slave = true; /* check-slave */ 475 case CHECK_REPLICA_OPT:
476 result.config.check_replica = true; /* check-slave */
460 break; 477 break;
461 case 'n': 478 case 'n':
462 ignore_auth = true; /* ignore-auth */ 479 result.config.ignore_auth = true; /* ignore-auth */
463 break; 480 break;
464 case 'w': 481 case 'w':
465 warning = optarg; 482 warning = optarg;
466 warning_time = strtod (warning, NULL); 483 result.config.warning_time = strtod(warning, NULL);
467 break; 484 break;
468 case 'c': 485 case 'c':
469 critical = optarg; 486 critical = optarg;
470 critical_time = strtod (critical, NULL); 487 result.config.critical_time = strtod(critical, NULL);
471 break; 488 break;
472 case 'V': /* version */ 489 case 'V': /* version */
473 print_revision (progname, NP_VERSION); 490 print_revision(progname, NP_VERSION);
474 exit (STATE_UNKNOWN); 491 exit(STATE_UNKNOWN);
475 case 'h': /* help */ 492 case 'h': /* help */
476 print_help (); 493 print_help();
477 exit (STATE_UNKNOWN); 494 exit(STATE_UNKNOWN);
478 case 'v': 495 case 'v':
479 verbose++; 496 verbose++;
480 break; 497 break;
481 case '?': /* help */ 498 case '?': /* help */
482 usage5 (); 499 usage5();
483 } 500 }
484 } 501 }
485 502
486 c = optind; 503 int index = optind;
487
488 set_thresholds(&my_threshold, warning, critical);
489 504
490 while ( argc > c ) { 505 set_thresholds(&result.config.my_threshold, warning, critical);
491 506
492 if (db_host == NULL) 507 while (argc > index) {
493 if (is_host (argv[c])) { 508 if (result.config.db_host == NULL) {
494 db_host = argv[c++]; 509 if (is_host(argv[index])) {
510 result.config.db_host = argv[index++];
511 } else {
512 usage2(_("Invalid hostname/address"), argv[index]);
495 } 513 }
496 else { 514 } else if (result.config.db_user == NULL) {
497 usage2 (_("Invalid hostname/address"), argv[c]); 515 result.config.db_user = argv[index++];
498 } 516 } else if (result.config.db_pass == NULL) {
499 else if (db_user == NULL) 517 result.config.db_pass = argv[index++];
500 db_user = argv[c++]; 518 } else if (result.config.db == NULL) {
501 else if (db_pass == NULL) 519 result.config.db = argv[index++];
502 db_pass = argv[c++]; 520 } else if (is_intnonneg(argv[index])) {
503 else if (db == NULL) 521 result.config.db_port = atoi(argv[index++]);
504 db = argv[c++]; 522 } else {
505 else if (is_intnonneg (argv[c]))
506 db_port = atoi (argv[c++]);
507 else
508 break; 523 break;
524 }
509 } 525 }
510 526
511 return validate_arguments (); 527 return validate_arguments(result);
512} 528}
513 529
530check_mysql_config_wrapper validate_arguments(check_mysql_config_wrapper config_wrapper) {
531 if (config_wrapper.config.db_user == NULL) {
532 config_wrapper.config.db_user = strdup("");
533 }
514 534
515int 535 if (config_wrapper.config.db_host == NULL) {
516validate_arguments (void) 536 config_wrapper.config.db_host = strdup("");
517{ 537 }
518 if (db_user == NULL)
519 db_user = strdup("");
520
521 if (db_host == NULL)
522 db_host = strdup("");
523 538
524 if (db == NULL) 539 if (config_wrapper.config.db == NULL) {
525 db = strdup(""); 540 config_wrapper.config.db = strdup("");
541 }
526 542
527 return OK; 543 return config_wrapper;
528} 544}
529 545
530 546void print_help(void) {
531void
532print_help (void)
533{
534 char *myport; 547 char *myport;
535 xasprintf (&myport, "%d", MYSQL_PORT); 548 xasprintf(&myport, "%d", MYSQL_PORT);
536 549
537 print_revision (progname, NP_VERSION); 550 print_revision(progname, NP_VERSION);
538 551
539 printf (_(COPYRIGHT), copyright, email); 552 printf(_(COPYRIGHT), copyright, email);
540 553
541 printf ("%s\n", _("This program tests connections to a MySQL server")); 554 printf("%s\n", _("This program tests connections to a MySQL server"));
542 555
543 printf ("\n\n"); 556 printf("\n\n");
544 557
545 print_usage (); 558 print_usage();
546 559
547 printf (UT_HELP_VRSN); 560 printf(UT_HELP_VRSN);
548 printf (UT_EXTRA_OPTS); 561 printf(UT_EXTRA_OPTS);
549 562
550 printf (UT_HOST_PORT, 'P', myport); 563 printf(UT_HOST_PORT, 'P', myport);
551 printf (" %s\n", "-n, --ignore-auth"); 564 printf(" %s\n", "-n, --ignore-auth");
552 printf (" %s\n", _("Ignore authentication failure and check for mysql connectivity only")); 565 printf(" %s\n", _("Ignore authentication failure and check for mysql connectivity only"));
553 566
554 printf (" %s\n", "-s, --socket=STRING"); 567 printf(" %s\n", "-s, --socket=STRING");
555 printf (" %s\n", _("Use the specified socket (has no effect if -H is used)")); 568 printf(" %s\n", _("Use the specified socket (has no effect if -H is used)"));
556 569
557 printf (" %s\n", "-d, --database=STRING"); 570 printf(" %s\n", "-d, --database=STRING");
558 printf (" %s\n", _("Check database with indicated name")); 571 printf(" %s\n", _("Check database with indicated name"));
559 printf (" %s\n", "-f, --file=STRING"); 572 printf(" %s\n", "-f, --file=STRING");
560 printf (" %s\n", _("Read from the specified client options file")); 573 printf(" %s\n", _("Read from the specified client options file"));
561 printf (" %s\n", "-g, --group=STRING"); 574 printf(" %s\n", "-g, --group=STRING");
562 printf (" %s\n", _("Use a client options group")); 575 printf(" %s\n", _("Use a client options group"));
563 printf (" %s\n", "-u, --username=STRING"); 576 printf(" %s\n", "-u, --username=STRING");
564 printf (" %s\n", _("Connect using the indicated username")); 577 printf(" %s\n", _("Connect using the indicated username"));
565 printf (" %s\n", "-p, --password=STRING"); 578 printf(" %s\n", "-p, --password=STRING");
566 printf (" %s\n", _("Use the indicated password to authenticate the connection")); 579 printf(" %s\n", _("Use the indicated password to authenticate the connection"));
567 printf (" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!")); 580 printf(" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!"));
568 printf (" %s\n", _("Your clear-text password could be visible as a process table entry")); 581 printf(" %s\n", _("Your clear-text password could be visible as a process table entry"));
569 printf (" %s\n", "-S, --check-slave"); 582 printf(" %s\n", "-S, --check-slave");
570 printf (" %s\n", _("Check if the slave thread is running properly.")); 583 printf(" %s\n",
571 printf (" %s\n", "-w, --warning"); 584 _("Check if the slave thread is running properly. This option is deprecated in favour of check-replica, which does the same"));
572 printf (" %s\n", _("Exit with WARNING status if slave server is more than INTEGER seconds")); 585 printf(" %s\n", "--check-replica");
573 printf (" %s\n", _("behind master")); 586 printf(" %s\n", _("Check if the replica thread is running properly."));
574 printf (" %s\n", "-c, --critical"); 587 printf(" %s\n", "-w, --warning");
575 printf (" %s\n", _("Exit with CRITICAL status if slave server is more then INTEGER seconds")); 588 printf(" %s\n", _("Exit with WARNING status if replica server is more than INTEGER seconds"));
576 printf (" %s\n", _("behind master")); 589 printf(" %s\n", _("behind master"));
577 printf (" %s\n", "-l, --ssl"); 590 printf(" %s\n", "-c, --critical");
578 printf (" %s\n", _("Use ssl encryption")); 591 printf(" %s\n", _("Exit with CRITICAL status if replica server is more then INTEGER seconds"));
579 printf (" %s\n", "-C, --ca-cert=STRING"); 592 printf(" %s\n", _("behind master"));
580 printf (" %s\n", _("Path to CA signing the cert")); 593 printf(" %s\n", "-l, --ssl");
581 printf (" %s\n", "-a, --cert=STRING"); 594 printf(" %s\n", _("Use ssl encryption"));
582 printf (" %s\n", _("Path to SSL certificate")); 595 printf(" %s\n", "-C, --ca-cert=STRING");
583 printf (" %s\n", "-k, --key=STRING"); 596 printf(" %s\n", _("Path to CA signing the cert"));
584 printf (" %s\n", _("Path to private SSL key")); 597 printf(" %s\n", "-a, --cert=STRING");
585 printf (" %s\n", "-D, --ca-dir=STRING"); 598 printf(" %s\n", _("Path to SSL certificate"));
586 printf (" %s\n", _("Path to CA directory")); 599 printf(" %s\n", "-k, --key=STRING");
587 printf (" %s\n", "-L, --ciphers=STRING"); 600 printf(" %s\n", _("Path to private SSL key"));
588 printf (" %s\n", _("List of valid SSL ciphers")); 601 printf(" %s\n", "-D, --ca-dir=STRING");
589 602 printf(" %s\n", _("Path to CA directory"));
590 603 printf(" %s\n", "-L, --ciphers=STRING");
591 printf ("\n"); 604 printf(" %s\n", _("List of valid SSL ciphers"));
592 printf (" %s\n", _("There are no required arguments. By default, the local database is checked")); 605
593 printf (" %s\n", _("using the default unix socket. You can force TCP on localhost by using an")); 606 printf("\n");
594 printf (" %s\n", _("IP address or FQDN ('localhost' will use the socket as well).")); 607 printf(" %s\n", _("There are no required arguments. By default, the local database is checked"));
595 608 printf(" %s\n", _("using the default unix socket. You can force TCP on localhost by using an"));
596 printf ("\n"); 609 printf(" %s\n", _("IP address or FQDN ('localhost' will use the socket as well)."));
597 printf ("%s\n", _("Notes:")); 610
598 printf (" %s\n", _("You must specify -p with an empty string to force an empty password,")); 611 printf("\n");
599 printf (" %s\n", _("overriding any my.cnf settings.")); 612 printf("%s\n", _("Notes:"));
600 613 printf(" %s\n", _("You must specify -p with an empty string to force an empty password,"));
601 printf (UT_SUPPORT); 614 printf(" %s\n", _("overriding any my.cnf settings."));
615
616 printf(UT_SUPPORT);
602} 617}
603 618
604 619void print_usage(void) {
605void 620 printf("%s\n", _("Usage:"));
606print_usage (void) 621 printf(" %s [-d database] [-H host] [-P port] [-s socket]\n", progname);
607{ 622 printf(" [-u user] [-p password] [-S] [-l] [-a cert] [-k key]\n");
608 printf ("%s\n", _("Usage:")); 623 printf(" [-C ca-cert] [-D ca-dir] [-L ciphers] [-f optfile] [-g group]\n");
609 printf (" %s [-d database] [-H host] [-P port] [-s socket]\n",progname);
610 printf (" [-u user] [-p password] [-S] [-l] [-a cert] [-k key]\n");
611 printf (" [-C ca-cert] [-D ca-dir] [-L ciphers] [-f optfile] [-g group]\n");
612} 624}
diff --git a/plugins/check_mysql.d/config.h b/plugins/check_mysql.d/config.h
new file mode 100644
index 00000000..71ddbe8d
--- /dev/null
+++ b/plugins/check_mysql.d/config.h
@@ -0,0 +1,58 @@
1#pragma once
2
3#include "../../config.h"
4#include "thresholds.h"
5#include <stddef.h>
6#include <mysql.h>
7
8typedef struct {
9 char *db_host;
10 unsigned int db_port;
11 char *db_user;
12 char *db_socket;
13 char *db_pass;
14 char *db;
15 char *ca_cert;
16 char *ca_dir;
17 char *cert;
18 char *key;
19 char *ciphers;
20 bool ssl;
21 char *opt_file;
22 char *opt_group;
23
24 bool check_replica;
25 bool ignore_auth;
26
27 double warning_time;
28 double critical_time;
29 thresholds *my_threshold;
30
31} check_mysql_config;
32
33check_mysql_config check_mysql_config_init() {
34 check_mysql_config tmp = {
35 .db_host = NULL,
36 .db_port = MYSQL_PORT,
37 .db = NULL,
38 .db_pass = NULL,
39 .db_socket = NULL,
40 .db_user = NULL,
41 .ca_cert = NULL,
42 .ca_dir = NULL,
43 .cert = NULL,
44 .key = NULL,
45 .ciphers = NULL,
46 .ssl = false,
47 .opt_file = NULL,
48 .opt_group = NULL,
49
50 .check_replica = false,
51 .ignore_auth = false,
52
53 .warning_time = 0,
54 .critical_time = 0,
55 .my_threshold = NULL,
56 };
57 return tmp;
58}
diff --git a/plugins/check_mysql_query.c b/plugins/check_mysql_query.c
index 842b7a2f..5e04a94b 100644
--- a/plugins/check_mysql_query.c
+++ b/plugins/check_mysql_query.c
@@ -1,157 +1,151 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_mysql_query plugin 3 * Monitoring check_mysql_query plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2006-2009 Monitoring Plugins Development Team 6 * Copyright (c) 2006-2024 Monitoring Plugins Development Team
7* Original code from check_mysql, copyright 1999 Didi Rieder 7 * Original code from check_mysql, copyright 1999 Didi Rieder
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains the check_mysql_query plugin 11 * This file contains the check_mysql_query plugin
12* 12 *
13* This plugin is for running arbitrary SQL and checking the results 13 * This plugin is for running arbitrary SQL and checking the results
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 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 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 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 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/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_mysql_query"; 32const char *progname = "check_mysql_query";
33const char *copyright = "1999-2007"; 33const char *copyright = "1999-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "common.h" 36#include "common.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"
40#include "check_mysql_query.d/config.h"
40 41
41#include <mysql.h> 42#include <mysql.h>
42#include <errmsg.h> 43#include <errmsg.h>
43 44
44char *db_user = NULL; 45typedef struct {
45char *db_host = NULL; 46 int errorcode;
46char *db_socket = NULL; 47 check_mysql_query_config config;
47char *db_pass = NULL; 48} check_mysql_query_config_wrapper;
48char *db = NULL; 49static check_mysql_query_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
49char *opt_file = NULL; 50static check_mysql_query_config_wrapper validate_arguments(check_mysql_query_config_wrapper /*config_wrapper*/);
50char *opt_group = NULL; 51static void print_help(void);
51unsigned int db_port = MYSQL_PORT; 52void print_usage(void);
52 53
53int process_arguments (int, char **); 54static int verbose = 0;
54int validate_arguments (void);
55void print_help (void);
56void print_usage (void);
57 55
58char *sql_query = NULL; 56int main(int argc, char **argv) {
59int verbose = 0; 57 setlocale(LC_ALL, "");
60thresholds *my_thresholds = NULL; 58 bindtextdomain(PACKAGE, LOCALEDIR);
61 59 textdomain(PACKAGE);
62
63int
64main (int argc, char **argv)
65{
66
67 MYSQL mysql;
68 MYSQL_RES *res;
69 MYSQL_ROW row;
70
71 double value;
72 char *error = NULL;
73 int status;
74
75 setlocale (LC_ALL, "");
76 bindtextdomain (PACKAGE, LOCALEDIR);
77 textdomain (PACKAGE);
78 60
79 /* Parse extra opts if any */ 61 /* Parse extra opts if any */
80 argv=np_extra_opts (&argc, argv, progname); 62 argv = np_extra_opts(&argc, argv, progname);
81 63
82 if (process_arguments (argc, argv) == ERROR) 64 check_mysql_query_config_wrapper tmp_config = process_arguments(argc, argv);
83 usage4 (_("Could not parse arguments")); 65 if (tmp_config.errorcode == ERROR) {
66 usage4(_("Could not parse arguments"));
67 }
84 68
69 const check_mysql_query_config config = tmp_config.config;
70
71 MYSQL mysql;
85 /* initialize mysql */ 72 /* initialize mysql */
86 mysql_init (&mysql); 73 mysql_init(&mysql);
87 74
88 if (opt_file != NULL) 75 if (config.opt_file != NULL) {
89 mysql_options(&mysql,MYSQL_READ_DEFAULT_FILE,opt_file); 76 mysql_options(&mysql, MYSQL_READ_DEFAULT_FILE, config.opt_file);
77 }
90 78
91 if (opt_group != NULL) 79 if (config.opt_group != NULL) {
92 mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,opt_group); 80 mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, config.opt_group);
93 else 81 } else {
94 mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,"client"); 82 mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "client");
83 }
95 84
96 /* establish a connection to the server and error checking */ 85 /* establish a connection to the server and error checking */
97 if (!mysql_real_connect(&mysql,db_host,db_user,db_pass,db,db_port,db_socket,0)) { 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_errno (&mysql) == CR_UNKNOWN_HOST) 87 if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) {
99 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql)); 88 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
100 else if (mysql_errno (&mysql) == CR_VERSION_ERROR) 89 } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) {
101 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql)); 90 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
102 else if (mysql_errno (&mysql) == CR_OUT_OF_MEMORY) 91 } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) {
103 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql)); 92 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
104 else if (mysql_errno (&mysql) == CR_IPSOCK_ERROR) 93 } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) {
105 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql)); 94 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
106 else if (mysql_errno (&mysql) == CR_SOCKET_CREATE_ERROR) 95 } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) {
107 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql)); 96 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
108 else 97 } else {
109 die (STATE_CRITICAL, "QUERY %s: %s\n", _("CRITICAL"), mysql_error (&mysql)); 98 die(STATE_CRITICAL, "QUERY %s: %s\n", _("CRITICAL"), mysql_error(&mysql));
99 }
110 } 100 }
111 101
112 if (mysql_query (&mysql, sql_query) != 0) { 102 char *error = NULL;
103 if (mysql_query(&mysql, config.sql_query) != 0) {
113 error = strdup(mysql_error(&mysql)); 104 error = strdup(mysql_error(&mysql));
114 mysql_close (&mysql); 105 mysql_close(&mysql);
115 die (STATE_CRITICAL, "QUERY %s: %s - %s\n", _("CRITICAL"), _("Error with query"), error); 106 die(STATE_CRITICAL, "QUERY %s: %s - %s\n", _("CRITICAL"), _("Error with query"), error);
116 } 107 }
117 108
109 MYSQL_RES *res;
118 /* store the result */ 110 /* store the result */
119 if ( (res = mysql_store_result (&mysql)) == NULL) { 111 if ((res = mysql_store_result(&mysql)) == NULL) {
120 error = strdup(mysql_error(&mysql)); 112 error = strdup(mysql_error(&mysql));
121 mysql_close (&mysql); 113 mysql_close(&mysql);
122 die (STATE_CRITICAL, "QUERY %s: Error with store_result - %s\n", _("CRITICAL"), error); 114 die(STATE_CRITICAL, "QUERY %s: Error with store_result - %s\n", _("CRITICAL"), error);
123 } 115 }
124 116
125 /* Check there is some data */ 117 /* Check there is some data */
126 if (mysql_num_rows(res) == 0) { 118 if (mysql_num_rows(res) == 0) {
127 mysql_close(&mysql); 119 mysql_close(&mysql);
128 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), _("No rows returned")); 120 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), _("No rows returned"));
129 } 121 }
130 122
123 MYSQL_ROW row;
131 /* fetch the first row */ 124 /* fetch the first row */
132 if ( (row = mysql_fetch_row (res)) == NULL) { 125 if ((row = mysql_fetch_row(res)) == NULL) {
133 error = strdup(mysql_error(&mysql)); 126 error = strdup(mysql_error(&mysql));
134 mysql_free_result (res); 127 mysql_free_result(res);
135 mysql_close (&mysql); 128 mysql_close(&mysql);
136 die (STATE_CRITICAL, "QUERY %s: Fetch row error - %s\n", _("CRITICAL"), error); 129 die(STATE_CRITICAL, "QUERY %s: Fetch row error - %s\n", _("CRITICAL"), error);
137 } 130 }
138 131
139 if (! is_numeric(row[0])) { 132 if (!is_numeric(row[0])) {
140 die (STATE_CRITICAL, "QUERY %s: %s - '%s'\n", _("CRITICAL"), _("Is not a numeric"), row[0]); 133 die(STATE_CRITICAL, "QUERY %s: %s - '%s'\n", _("CRITICAL"), _("Is not a numeric"), row[0]);
141 } 134 }
142 135
143 value = strtod(row[0], NULL); 136 double value = strtod(row[0], NULL);
144 137
145 /* free the result */ 138 /* free the result */
146 mysql_free_result (res); 139 mysql_free_result(res);
147 140
148 /* close the connection */ 141 /* close the connection */
149 mysql_close (&mysql); 142 mysql_close(&mysql);
150 143
151 if (verbose >= 3) 144 if (verbose >= 3) {
152 printf("mysql result: %f\n", value); 145 printf("mysql result: %f\n", value);
146 }
153 147
154 status = get_status(value, my_thresholds); 148 int status = get_status(value, config.my_thresholds);
155 149
156 if (status == STATE_OK) { 150 if (status == STATE_OK) {
157 printf("QUERY %s: ", _("OK")); 151 printf("QUERY %s: ", _("OK"));
@@ -160,75 +154,63 @@ main (int argc, char **argv)
160 } else if (status == STATE_CRITICAL) { 154 } else if (status == STATE_CRITICAL) {
161 printf("QUERY %s: ", _("CRITICAL")); 155 printf("QUERY %s: ", _("CRITICAL"));
162 } 156 }
163 printf(_("'%s' returned %f | %s"), sql_query, value, 157 printf(_("'%s' returned %f | %s"), config.sql_query, value,
164 fperfdata("result", value, "", 158 fperfdata("result", value, "", config.my_thresholds->warning, config.my_thresholds->warning ? config.my_thresholds->warning->end : 0,
165 my_thresholds->warning?true:false, my_thresholds->warning?my_thresholds->warning->end:0, 159 config.my_thresholds->critical, config.my_thresholds->critical ? config.my_thresholds->critical->end : 0, false, 0, false, 0));
166 my_thresholds->critical?true:false, my_thresholds->critical?my_thresholds->critical->end:0,
167 false, 0,
168 false, 0)
169 );
170 printf("\n"); 160 printf("\n");
171 161
172 return status; 162 return status;
173} 163}
174 164
175
176/* process command-line arguments */ 165/* process command-line arguments */
177int 166check_mysql_query_config_wrapper process_arguments(int argc, char **argv) {
178process_arguments (int argc, char **argv)
179{
180 int c;
181 char *warning = NULL;
182 char *critical = NULL;
183
184 int option = 0;
185 static struct option longopts[] = { 167 static struct option longopts[] = {
186 {"hostname", required_argument, 0, 'H'}, 168 {"hostname", required_argument, 0, 'H'}, {"socket", required_argument, 0, 's'}, {"database", required_argument, 0, 'd'},
187 {"socket", required_argument, 0, 's'}, 169 {"username", required_argument, 0, 'u'}, {"password", required_argument, 0, 'p'}, {"file", required_argument, 0, 'f'},
188 {"database", required_argument, 0, 'd'}, 170 {"group", required_argument, 0, 'g'}, {"port", required_argument, 0, 'P'}, {"verbose", no_argument, 0, 'v'},
189 {"username", required_argument, 0, 'u'}, 171 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"query", required_argument, 0, 'q'},
190 {"password", required_argument, 0, 'p'}, 172 {"warning", required_argument, 0, 'w'}, {"critical", required_argument, 0, 'c'}, {0, 0, 0, 0}};
191 {"file", required_argument, 0, 'f'}, 173
192 {"group", required_argument, 0, 'g'}, 174 check_mysql_query_config_wrapper result = {
193 {"port", required_argument, 0, 'P'}, 175 .errorcode = OK,
194 {"verbose", no_argument, 0, 'v'}, 176 .config = check_mysql_query_config_init(),
195 {"version", no_argument, 0, 'V'},
196 {"help", no_argument, 0, 'h'},
197 {"query", required_argument, 0, 'q'},
198 {"warning", required_argument, 0, 'w'},
199 {"critical", required_argument, 0, 'c'},
200 {0, 0, 0, 0}
201 }; 177 };
202 178
203 if (argc < 1) 179 if (argc < 1) {
204 return ERROR; 180 result.errorcode = ERROR;
181 return result;
182 }
205 183
206 while (1) { 184 char *warning = NULL;
207 c = getopt_long (argc, argv, "hvVP:p:u:d:H:s:q:w:c:f:g:", longopts, &option); 185 char *critical = NULL;
208 186
209 if (c == -1 || c == EOF) 187 while (true) {
188 int option = 0;
189 int option_char = getopt_long(argc, argv, "hvVP:p:u:d:H:s:q:w:c:f:g:", longopts, &option);
190
191 if (option_char == -1 || option_char == EOF) {
210 break; 192 break;
193 }
211 194
212 switch (c) { 195 switch (option_char) {
213 case 'H': /* hostname */ 196 case 'H': /* hostname */
214 if (is_host (optarg)) { 197 if (is_host(optarg)) {
215 db_host = optarg; 198 result.config.db_host = optarg;
216 } 199 } else {
217 else { 200 usage2(_("Invalid hostname/address"), optarg);
218 usage2 (_("Invalid hostname/address"), optarg);
219 } 201 }
220 break; 202 break;
221 case 's': /* socket */ 203 case 's': /* socket */
222 db_socket = optarg; 204 result.config.db_socket = optarg;
223 break; 205 break;
224 case 'd': /* database */ 206 case 'd': /* database */
225 db = optarg; 207 result.config.db = optarg;
226 break; 208 break;
227 case 'u': /* username */ 209 case 'u': /* username */
228 db_user = optarg; 210 result.config.db_user = optarg;
229 break; 211 break;
230 case 'p': /* authentication information: password */ 212 case 'p': /* authentication information: password */
231 db_pass = strdup(optarg); 213 result.config.db_pass = strdup(optarg);
232 214
233 /* Delete the password from process list */ 215 /* Delete the password from process list */
234 while (*optarg != '\0') { 216 while (*optarg != '\0') {
@@ -236,26 +218,26 @@ process_arguments (int argc, char **argv)
236 optarg++; 218 optarg++;
237 } 219 }
238 break; 220 break;
239 case 'f': /* client options file */ 221 case 'f': /* client options file */
240 opt_file = optarg; 222 result.config.opt_file = optarg;
241 break; 223 break;
242 case 'g': /* client options group */ 224 case 'g': /* client options group */
243 opt_group = optarg; 225 result.config.opt_group = optarg;
244 break; 226 break;
245 case 'P': /* critical time threshold */ 227 case 'P': /* critical time threshold */
246 db_port = atoi (optarg); 228 result.config.db_port = atoi(optarg);
247 break; 229 break;
248 case 'v': 230 case 'v':
249 verbose++; 231 verbose++;
250 break; 232 break;
251 case 'V': /* version */ 233 case 'V': /* version */
252 print_revision (progname, NP_VERSION); 234 print_revision(progname, NP_VERSION);
253 exit (STATE_UNKNOWN); 235 exit(STATE_UNKNOWN);
254 case 'h': /* help */ 236 case 'h': /* help */
255 print_help (); 237 print_help();
256 exit (STATE_UNKNOWN); 238 exit(STATE_UNKNOWN);
257 case 'q': 239 case 'q':
258 xasprintf(&sql_query, "%s", optarg); 240 xasprintf(&result.config.sql_query, "%s", optarg);
259 break; 241 break;
260 case 'w': 242 case 'w':
261 warning = optarg; 243 warning = optarg;
@@ -263,92 +245,85 @@ process_arguments (int argc, char **argv)
263 case 'c': 245 case 'c':
264 critical = optarg; 246 critical = optarg;
265 break; 247 break;
266 case '?': /* help */ 248 case '?': /* help */
267 usage5 (); 249 usage5();
268 } 250 }
269 } 251 }
270 252
271 c = optind; 253 set_thresholds(&result.config.my_thresholds, warning, critical);
272 254
273 set_thresholds(&my_thresholds, warning, critical); 255 return validate_arguments(result);
274
275 return validate_arguments ();
276} 256}
277 257
278 258check_mysql_query_config_wrapper validate_arguments(check_mysql_query_config_wrapper config_wrapper) {
279int 259 if (config_wrapper.config.sql_query == NULL) {
280validate_arguments (void)
281{
282 if (sql_query == NULL)
283 usage("Must specify a SQL query to run"); 260 usage("Must specify a SQL query to run");
261 }
284 262
285 if (db_user == NULL) 263 if (config_wrapper.config.db_user == NULL) {
286 db_user = strdup(""); 264 config_wrapper.config.db_user = strdup("");
265 }
287 266
288 if (db_host == NULL) 267 if (config_wrapper.config.db_host == NULL) {
289 db_host = strdup(""); 268 config_wrapper.config.db_host = strdup("");
269 }
290 270
291 if (db == NULL) 271 if (config_wrapper.config.db == NULL) {
292 db = strdup(""); 272 config_wrapper.config.db = strdup("");
273 }
293 274
294 return OK; 275 return config_wrapper;
295} 276}
296 277
297 278void print_help(void) {
298void
299print_help (void)
300{
301 char *myport; 279 char *myport;
302 xasprintf (&myport, "%d", MYSQL_PORT); 280 xasprintf(&myport, "%d", MYSQL_PORT);
303 281
304 print_revision (progname, NP_VERSION); 282 print_revision(progname, NP_VERSION);
305 283
306 printf (_(COPYRIGHT), copyright, email); 284 printf(_(COPYRIGHT), copyright, email);
307 285
308 printf ("%s\n", _("This program checks a query result against threshold levels")); 286 printf("%s\n", _("This program checks a query result against threshold levels"));
309 287
310 printf ("\n\n"); 288 printf("\n\n");
311 289
312 print_usage (); 290 print_usage();
313 291
314 printf (UT_HELP_VRSN); 292 printf(UT_HELP_VRSN);
315 printf (UT_EXTRA_OPTS); 293 printf(UT_EXTRA_OPTS);
316 printf (" -q, --query=STRING\n"); 294 printf(" -q, --query=STRING\n");
317 printf (" %s\n", _("SQL query to run. Only first column in first row will be read")); 295 printf(" %s\n", _("SQL query to run. Only first column in first row will be read"));
318 printf (UT_WARN_CRIT_RANGE); 296 printf(UT_WARN_CRIT_RANGE);
319 printf (UT_HOST_PORT, 'P', myport); 297 printf(UT_HOST_PORT, 'P', myport);
320 printf (" %s\n", "-s, --socket=STRING"); 298 printf(" %s\n", "-s, --socket=STRING");
321 printf (" %s\n", _("Use the specified socket (has no effect if -H is used)")); 299 printf(" %s\n", _("Use the specified socket (has no effect if -H is used)"));
322 printf (" -d, --database=STRING\n"); 300 printf(" -d, --database=STRING\n");
323 printf (" %s\n", _("Database to check")); 301 printf(" %s\n", _("Database to check"));
324 printf (" %s\n", "-f, --file=STRING"); 302 printf(" %s\n", "-f, --file=STRING");
325 printf (" %s\n", _("Read from the specified client options file")); 303 printf(" %s\n", _("Read from the specified client options file"));
326 printf (" %s\n", "-g, --group=STRING"); 304 printf(" %s\n", "-g, --group=STRING");
327 printf (" %s\n", _("Use a client options group")); 305 printf(" %s\n", _("Use a client options group"));
328 printf (" -u, --username=STRING\n"); 306 printf(" -u, --username=STRING\n");
329 printf (" %s\n", _("Username to login with")); 307 printf(" %s\n", _("Username to login with"));
330 printf (" -p, --password=STRING\n"); 308 printf(" -p, --password=STRING\n");
331 printf (" %s\n", _("Password to login with")); 309 printf(" %s\n", _("Password to login with"));
332 printf (" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!")); 310 printf(" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!"));
333 printf (" %s\n", _("Your clear-text password could be visible as a process table entry")); 311 printf(" %s\n", _("Your clear-text password could be visible as a process table entry"));
334
335 printf ("\n");
336 printf (" %s\n", _("A query is required. The result from the query should be numeric."));
337 printf (" %s\n", _("For extra security, create a user with minimal access."));
338
339 printf ("\n");
340 printf ("%s\n", _("Notes:"));
341 printf (" %s\n", _("You must specify -p with an empty string to force an empty password,"));
342 printf (" %s\n", _("overriding any my.cnf settings."));
343
344 printf (UT_SUPPORT);
345}
346 312
313 printf("\n");
314 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."));
316
317 printf("\n");
318 printf("%s\n", _("Notes:"));
319 printf(" %s\n", _("You must specify -p with an empty string to force an empty password,"));
320 printf(" %s\n", _("overriding any my.cnf settings."));
321
322 printf(UT_SUPPORT);
323}
347 324
348void 325void print_usage(void) {
349print_usage (void) 326 printf("%s\n", _("Usage:"));
350{ 327 printf(" %s -q SQL_query [-w warn] [-c crit] [-H host] [-P port] [-s socket]\n", progname);
351 printf ("%s\n", _("Usage:")); 328 printf(" [-d database] [-u user] [-p password] [-f optfile] [-g group]\n");
352 printf (" %s -q SQL_query [-w warn] [-c crit] [-H host] [-P port] [-s socket]\n",progname);
353 printf (" [-d database] [-u user] [-p password] [-f optfile] [-g group]\n");
354} 329}
diff --git a/plugins/check_mysql_query.d/config.h b/plugins/check_mysql_query.d/config.h
new file mode 100644
index 00000000..be019160
--- /dev/null
+++ b/plugins/check_mysql_query.d/config.h
@@ -0,0 +1,36 @@
1#pragma once
2
3#include "../../config.h"
4#include "thresholds.h"
5#include <mysql.h>
6
7typedef struct {
8 char *db_host;
9 char *db_socket;
10 char *db;
11 char *db_user;
12 char *db_pass;
13 char *opt_file;
14 char *opt_group;
15 unsigned int db_port;
16
17 char *sql_query;
18 thresholds *my_thresholds;
19} check_mysql_query_config;
20
21check_mysql_query_config check_mysql_query_config_init() {
22 check_mysql_query_config tmp = {
23 .db_host = NULL,
24 .db_socket = NULL,
25 .db = NULL,
26 .db_user = NULL,
27 .db_pass = NULL,
28 .opt_file = NULL,
29 .opt_group = NULL,
30 .db_port = MYSQL_PORT,
31
32 .sql_query = NULL,
33 .my_thresholds = NULL,
34 };
35 return tmp;
36}
diff --git a/plugins/check_nagios.c b/plugins/check_nagios.c
index 40d68f03..a46dc1ed 100644
--- a/plugins/check_nagios.c
+++ b/plugins/check_nagios.c
@@ -1,325 +1,317 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_nagios plugin 3 * Monitoring check_nagios plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2007 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_nagios plugin 10 * This file contains the check_nagios plugin
11* 11 *
12* This plugin checks the status of the Nagios process on the local machine. 12 * This plugin checks the status of the Nagios process on the local machine.
13* The plugin will check to make sure the Nagios status log is no older than 13 * The plugin will check to make sure the Nagios status log is no older than
14* the number of minutes specified by the expires option. 14 * the number of minutes specified by the expires option.
15* It also checks the process table for a process matching the command 15 * It also checks the process table for a process matching the command
16* argument. 16 * argument.
17* 17 *
18* 18 *
19* This program is free software: you can redistribute it and/or modify 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 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 21 * the Free Software Foundation, either version 3 of the License, or
22* (at your option) any later version. 22 * (at your option) any later version.
23* 23 *
24* This program is distributed in the hope that it will be useful, 24 * This program is distributed in the hope that it will be useful,
25* but WITHOUT ANY WARRANTY; without even the implied warranty of 25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27* GNU General Public License for more details. 27 * GNU General Public License for more details.
28* 28 *
29* You should have received a copy of the GNU General Public License 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/>. 30 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31* 31 *
32* 32 *
33*****************************************************************************/ 33 *****************************************************************************/
34 34
35const char *progname = "check_nagios"; 35const char *progname = "check_nagios";
36const char *copyright = "1999-2007"; 36const char *copyright = "1999-2024";
37const char *email = "devel@monitoring-plugins.org"; 37const char *email = "devel@monitoring-plugins.org";
38 38
39#include "common.h" 39#include "common.h"
40#include "runcmd.h" 40#include "runcmd.h"
41#include "utils.h" 41#include "utils.h"
42#include "states.h"
43#include "check_nagios.d/config.h"
42 44
43int process_arguments (int, char **); 45typedef struct {
44void print_help (void); 46 int errorcode;
45void print_usage (void); 47 check_nagios_config config;
48} check_nagios_config_wrapper;
49static check_nagios_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
50static void print_help(void);
51void print_usage(void);
46 52
47char *status_log = NULL; 53static int verbose = 0;
48char *process_string = NULL;
49int expire_minutes = 0;
50 54
51int verbose = 0; 55int main(int argc, char **argv) {
52 56 setlocale(LC_ALL, "");
53int 57 bindtextdomain(PACKAGE, LOCALEDIR);
54main (int argc, char **argv) 58 textdomain(PACKAGE);
55{
56 int result = STATE_UNKNOWN;
57 char input_buffer[MAX_INPUT_BUFFER];
58 unsigned long latest_entry_time = 0L;
59 unsigned long temp_entry_time = 0L;
60 int proc_entries = 0;
61 time_t current_time;
62 char *temp_ptr;
63 FILE *fp;
64 int procuid = 0;
65 int procpid = 0;
66 int procppid = 0;
67 int procvsz = 0;
68 int procrss = 0;
69 float procpcpu = 0;
70 char procstat[8];
71#ifdef PS_USES_PROCETIME
72 char procetime[MAX_INPUT_BUFFER];
73#endif /* PS_USES_PROCETIME */
74 char procprog[MAX_INPUT_BUFFER];
75 char *procargs;
76 int pos, cols;
77 int expected_cols = PS_COLS - 1;
78 const char *zombie = "Z";
79 char *temp_string;
80 output chld_out, chld_err;
81 size_t i;
82
83 setlocale (LC_ALL, "");
84 bindtextdomain (PACKAGE, LOCALEDIR);
85 textdomain (PACKAGE);
86 59
87 /* Parse extra opts if any */ 60 /* Parse extra opts if any */
88 argv=np_extra_opts (&argc, argv, progname); 61 argv = np_extra_opts(&argc, argv, progname);
62
63 check_nagios_config_wrapper tmp_config = process_arguments(argc, argv);
89 64
90 if (process_arguments (argc, argv) == ERROR) 65 if (tmp_config.errorcode == ERROR) {
91 usage_va(_("Could not parse arguments")); 66 usage_va(_("Could not parse arguments"));
67 }
68
69 const check_nagios_config config = tmp_config.config;
92 70
93 /* Set signal handling and alarm timeout */ 71 /* Set signal handling and alarm timeout */
94 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 72 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
95 usage_va(_("Cannot catch SIGALRM")); 73 usage_va(_("Cannot catch SIGALRM"));
96 } 74 }
97 75
98 /* handle timeouts gracefully... */ 76 /* handle timeouts gracefully... */
99 alarm (timeout_interval); 77 alarm(timeout_interval);
100 78
101 /* open the status log */ 79 /* open the status log */
102 fp = fopen (status_log, "r"); 80 FILE *log_file = fopen(config.status_log, "r");
103 if (fp == NULL) { 81 if (log_file == NULL) {
104 die (STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Cannot open status log for reading!")); 82 die(STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Cannot open status log for reading!"));
105 } 83 }
106 84
85 unsigned long latest_entry_time = 0L;
86 unsigned long temp_entry_time = 0L;
87 char input_buffer[MAX_INPUT_BUFFER];
88 char *temp_ptr;
107 /* get the date/time of the last item updated in the log */ 89 /* get the date/time of the last item updated in the log */
108 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) { 90 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, log_file)) {
109 if ((temp_ptr = strstr (input_buffer, "created=")) != NULL) { 91 if ((temp_ptr = strstr(input_buffer, "created=")) != NULL) {
110 temp_entry_time = strtoul (temp_ptr + 8, NULL, 10); 92 temp_entry_time = strtoul(temp_ptr + 8, NULL, 10);
111 latest_entry_time = temp_entry_time; 93 latest_entry_time = temp_entry_time;
112 break; 94 break;
113 } else if ((temp_ptr = strtok (input_buffer, "]")) != NULL) { 95 }
114 temp_entry_time = strtoul (temp_ptr + 1, NULL, 10); 96 if ((temp_ptr = strtok(input_buffer, "]")) != NULL) {
115 if (temp_entry_time > latest_entry_time) 97 temp_entry_time = strtoul(temp_ptr + 1, NULL, 10);
98 if (temp_entry_time > latest_entry_time) {
116 latest_entry_time = temp_entry_time; 99 latest_entry_time = temp_entry_time;
100 }
117 } 101 }
118 } 102 }
119 fclose (fp); 103 fclose(log_file);
120 104
121 if (verbose >= 2) 105 if (verbose >= 2) {
122 printf("command: %s\n", PS_COMMAND); 106 printf("command: %s\n", PS_COMMAND);
107 }
123 108
124 /* run the command to check for the Nagios process.. */ 109 /* run the command to check for the Nagios process.. */
125 if((result = np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0)) != 0) 110 mp_state_enum result = STATE_UNKNOWN;
111 output chld_out;
112 output chld_err;
113 if ((result = np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0)) != 0) {
126 result = STATE_WARNING; 114 result = STATE_WARNING;
115 }
127 116
117 int procuid = 0;
118 int procpid = 0;
119 int procppid = 0;
120 int procvsz = 0;
121 int procrss = 0;
122 int proc_entries = 0;
123 float procpcpu = 0;
124 char procstat[8];
125 char procprog[MAX_INPUT_BUFFER];
126 char *procargs;
127#ifdef PS_USES_PROCETIME
128 char procetime[MAX_INPUT_BUFFER];
129#endif /* PS_USES_PROCETIME */
130 int pos;
131 int expected_cols = PS_COLS - 1;
132 const char *zombie = "Z";
128 /* count the number of matching Nagios processes... */ 133 /* count the number of matching Nagios processes... */
129 for(i = 0; i < chld_out.lines; i++) { 134 for (size_t i = 0; i < chld_out.lines; i++) {
130 cols = sscanf (chld_out.line[i], PS_FORMAT, PS_VARLIST); 135 int cols = sscanf(chld_out.line[i], PS_FORMAT, PS_VARLIST);
131 /* Zombie processes do not give a procprog command */ 136 /* Zombie processes do not give a procprog command */
132 if ( cols == (expected_cols - 1) && strstr(procstat, zombie) ) { 137 if (cols == (expected_cols - 1) && strstr(procstat, zombie)) {
133 cols = expected_cols; 138 cols = expected_cols;
134 /* Set some value for procargs for the strip command further below 139 /* Set some value for procargs for the strip command further below
135 * Seen to be a problem on some Solaris 7 and 8 systems */ 140 * Seen to be a problem on some Solaris 7 and 8 systems */
136 chld_out.line[i][pos] = '\n'; 141 chld_out.line[i][pos] = '\n';
137 chld_out.line[i][pos+1] = 0x0; 142 chld_out.line[i][pos + 1] = 0x0;
138 } 143 }
139 if ( cols >= expected_cols ) { 144 if (cols >= expected_cols) {
140 xasprintf (&procargs, "%s", chld_out.line[i] + pos); 145 xasprintf(&procargs, "%s", chld_out.line[i] + pos);
141 strip (procargs); 146 strip(procargs);
142 147
143 /* Some ps return full pathname for command. This removes path */ 148 /* Some ps return full pathname for command. This removes path */
144 temp_string = strtok ((char *)procprog, "/"); 149 char *temp_string = strtok((char *)procprog, "/");
145 while (temp_string) { 150 while (temp_string) {
146 strcpy(procprog, temp_string); 151 strcpy(procprog, temp_string);
147 temp_string = strtok (NULL, "/"); 152 temp_string = strtok(NULL, "/");
148 } 153 }
149 154
150 /* May get empty procargs */ 155 /* May get empty procargs */
151 if (!strstr(procargs, argv[0]) && strstr(procargs, process_string) && strcmp(procargs,"")) { 156 if (!strstr(procargs, argv[0]) && strstr(procargs, config.process_string) && strcmp(procargs, "")) {
152 proc_entries++; 157 proc_entries++;
153 if (verbose >= 2) { 158 if (verbose >= 2) {
154 printf (_("Found process: %s %s\n"), procprog, procargs); 159 printf(_("Found process: %s %s\n"), procprog, procargs);
155 } 160 }
156 } 161 }
157 } 162 }
158 } 163 }
159 164
160 /* If we get anything on stderr, at least set warning */ 165 /* If we get anything on stderr, at least set warning */
161 if(chld_err.buflen) 166 if (chld_err.buflen) {
162 result = max_state (result, STATE_WARNING); 167 result = max_state(result, STATE_WARNING);
168 }
163 169
164 /* reset the alarm handler */ 170 /* reset the alarm handler */
165 alarm (0); 171 alarm(0);
166 172
167 if (proc_entries == 0) { 173 if (proc_entries == 0) {
168 die (STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Could not locate a running Nagios process!")); 174 die(STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Could not locate a running Nagios process!"));
169 } 175 }
170 176
171 if (latest_entry_time == 0L) { 177 if (latest_entry_time == 0L) {
172 die (STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Cannot parse Nagios log file for valid time")); 178 die(STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Cannot parse Nagios log file for valid time"));
173 } 179 }
174 180
175 time (&current_time); 181 time_t current_time;
176 if ((int)(current_time - latest_entry_time) > (expire_minutes * 60)) { 182 time(&current_time);
183 if ((int)(current_time - latest_entry_time) > (config.expire_minutes * 60)) {
177 result = STATE_WARNING; 184 result = STATE_WARNING;
178 } else { 185 } else {
179 result = STATE_OK; 186 result = STATE_OK;
180 } 187 }
181 188
182 printf ("NAGIOS %s: ", (result == STATE_OK) ? _("OK") : _("WARNING")); 189 printf("NAGIOS %s: ", (result == STATE_OK) ? _("OK") : _("WARNING"));
183 printf (ngettext ("%d process", "%d processes", proc_entries), proc_entries); 190 printf(ngettext("%d process", "%d processes", proc_entries), proc_entries);
184 printf (", "); 191 printf(", ");
185 printf ( 192 printf(ngettext("status log updated %d second ago", "status log updated %d seconds ago", (int)(current_time - latest_entry_time)),
186 ngettext ("status log updated %d second ago", 193 (int)(current_time - latest_entry_time));
187 "status log updated %d seconds ago", 194 printf("\n");
188 (int) (current_time - latest_entry_time) ),
189 (int) (current_time - latest_entry_time) );
190 printf ("\n");
191 195
192 return result; 196 exit(result);
193} 197}
194 198
195
196
197/* process command-line arguments */ 199/* process command-line arguments */
198int 200check_nagios_config_wrapper process_arguments(int argc, char **argv) {
199process_arguments (int argc, char **argv) 201 static struct option longopts[] = {{"filename", required_argument, 0, 'F'}, {"expires", required_argument, 0, 'e'},
200{ 202 {"command", required_argument, 0, 'C'}, {"timeout", optional_argument, 0, 't'},
201 int c; 203 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'},
202 204 {"verbose", no_argument, 0, 'v'}, {0, 0, 0, 0}};
203 int option = 0; 205
204 static struct option longopts[] = { 206 check_nagios_config_wrapper result = {
205 {"filename", required_argument, 0, 'F'}, 207 .errorcode = OK,
206 {"expires", required_argument, 0, 'e'}, 208 .config = check_nagios_config_init(),
207 {"command", required_argument, 0, 'C'},
208 {"timeout", optional_argument, 0, 't'},
209 {"version", no_argument, 0, 'V'},
210 {"help", no_argument, 0, 'h'},
211 {"verbose", no_argument, 0, 'v'},
212 {0, 0, 0, 0}
213 }; 209 };
210 if (argc < 2) {
211 result.errorcode = ERROR;
212 return result;
213 }
214 214
215 if (argc < 2) 215 if (!is_option(argv[1])) {
216 return ERROR; 216 result.config.status_log = argv[1];
217 217 if (is_intnonneg(argv[2])) {
218 if (!is_option (argv[1])) { 218 result.config.expire_minutes = atoi(argv[2]);
219 status_log = argv[1]; 219 } else {
220 if (is_intnonneg (argv[2])) 220 die(STATE_UNKNOWN, _("Expiration time must be an integer (seconds)\n"));
221 expire_minutes = atoi (argv[2]); 221 }
222 else 222 result.config.process_string = argv[3];
223 die (STATE_UNKNOWN, 223 return result;
224 _("Expiration time must be an integer (seconds)\n"));
225 process_string = argv[3];
226 return OK;
227 } 224 }
228 225
229 while (1) { 226 int option = 0;
230 c = getopt_long (argc, argv, "+hVvF:C:e:t:", longopts, &option); 227 while (true) {
228 int option_index = getopt_long(argc, argv, "+hVvF:C:e:t:", longopts, &option);
231 229
232 if (c == -1 || c == EOF || c == 1) 230 if (option_index == -1 || option_index == EOF || option_index == 1) {
233 break; 231 break;
232 }
234 233
235 switch (c) { 234 switch (option_index) {
236 case 'h': /* help */ 235 case 'h': /* help */
237 print_help (); 236 print_help();
238 exit (STATE_UNKNOWN); 237 exit(STATE_UNKNOWN);
239 case 'V': /* version */ 238 case 'V': /* version */
240 print_revision (progname, NP_VERSION); 239 print_revision(progname, NP_VERSION);
241 exit (STATE_UNKNOWN); 240 exit(STATE_UNKNOWN);
242 case 'F': /* status log */ 241 case 'F': /* status log */
243 status_log = optarg; 242 result.config.status_log = optarg;
244 break; 243 break;
245 case 'C': /* command */ 244 case 'C': /* command */
246 process_string = optarg; 245 result.config.process_string = optarg;
247 break; 246 break;
248 case 'e': /* expiry time */ 247 case 'e': /* expiry time */
249 if (is_intnonneg (optarg)) 248 if (is_intnonneg(optarg)) {
250 expire_minutes = atoi (optarg); 249 result.config.expire_minutes = atoi(optarg);
251 else 250 } else {
252 die (STATE_UNKNOWN, 251 die(STATE_UNKNOWN, _("Expiration time must be an integer (seconds)\n"));
253 _("Expiration time must be an integer (seconds)\n")); 252 }
254 break; 253 break;
255 case 't': /* timeout */ 254 case 't': /* timeout */
256 if (is_intnonneg (optarg)) 255 if (is_intnonneg(optarg)) {
257 timeout_interval = atoi (optarg); 256 timeout_interval = atoi(optarg);
258 else 257 } else {
259 die (STATE_UNKNOWN, 258 die(STATE_UNKNOWN, _("Timeout must be an integer (seconds)\n"));
260 _("Timeout must be an integer (seconds)\n")); 259 }
261 break; 260 break;
262 case 'v': 261 case 'v':
263 verbose++; 262 verbose++;
264 break; 263 break;
265 default: /* print short usage_va statement if args not parsable */ 264 default: /* print short usage_va statement if args not parsable */
266 usage5(); 265 usage5();
267 } 266 }
268 } 267 }
269 268
269 if (result.config.status_log == NULL) {
270 die(STATE_UNKNOWN, _("You must provide the status_log\n"));
271 }
270 272
271 if (status_log == NULL) 273 if (result.config.process_string == NULL) {
272 die (STATE_UNKNOWN, _("You must provide the status_log\n")); 274 die(STATE_UNKNOWN, _("You must provide a process string\n"));
273 275 }
274 if (process_string == NULL)
275 die (STATE_UNKNOWN, _("You must provide a process string\n"));
276 276
277 return OK; 277 return result;
278} 278}
279 279
280void print_help(void) {
281 print_revision(progname, NP_VERSION);
280 282
283 printf(_(COPYRIGHT), copyright, email);
281 284
282void 285 printf("%s\n", _("This plugin checks the status of the Nagios process on the local machine"));
283print_help (void) 286 printf("%s\n", _("The plugin will check to make sure the Nagios status log is no older than"));
284{ 287 printf("%s\n", _("the number of minutes specified by the expires option."));
285 print_revision (progname, NP_VERSION); 288 printf("%s\n", _("It also checks the process table for a process matching the command argument."));
286 289
287 printf (_(COPYRIGHT), copyright, email); 290 printf("\n\n");
288 291
289 printf ("%s\n", _("This plugin checks the status of the Nagios process on the local machine")); 292 print_usage();
290 printf ("%s\n", _("The plugin will check to make sure the Nagios status log is no older than"));
291 printf ("%s\n", _("the number of minutes specified by the expires option."));
292 printf ("%s\n", _("It also checks the process table for a process matching the command argument."));
293 293
294 printf ("\n\n"); 294 printf(UT_HELP_VRSN);
295 printf(UT_EXTRA_OPTS);
295 296
296 print_usage (); 297 printf(" %s\n", "-F, --filename=FILE");
298 printf(" %s\n", _("Name of the log file to check"));
299 printf(" %s\n", "-e, --expires=INTEGER");
300 printf(" %s\n", _("Minutes aging after which logfile is considered stale"));
301 printf(" %s\n", "-C, --command=STRING");
302 printf(" %s\n", _("Substring to search for in process arguments"));
303 printf(" %s\n", "-t, --timeout=INTEGER");
304 printf(" %s\n", _("Timeout for the plugin in seconds"));
305 printf(UT_VERBOSE);
297 306
298 printf (UT_HELP_VRSN); 307 printf("\n");
299 printf (UT_EXTRA_OPTS); 308 printf("%s\n", _("Examples:"));
309 printf(" %s\n", "check_nagios -t 20 -e 5 -F /usr/local/nagios/var/status.log -C /usr/local/nagios/bin/nagios");
300 310
301 printf (" %s\n", "-F, --filename=FILE"); 311 printf(UT_SUPPORT);
302 printf (" %s\n", _("Name of the log file to check"));
303 printf (" %s\n", "-e, --expires=INTEGER");
304 printf (" %s\n", _("Minutes aging after which logfile is considered stale"));
305 printf (" %s\n", "-C, --command=STRING");
306 printf (" %s\n", _("Substring to search for in process arguments"));
307 printf (" %s\n", "-t, --timeout=INTEGER");
308 printf (" %s\n", _("Timeout for the plugin in seconds"));
309 printf (UT_VERBOSE);
310
311 printf ("\n");
312 printf ("%s\n", _("Examples:"));
313 printf (" %s\n", "check_nagios -t 20 -e 5 -F /usr/local/nagios/var/status.log -C /usr/local/nagios/bin/nagios");
314
315 printf (UT_SUPPORT);
316} 312}
317 313
318 314void print_usage(void) {
319 315 printf("%s\n", _("Usage:"));
320void 316 printf("%s -F <status log file> -t <timeout_seconds> -e <expire_minutes> -C <process_string>\n", progname);
321print_usage (void)
322{
323 printf ("%s\n", _("Usage:"));
324 printf ("%s -F <status log file> -t <timeout_seconds> -e <expire_minutes> -C <process_string>\n", progname);
325} 317}
diff --git a/plugins/check_nagios.d/config.h b/plugins/check_nagios.d/config.h
new file mode 100644
index 00000000..efe139f9
--- /dev/null
+++ b/plugins/check_nagios.d/config.h
@@ -0,0 +1,19 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6typedef struct {
7 char *status_log;
8 char *process_string;
9 int expire_minutes;
10} check_nagios_config;
11
12check_nagios_config check_nagios_config_init() {
13 check_nagios_config tmp = {
14 .status_log = NULL,
15 .process_string = NULL,
16 .expire_minutes = 0,
17 };
18 return tmp;
19}
diff --git a/plugins/check_nt.c b/plugins/check_nt.c
index 19c050de..7dd23e5c 100644
--- a/plugins/check_nt.c
+++ b/plugins/check_nt.c
@@ -1,336 +1,291 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_nt plugin 3 * Monitoring check_nt plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2002 Yves Rubin (rubiyz@yahoo.com) 6 * Copyright (c) 2000-2002 Yves Rubin (rubiyz@yahoo.com)
7* Copyright (c) 2003-2007 Monitoring Plugins Development Team 7 * Copyright (c) 2003-2024 Monitoring Plugins Development Team
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains the check_nt plugin 11 * This file contains the check_nt plugin
12* 12 *
13* This plugin collects data from the NSClient service running on a 13 * This plugin collects data from the NSClient service running on a
14* Windows NT/2000/XP/2003 server. 14 * Windows NT/2000/XP/2003 server.
15* This plugin requires NSClient software to run on NT 15 * This plugin requires NSClient software to run on NT
16* (http://nsclient.ready2run.nl/) 16 * (https://nsclient.org/)
17* 17 *
18* 18 *
19* This program is free software: you can redistribute it and/or modify 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 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 21 * the Free Software Foundation, either version 3 of the License, or
22* (at your option) any later version. 22 * (at your option) any later version.
23* 23 *
24* This program is distributed in the hope that it will be useful, 24 * This program is distributed in the hope that it will be useful,
25* but WITHOUT ANY WARRANTY; without even the implied warranty of 25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27* GNU General Public License for more details. 27 * GNU General Public License for more details.
28* 28 *
29* You should have received a copy of the GNU General Public License 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/>. 30 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31* 31 *
32* 32 *
33*****************************************************************************/ 33 *****************************************************************************/
34 34
35const char *progname = "check_nt"; 35const char *progname = "check_nt";
36const char *copyright = "2000-2007"; 36const char *copyright = "2000-2024";
37const char *email = "devel@monitoring-plugins.org"; 37const char *email = "devel@monitoring-plugins.org";
38 38
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_nt.d/config.h"
43enum checkvars {
44 CHECK_NONE,
45 CHECK_CLIENTVERSION,
46 CHECK_CPULOAD,
47 CHECK_UPTIME,
48 CHECK_USEDDISKSPACE,
49 CHECK_SERVICESTATE,
50 CHECK_PROCSTATE,
51 CHECK_MEMUSE,
52 CHECK_COUNTER,
53 CHECK_FILEAGE,
54 CHECK_INSTANCES
55};
56 43
57enum { 44enum {
58 MAX_VALUE_LIST = 30, 45 MAX_VALUE_LIST = 30,
59 PORT = 1248
60}; 46};
61 47
62char *server_address=NULL; 48static char recv_buffer[MAX_INPUT_BUFFER];
63char *volume_name=NULL;
64int server_port=PORT;
65char *value_list=NULL;
66char *req_password=NULL;
67unsigned long lvalue_list[MAX_VALUE_LIST];
68unsigned long warning_value=0L;
69unsigned long critical_value=0L;
70bool check_warning_value=false;
71bool check_critical_value=false;
72enum checkvars vars_to_check = CHECK_NONE;
73bool show_all = false;
74
75char recv_buffer[MAX_INPUT_BUFFER];
76
77void fetch_data (const char* address, int port, const char* sendb);
78int process_arguments(int, char **);
79void preparelist(char *string);
80bool strtoularray(unsigned long *array, char *string, const char *delim);
81void print_help(void);
82void print_usage(void);
83 49
84int main(int argc, char **argv){ 50static void fetch_data(const char *address, int port, const char *sendb);
85 51
86/* should be int result = STATE_UNKNOWN; */ 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*/);
87 57
88 int return_code = STATE_UNKNOWN; 58static void preparelist(char *string);
89 char *send_buffer=NULL; 59static bool strtoularray(unsigned long *array, char *string, const char *delim);
90 char *output_message=NULL; 60static void print_help(void);
91 char *perfdata=NULL; 61void print_usage(void);
92 char *temp_string=NULL; 62
93 char *temp_string_perf=NULL; 63int main(int argc, char **argv) {
94 char *description=NULL,*counter_unit = NULL; 64 setlocale(LC_ALL, "");
95 char *minval = NULL, *maxval = NULL, *errcvt = NULL; 65 bindtextdomain(PACKAGE, LOCALEDIR);
96 char *fds=NULL, *tds=NULL; 66 textdomain(PACKAGE);
97 char *numstr;
98
99 double total_disk_space=0;
100 double free_disk_space=0;
101 double percent_used_space=0;
102 double warning_used_space=0;
103 double critical_used_space=0;
104 double mem_commitLimit=0;
105 double mem_commitByte=0;
106 double fminval = 0, fmaxval = 0;
107 unsigned long utilization;
108 unsigned long uptime;
109 unsigned long age_in_minutes;
110 double counter_value = 0.0;
111 int offset=0;
112 int updays=0;
113 int uphours=0;
114 int upminutes=0;
115
116 bool isPercent = false;
117 bool allRight = false;
118
119 setlocale (LC_ALL, "");
120 bindtextdomain (PACKAGE, LOCALEDIR);
121 textdomain (PACKAGE);
122 67
123 /* Parse extra opts if any */ 68 /* Parse extra opts if any */
124 argv=np_extra_opts (&argc, argv, progname); 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 }
125 75
126 if(process_arguments(argc,argv) == ERROR) 76 const check_nt_config config = tmp_config.config;
127 usage4 (_("Could not parse arguments"));
128 77
129 /* initialize alarm signal handling */ 78 /* initialize alarm signal handling */
130 signal(SIGALRM,socket_timeout_alarm_handler); 79 signal(SIGALRM, socket_timeout_alarm_handler);
131 80
132 /* set socket timeout */ 81 /* set socket timeout */
133 alarm(socket_timeout); 82 alarm(socket_timeout);
134 83
135 switch (vars_to_check) { 84 int return_code = STATE_UNKNOWN;
136 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) {
137 case CHECK_CLIENTVERSION: 95 case CHECK_CLIENTVERSION:
138 96 xasprintf(&send_buffer, "%s&1", config.req_password);
139 xasprintf(&send_buffer, "%s&1", req_password); 97 fetch_data(config.server_address, config.server_port, send_buffer);
140 fetch_data (server_address, server_port, send_buffer); 98 if (config.value_list != NULL && strcmp(recv_buffer, config.value_list) != 0) {
141 if (value_list != NULL && strcmp(recv_buffer, value_list) != 0) { 99 xasprintf(&output_message, _("Wrong client version - running: %s, required: %s"), recv_buffer, config.value_list);
142 xasprintf (&output_message, _("Wrong client version - running: %s, required: %s"), recv_buffer, value_list);
143 return_code = STATE_WARNING; 100 return_code = STATE_WARNING;
144 } else { 101 } else {
145 xasprintf (&output_message, "%s", recv_buffer); 102 xasprintf(&output_message, "%s", recv_buffer);
146 return_code = STATE_OK; 103 return_code = STATE_OK;
147 } 104 }
148 break; 105 break;
149
150 case CHECK_CPULOAD: 106 case CHECK_CPULOAD:
151 107 if (config.value_list == NULL) {
152 if (value_list==NULL) 108 output_message = strdup(_("missing -l parameters"));
153 output_message = strdup (_("missing -l parameters")); 109 } else if (!strtoularray(lvalue_list, config.value_list, ",")) {
154 else if (! strtoularray(lvalue_list,value_list,",")) 110 output_message = strdup(_("wrong -l parameter."));
155 output_message = strdup (_("wrong -l parameter.")); 111 } else {
156 else {
157 /* -l parameters is present with only integers */ 112 /* -l parameters is present with only integers */
158 return_code=STATE_OK; 113 return_code = STATE_OK;
159 temp_string = strdup (_("CPU Load")); 114 temp_string = strdup(_("CPU Load"));
160 temp_string_perf = strdup (" "); 115 temp_string_perf = strdup(" ");
161 116
162 /* loop until one of the parameters is wrong or not present */ 117 /* loop until one of the parameters is wrong or not present */
163 while (lvalue_list[0+offset]> (unsigned long)0 && 118 int offset = 0;
164 lvalue_list[0+offset]<=(unsigned long)17280 && 119 while (lvalue_list[0 + offset] > (unsigned long)0 && lvalue_list[0 + offset] <= (unsigned long)17280 &&
165 lvalue_list[1+offset]> (unsigned long)0 && 120 lvalue_list[1 + offset] > (unsigned long)0 && lvalue_list[1 + offset] <= (unsigned long)100 &&
166 lvalue_list[1+offset]<=(unsigned long)100 && 121 lvalue_list[2 + offset] > (unsigned long)0 && lvalue_list[2 + offset] <= (unsigned long)100) {
167 lvalue_list[2+offset]> (unsigned long)0 &&
168 lvalue_list[2+offset]<=(unsigned long)100) {
169 122
170 /* Send request and retrieve data */ 123 /* Send request and retrieve data */
171 xasprintf(&send_buffer,"%s&2&%lu",req_password,lvalue_list[0+offset]); 124 xasprintf(&send_buffer, "%s&2&%lu", config.req_password, lvalue_list[0 + offset]);
172 fetch_data (server_address, server_port, send_buffer); 125 fetch_data(config.server_address, config.server_port, send_buffer);
173 126
174 utilization=strtoul(recv_buffer,NULL,10); 127 unsigned long utilization = strtoul(recv_buffer, NULL, 10);
175 128
176 /* Check if any of the request is in a warning or critical state */ 129 /* Check if any of the request is in a warning or critical state */
177 if(utilization >= lvalue_list[2+offset]) 130 if (utilization >= lvalue_list[2 + offset]) {
178 return_code=STATE_CRITICAL; 131 return_code = STATE_CRITICAL;
179 else if(utilization >= lvalue_list[1+offset] && return_code<STATE_WARNING) 132 } else if (utilization >= lvalue_list[1 + offset] && return_code < STATE_WARNING) {
180 return_code=STATE_WARNING; 133 return_code = STATE_WARNING;
181 134 }
182 xasprintf(&output_message,_(" %lu%% (%lu min average)"), utilization, lvalue_list[0+offset]); 135
183 xasprintf(&temp_string,"%s%s",temp_string,output_message); 136 xasprintf(&output_message, _(" %lu%% (%lu min average)"), utilization, lvalue_list[0 + offset]);
184 xasprintf(&perfdata,_(" '%lu min avg Load'=%lu%%;%lu;%lu;0;100"), lvalue_list[0+offset], utilization, 137 xasprintf(&temp_string, "%s%s", temp_string, output_message);
185 lvalue_list[1+offset], lvalue_list[2+offset]); 138 xasprintf(&perfdata, _(" '%lu min avg Load'=%lu%%;%lu;%lu;0;100"), lvalue_list[0 + offset], utilization,
186 xasprintf(&temp_string_perf,"%s%s",temp_string_perf,perfdata); 139 lvalue_list[1 + offset], lvalue_list[2 + offset]);
187 offset+=3; /* move across the array */ 140 xasprintf(&temp_string_perf, "%s%s", temp_string_perf, perfdata);
141 offset += 3; /* move across the array */
188 } 142 }
189 143
190 if (strlen(temp_string)>10) { /* we had at least one loop */ 144 if (strlen(temp_string) > 10) { /* we had at least one loop */
191 output_message = strdup (temp_string); 145 output_message = strdup(temp_string);
192 perfdata = temp_string_perf; 146 perfdata = temp_string_perf;
193 } else 147 } else {
194 output_message = strdup (_("not enough values for -l parameters")); 148 output_message = strdup(_("not enough values for -l parameters"));
149 }
195 } 150 }
196 break; 151 break;
197 152 case CHECK_UPTIME: {
198 case CHECK_UPTIME: 153 char *tmp_value_list = config.value_list;
199 154 if (config.value_list == NULL) {
200 if (value_list == NULL) { 155 tmp_value_list = "minutes";
201 value_list = "minutes";
202 } 156 }
203 if (strncmp(value_list, "seconds", strlen("seconds") + 1 ) && 157 if (strncmp(tmp_value_list, "seconds", strlen("seconds") + 1) && strncmp(tmp_value_list, "minutes", strlen("minutes") + 1) &&
204 strncmp(value_list, "minutes", strlen("minutes") + 1) && 158 strncmp(config.value_list, "hours", strlen("hours") + 1) && strncmp(tmp_value_list, "days", strlen("days") + 1)) {
205 strncmp(value_list, "hours", strlen("hours") + 1) &&
206 strncmp(value_list, "days", strlen("days") + 1)) {
207 159
208 output_message = strdup (_("wrong -l argument")); 160 output_message = strdup(_("wrong -l argument"));
209 } else { 161 } else {
210 xasprintf(&send_buffer, "%s&3", req_password); 162 xasprintf(&send_buffer, "%s&3", config.req_password);
211 fetch_data (server_address, server_port, send_buffer); 163 fetch_data(config.server_address, config.server_port, send_buffer);
212 uptime=strtoul(recv_buffer,NULL,10); 164 unsigned long uptime = strtoul(recv_buffer, NULL, 10);
213 updays = uptime / 86400; 165 int updays = uptime / 86400;
214 uphours = (uptime % 86400) / 3600; 166 int uphours = (uptime % 86400) / 3600;
215 upminutes = ((uptime % 86400) % 3600) / 60; 167 int upminutes = ((uptime % 86400) % 3600) / 60;
216 168
217 if (!strncmp(value_list, "minutes", strlen("minutes"))) 169 if (!strncmp(tmp_value_list, "minutes", strlen("minutes"))) {
218 uptime = uptime / 60; 170 uptime = uptime / 60;
219 else if (!strncmp(value_list, "hours", strlen("hours"))) 171 } else if (!strncmp(tmp_value_list, "hours", strlen("hours"))) {
220 uptime = uptime / 3600; 172 uptime = uptime / 3600;
221 else if (!strncmp(value_list, "days", strlen("days"))) 173 } else if (!strncmp(tmp_value_list, "days", strlen("days"))) {
222 uptime = uptime / 86400; 174 uptime = uptime / 86400;
175 }
223 /* else uptime in seconds, nothing to do */ 176 /* else uptime in seconds, nothing to do */
224 177
225 xasprintf(&output_message,_("System Uptime - %u day(s) %u hour(s) %u minute(s) |uptime=%lu"),updays, uphours, upminutes, uptime); 178 xasprintf(&output_message, _("System Uptime - %u day(s) %u hour(s) %u minute(s) |uptime=%lu"), updays, uphours, upminutes,
179 uptime);
226 180
227 if (check_critical_value && uptime <= critical_value) 181 if (config.check_critical_value && uptime <= config.critical_value) {
228 return_code=STATE_CRITICAL; 182 return_code = STATE_CRITICAL;
229 else if (check_warning_value && uptime <= warning_value) 183 } else if (config.check_warning_value && uptime <= config.warning_value) {
230 return_code=STATE_WARNING; 184 return_code = STATE_WARNING;
231 else 185 } else {
232 return_code=STATE_OK; 186 return_code = STATE_OK;
187 }
233 } 188 }
234 break; 189 } break;
235
236 case CHECK_USEDDISKSPACE: 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 }
237 208
238 if (value_list==NULL) 209 if (total_disk_space > 0 && free_disk_space >= 0) {
239 output_message = strdup (_("missing -l parameters")); 210 double percent_used_space = ((total_disk_space - free_disk_space) / total_disk_space) * 100;
240 else if (strlen(value_list)!=1) 211 double warning_used_space = ((float)config.warning_value / 100) * total_disk_space;
241 output_message = strdup (_("wrong -l argument")); 212 double critical_used_space = ((float)config.critical_value / 100) * total_disk_space;
242 else { 213
243 xasprintf(&send_buffer,"%s&4&%s", req_password, value_list); 214 xasprintf(&temp_string, _("%s:\\ - total: %.2f Gb - used: %.2f Gb (%.0f%%) - free %.2f Gb (%.0f%%)"), config.value_list,
244 fetch_data (server_address, server_port, send_buffer); 215 total_disk_space / 1073741824, (total_disk_space - free_disk_space) / 1073741824, percent_used_space,
245 fds=strtok(recv_buffer,"&"); 216 free_disk_space / 1073741824, (free_disk_space / total_disk_space) * 100);
246 tds=strtok(NULL,"&"); 217 xasprintf(&temp_string_perf, _("'%s:\\ Used Space'=%.2fGb;%.2f;%.2f;0.00;%.2f"), config.value_list,
247 if(fds!=NULL) 218 (total_disk_space - free_disk_space) / 1073741824, warning_used_space / 1073741824,
248 free_disk_space=atof(fds); 219 critical_used_space / 1073741824, total_disk_space / 1073741824);
249 if(tds!=NULL) 220
250 total_disk_space=atof(tds); 221 if (config.check_critical_value && percent_used_space >= config.critical_value) {
251 222 return_code = STATE_CRITICAL;
252 if (total_disk_space>0 && free_disk_space>=0) { 223 } else if (config.check_warning_value && percent_used_space >= config.warning_value) {
253 percent_used_space = ((total_disk_space - free_disk_space) / total_disk_space) * 100; 224 return_code = STATE_WARNING;
254 warning_used_space = ((float)warning_value / 100) * total_disk_space; 225 } else {
255 critical_used_space = ((float)critical_value / 100) * total_disk_space; 226 return_code = STATE_OK;
256 227 }
257 xasprintf(&temp_string,_("%s:\\ - total: %.2f Gb - used: %.2f Gb (%.0f%%) - free %.2f Gb (%.0f%%)"), 228
258 value_list, total_disk_space / 1073741824, (total_disk_space - free_disk_space) / 1073741824, 229 output_message = strdup(temp_string);
259 percent_used_space, free_disk_space / 1073741824, (free_disk_space / total_disk_space)*100);
260 xasprintf(&temp_string_perf,_("'%s:\\ Used Space'=%.2fGb;%.2f;%.2f;0.00;%.2f"), value_list,
261 (total_disk_space - free_disk_space) / 1073741824, warning_used_space / 1073741824,
262 critical_used_space / 1073741824, total_disk_space / 1073741824);
263
264 if(check_critical_value && percent_used_space >= critical_value)
265 return_code=STATE_CRITICAL;
266 else if (check_warning_value && percent_used_space >= warning_value)
267 return_code=STATE_WARNING;
268 else
269 return_code=STATE_OK;
270
271 output_message = strdup (temp_string);
272 perfdata = temp_string_perf; 230 perfdata = temp_string_perf;
273 } else { 231 } else {
274 output_message = strdup (_("Free disk space : Invalid drive")); 232 output_message = strdup(_("Free disk space : Invalid drive"));
275 return_code=STATE_UNKNOWN; 233 return_code = STATE_UNKNOWN;
276 } 234 }
277 } 235 }
278 break; 236 break;
279
280 case CHECK_SERVICESTATE: 237 case CHECK_SERVICESTATE:
281 case CHECK_PROCSTATE: 238 case CHECK_PROCSTATE:
282 239 if (config.value_list == NULL) {
283 if (value_list==NULL) 240 output_message = strdup(_("No service/process specified"));
284 output_message = strdup (_("No service/process specified")); 241 } else {
285 else { 242 preparelist(config.value_list); /* replace , between services with & to send the request */
286 preparelist(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,
287 xasprintf(&send_buffer,"%s&%u&%s&%s", req_password,(vars_to_check==CHECK_SERVICESTATE)?5:6, 244 (config.show_all) ? "ShowAll" : "ShowFail", config.value_list);
288 (show_all) ? "ShowAll" : "ShowFail",value_list); 245 fetch_data(config.server_address, config.server_port, send_buffer);
289 fetch_data (server_address, server_port, send_buffer); 246 char *numstr = strtok(recv_buffer, "&");
290 numstr = strtok(recv_buffer,"&"); 247 if (numstr == NULL) {
291 if (numstr == NULL)
292 die(STATE_UNKNOWN, _("could not fetch information from server\n")); 248 die(STATE_UNKNOWN, _("could not fetch information from server\n"));
293 return_code=atoi(numstr); 249 }
294 temp_string=strtok(NULL,"&"); 250 return_code = atoi(numstr);
295 output_message = strdup (temp_string); 251 temp_string = strtok(NULL, "&");
252 output_message = strdup(temp_string);
296 } 253 }
297 break; 254 break;
298
299 case CHECK_MEMUSE: 255 case CHECK_MEMUSE:
300 256 xasprintf(&send_buffer, "%s&7", config.req_password);
301 xasprintf(&send_buffer,"%s&7", req_password); 257 fetch_data(config.server_address, config.server_port, send_buffer);
302 fetch_data (server_address, server_port, send_buffer); 258 char *numstr = strtok(recv_buffer, "&");
303 numstr = strtok(recv_buffer,"&"); 259 if (numstr == NULL) {
304 if (numstr == NULL)
305 die(STATE_UNKNOWN, _("could not fetch information from server\n")); 260 die(STATE_UNKNOWN, _("could not fetch information from server\n"));
306 mem_commitLimit=atof(numstr); 261 }
307 numstr = strtok(NULL,"&"); 262 double mem_commitLimit = atof(numstr);
308 if (numstr == NULL) 263 numstr = strtok(NULL, "&");
264 if (numstr == NULL) {
309 die(STATE_UNKNOWN, _("could not fetch information from server\n")); 265 die(STATE_UNKNOWN, _("could not fetch information from server\n"));
310 mem_commitByte=atof(numstr); 266 }
311 percent_used_space = (mem_commitByte / mem_commitLimit) * 100; 267 double mem_commitByte = atof(numstr);
312 warning_used_space = ((float)warning_value / 100) * mem_commitLimit; 268 double percent_used_space = (mem_commitByte / mem_commitLimit) * 100;
313 critical_used_space = ((float)critical_value / 100) * mem_commitLimit; 269 double warning_used_space = ((float)config.warning_value / 100) * mem_commitLimit;
270 double critical_used_space = ((float)config.critical_value / 100) * mem_commitLimit;
314 271
315 /* Divisor should be 1048567, not 3044515, as we are measuring "Commit Charge" here, 272 /* Divisor should be 1048567, not 3044515, as we are measuring "Commit Charge" here,
316 which equals RAM + Pagefiles. */ 273 which equals RAM + Pagefiles. */
317 xasprintf(&output_message,_("Memory usage: total:%.2f MB - used: %.2f MB (%.0f%%) - free: %.2f MB (%.0f%%)"), 274 xasprintf(&output_message, _("Memory usage: total:%.2f MB - used: %.2f MB (%.0f%%) - free: %.2f MB (%.0f%%)"),
318 mem_commitLimit / 1048567, mem_commitByte / 1048567, percent_used_space, 275 mem_commitLimit / 1048567, mem_commitByte / 1048567, percent_used_space, (mem_commitLimit - mem_commitByte) / 1048567,
319 (mem_commitLimit - mem_commitByte) / 1048567, (mem_commitLimit - mem_commitByte) / mem_commitLimit * 100); 276 (mem_commitLimit - mem_commitByte) / mem_commitLimit * 100);
320 xasprintf(&perfdata,_("'Memory usage'=%.2fMB;%.2f;%.2f;0.00;%.2f"), mem_commitByte / 1048567, 277 xasprintf(&perfdata, _("'Memory usage'=%.2fMB;%.2f;%.2f;0.00;%.2f"), mem_commitByte / 1048567, warning_used_space / 1048567,
321 warning_used_space / 1048567, critical_used_space / 1048567, mem_commitLimit / 1048567); 278 critical_used_space / 1048567, mem_commitLimit / 1048567);
322 279
323 return_code=STATE_OK; 280 return_code = STATE_OK;
324 if(check_critical_value && percent_used_space >= critical_value) 281 if (config.check_critical_value && percent_used_space >= config.critical_value) {
325 return_code=STATE_CRITICAL; 282 return_code = STATE_CRITICAL;
326 else if (check_warning_value && percent_used_space >= warning_value) 283 } else if (config.check_warning_value && percent_used_space >= config.warning_value) {
327 return_code=STATE_WARNING; 284 return_code = STATE_WARNING;
285 }
328 286
329 break; 287 break;
330 288 case CHECK_COUNTER: {
331 case CHECK_COUNTER:
332
333
334 /* 289 /*
335 CHECK_COUNTER has been modified to provide extensive perfdata information. 290 CHECK_COUNTER has been modified to provide extensive perfdata information.
336 In order to do this, some modifications have been done to the code 291 In order to do this, some modifications have been done to the code
@@ -352,450 +307,450 @@ int main(int argc, char **argv){
352 strange things will happen when you make graphs of your data. 307 strange things will happen when you make graphs of your data.
353 */ 308 */
354 309
355 if (value_list == NULL) 310 double counter_value = 0.0;
356 output_message = strdup (_("No counter specified")); 311 if (config.value_list == NULL) {
357 else 312 output_message = strdup(_("No counter specified"));
358 { 313 } else {
359 preparelist (value_list); /* replace , between services with & to send the request */ 314 preparelist(config.value_list); /* replace , between services with & to send the request */
360 isPercent = (strchr (value_list, '%') != NULL); 315 bool isPercent = (strchr(config.value_list, '%') != NULL);
361 316
362 strtok (value_list, "&"); /* burn the first parameters */ 317 strtok(config.value_list, "&"); /* burn the first parameters */
363 description = strtok (NULL, "&"); 318 description = strtok(NULL, "&");
364 counter_unit = strtok (NULL, "&"); 319 counter_unit = strtok(NULL, "&");
365 xasprintf (&send_buffer, "%s&8&%s", req_password, value_list); 320 xasprintf(&send_buffer, "%s&8&%s", config.req_password, config.value_list);
366 fetch_data (server_address, server_port, send_buffer); 321 fetch_data(config.server_address, config.server_port, send_buffer);
367 counter_value = atof (recv_buffer); 322 counter_value = atof(recv_buffer);
368 323
369 if (description == NULL) 324 bool allRight = false;
370 xasprintf (&output_message, "%.f", counter_value); 325 if (description == NULL) {
371 else if (isPercent) 326 xasprintf(&output_message, "%.f", counter_value);
372 { 327 } else if (isPercent) {
373 counter_unit = strdup ("%"); 328 counter_unit = strdup("%");
374 allRight = true; 329 allRight = true;
375 } 330 }
376 331
377 if ((counter_unit != NULL) && (!allRight)) 332 char *minval = NULL;
378 { 333 char *maxval = NULL;
379 minval = strtok (NULL, "&"); 334 double fminval = 0;
380 maxval = strtok (NULL, "&"); 335 double fmaxval = 0;
336 if ((counter_unit != NULL) && (!allRight)) {
337 minval = strtok(NULL, "&");
338 maxval = strtok(NULL, "&");
381 339
382 /* All parameters specified. Let's check the numbers */ 340 /* All parameters specified. Let's check the numbers */
383 341
384 fminval = (minval != NULL) ? strtod (minval, &errcvt) : -1; 342 fminval = (minval != NULL) ? strtod(minval, &errcvt) : -1;
385 fmaxval = (minval != NULL) ? strtod (maxval, &errcvt) : -1; 343 fmaxval = (minval != NULL) ? strtod(maxval, &errcvt) : -1;
386
387 if ((fminval == 0) && (minval == errcvt))
388 output_message = strdup (_("Minimum value contains non-numbers"));
389 else
390 {
391 if ((fmaxval == 0) && (maxval == errcvt))
392 output_message = strdup (_("Maximum value contains non-numbers"));
393 else
394 allRight = true; /* Everything is OK. */
395 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 }
396 } 353 }
354 } else if ((counter_unit == NULL) && (description != NULL)) {
355 output_message = strdup(_("No unit counter specified"));
397 } 356 }
398 else if ((counter_unit == NULL) && (description != NULL))
399 output_message = strdup (_("No unit counter specified"));
400 357
401 if (allRight) 358 if (allRight) {
402 {
403 /* Let's format the output string, finally... */ 359 /* Let's format the output string, finally... */
404 if (strstr(description, "%") == NULL) { 360 if (strstr(description, "%") == NULL) {
405 xasprintf (&output_message, "%s = %.2f %s", description, counter_value, counter_unit); 361 xasprintf(&output_message, "%s = %.2f %s", description, counter_value, counter_unit);
406 } else { 362 } else {
407 /* has formatting, will segv if wrong */ 363 /* has formatting, will segv if wrong */
408 xasprintf (&output_message, description, counter_value); 364 xasprintf(&output_message, description, counter_value);
409 } 365 }
410 xasprintf (&output_message, "%s |", output_message); 366 xasprintf(&output_message, "%s |", output_message);
411 xasprintf (&output_message,"%s %s", output_message, 367 xasprintf(&output_message, "%s %s", output_message,
412 fperfdata (description, counter_value, 368 fperfdata(description, counter_value, counter_unit, 1, config.warning_value, 1, config.critical_value,
413 counter_unit, 1, warning_value, 1, critical_value, 369 (!(isPercent) && (minval != NULL)), fminval, (!(isPercent) && (minval != NULL)), fmaxval));
414 (!(isPercent) && (minval != NULL)), fminval,
415 (!(isPercent) && (minval != NULL)), fmaxval));
416 } 370 }
417 } 371 }
418 372
419 if (critical_value > warning_value) 373 if (config.critical_value > config.warning_value) { /* Normal thresholds */
420 { /* Normal thresholds */ 374 if (config.check_critical_value && counter_value >= config.critical_value) {
421 if (check_critical_value && counter_value >= critical_value)
422 return_code = STATE_CRITICAL; 375 return_code = STATE_CRITICAL;
423 else if (check_warning_value && counter_value >= warning_value) 376 } else if (config.check_warning_value && counter_value >= config.warning_value) {
424 return_code = STATE_WARNING; 377 return_code = STATE_WARNING;
425 else 378 } else {
426 return_code = STATE_OK; 379 return_code = STATE_OK;
427 } 380 }
428 else 381 } else { /* inverse thresholds */
429 { /* inverse thresholds */
430 return_code = STATE_OK; 382 return_code = STATE_OK;
431 if (check_critical_value && counter_value <= critical_value) 383 if (config.check_critical_value && counter_value <= config.critical_value) {
432 return_code = STATE_CRITICAL; 384 return_code = STATE_CRITICAL;
433 else if (check_warning_value && counter_value <= warning_value) 385 } else if (config.check_warning_value && counter_value <= config.warning_value) {
434 return_code = STATE_WARNING; 386 return_code = STATE_WARNING;
387 }
435 } 388 }
436 break; 389 } break;
437
438 case CHECK_FILEAGE: 390 case CHECK_FILEAGE:
439 391 if (config.value_list == NULL) {
440 if (value_list==NULL) 392 output_message = strdup(_("No counter specified"));
441 output_message = strdup (_("No counter specified")); 393 } else {
442 else { 394 preparelist(config.value_list); /* replace , between services with & to send the request */
443 preparelist(value_list); /* replace , between services with & to send the request */ 395 xasprintf(&send_buffer, "%s&9&%s", config.req_password, config.value_list);
444 xasprintf(&send_buffer,"%s&9&%s", req_password,value_list); 396 fetch_data(config.server_address, config.server_port, send_buffer);
445 fetch_data (server_address, server_port, send_buffer); 397 unsigned long age_in_minutes = atoi(strtok(recv_buffer, "&"));
446 age_in_minutes = atoi(strtok(recv_buffer,"&")); 398 description = strtok(NULL, "&");
447 description = strtok(NULL,"&"); 399 output_message = strdup(description);
448 output_message = strdup (description); 400
449 401 if (config.critical_value > config.warning_value) { /* Normal thresholds */
450 if (critical_value > warning_value) { /* Normal thresholds */ 402 if (config.check_critical_value && age_in_minutes >= config.critical_value) {
451 if(check_critical_value && age_in_minutes >= critical_value) 403 return_code = STATE_CRITICAL;
452 return_code=STATE_CRITICAL; 404 } else if (config.check_warning_value && age_in_minutes >= config.warning_value) {
453 else if (check_warning_value && age_in_minutes >= warning_value) 405 return_code = STATE_WARNING;
454 return_code=STATE_WARNING; 406 } else {
455 else 407 return_code = STATE_OK;
456 return_code=STATE_OK; 408 }
457 } 409 } else { /* inverse thresholds */
458 else { /* inverse thresholds */ 410 if (config.check_critical_value && age_in_minutes <= config.critical_value) {
459 if(check_critical_value && age_in_minutes <= critical_value) 411 return_code = STATE_CRITICAL;
460 return_code=STATE_CRITICAL; 412 } else if (config.check_warning_value && age_in_minutes <= config.warning_value) {
461 else if (check_warning_value && age_in_minutes <= warning_value) 413 return_code = STATE_WARNING;
462 return_code=STATE_WARNING; 414 } else {
463 else 415 return_code = STATE_OK;
464 return_code=STATE_OK; 416 }
465 } 417 }
466 } 418 }
467 break; 419 break;
468 420
469 case CHECK_INSTANCES: 421 case CHECK_INSTANCES:
470 if (value_list==NULL) 422 if (config.value_list == NULL) {
471 output_message = strdup (_("No counter specified")); 423 output_message = strdup(_("No counter specified"));
472 else { 424 } else {
473 xasprintf(&send_buffer,"%s&10&%s", req_password,value_list); 425 xasprintf(&send_buffer, "%s&10&%s", config.req_password, config.value_list);
474 fetch_data (server_address, server_port, send_buffer); 426 fetch_data(config.server_address, config.server_port, send_buffer);
475 if (!strncmp(recv_buffer,"ERROR",5)) { 427 if (!strncmp(recv_buffer, "ERROR", 5)) {
476 printf("NSClient - %s\n",recv_buffer); 428 printf("NSClient - %s\n", recv_buffer);
477 exit(STATE_UNKNOWN); 429 exit(STATE_UNKNOWN);
478 } 430 }
479 xasprintf(&output_message,"%s",recv_buffer); 431 xasprintf(&output_message, "%s", recv_buffer);
480 return_code=STATE_OK; 432 return_code = STATE_OK;
481 } 433 }
482 break; 434 break;
483 435
484 case CHECK_NONE: 436 case CHECK_NONE:
485 default: 437 default:
486 usage4 (_("Please specify a variable to check")); 438 usage4(_("Please specify a variable to check"));
487 break; 439 break;
488
489 } 440 }
490 441
491 /* reset timeout */ 442 /* reset timeout */
492 alarm(0); 443 alarm(0);
493 444
494 if (perfdata==NULL) 445 if (perfdata == NULL) {
495 printf("%s\n",output_message); 446 printf("%s\n", output_message);
496 else 447 } else {
497 printf("%s | %s\n",output_message,perfdata); 448 printf("%s | %s\n", output_message, perfdata);
449 }
498 return return_code; 450 return return_code;
499} 451}
500 452
501
502
503/* process command-line arguments */ 453/* process command-line arguments */
504int process_arguments(int argc, char **argv){ 454check_nt_config_wrapper process_arguments(int argc, char **argv) {
505 int c; 455 static struct option longopts[] = {{"port", required_argument, 0, 'p'},
506 456 {"timeout", required_argument, 0, 't'},
507 int option = 0; 457 {"critical", required_argument, 0, 'c'},
508 static struct option longopts[] = 458 {"warning", required_argument, 0, 'w'},
509 { 459 {"variable", required_argument, 0, 'v'},
510 {"port", required_argument,0,'p'}, 460 {"hostname", required_argument, 0, 'H'},
511 {"timeout", required_argument,0,'t'}, 461 {"params", required_argument, 0, 'l'},
512 {"critical", required_argument,0,'c'}, 462 {"secret", required_argument, 0, 's'},
513 {"warning", required_argument,0,'w'}, 463 {"display", required_argument, 0, 'd'},
514 {"variable", required_argument,0,'v'}, 464 {"unknown-timeout", no_argument, 0, 'u'},
515 {"hostname", required_argument,0,'H'}, 465 {"version", no_argument, 0, 'V'},
516 {"params", required_argument,0,'l'}, 466 {"help", no_argument, 0, 'h'},
517 {"secret", required_argument,0,'s'}, 467 {0, 0, 0, 0}};
518 {"display", required_argument,0,'d'}, 468
519 {"unknown-timeout", no_argument, 0, 'u'}, 469 check_nt_config_wrapper result = {
520 {"version", no_argument, 0,'V'}, 470 .errorcode = OK,
521 {"help", no_argument, 0,'h'}, 471 .config = check_nt_config_init(),
522 {0,0,0,0}
523 }; 472 };
524 473
525 /* no options were supplied */ 474 /* no options were supplied */
526 if(argc<2) return ERROR; 475 if (argc < 2) {
476 result.errorcode = ERROR;
477 return result;
478 }
527 479
528 /* backwards compatibility */ 480 /* backwards compatibility */
529 if (! is_option(argv[1])) { 481 if (!is_option(argv[1])) {
530 server_address = strdup(argv[1]); 482 result.config.server_address = strdup(argv[1]);
531 argv[1]=argv[0]; 483 argv[1] = argv[0];
532 argv=&argv[1]; 484 argv = &argv[1];
533 argc--; 485 argc--;
534 } 486 }
535 487
536 for (c=1;c<argc;c++) { 488 for (int index = 1; index < argc; index++) {
537 if(strcmp("-to",argv[c])==0) 489 if (strcmp("-to", argv[index]) == 0) {
538 strcpy(argv[c],"-t"); 490 strcpy(argv[index], "-t");
539 else if (strcmp("-wv",argv[c])==0) 491 } else if (strcmp("-wv", argv[index]) == 0) {
540 strcpy(argv[c],"-w"); 492 strcpy(argv[index], "-w");
541 else if (strcmp("-cv",argv[c])==0) 493 } else if (strcmp("-cv", argv[index]) == 0) {
542 strcpy(argv[c],"-c"); 494 strcpy(argv[index], "-c");
495 }
543 } 496 }
544 497
545 while (1) { 498 int option = 0;
546 c = getopt_long(argc,argv,"+hVH:t:c:w:p:v:l:s:d:u",longopts,&option); 499 while (true) {
500 int option_index = getopt_long(argc, argv, "+hVH:t:c:w:p:v:l:s:d:u", longopts, &option);
547 501
548 if (c==-1||c==EOF||c==1) 502 if (option_index == -1 || option_index == EOF || option_index == 1) {
549 break; 503 break;
504 }
550 505
551 switch (c) { 506 switch (option_index) {
552 case '?': /* print short usage statement if args not parsable */ 507 case '?': /* print short usage statement if args not parsable */
553 usage5 (); 508 usage5();
554 case 'h': /* help */ 509 case 'h': /* help */
555 print_help(); 510 print_help();
556 exit(STATE_UNKNOWN); 511 exit(STATE_UNKNOWN);
557 case 'V': /* version */ 512 case 'V': /* version */
558 print_revision(progname, NP_VERSION); 513 print_revision(progname, NP_VERSION);
559 exit(STATE_UNKNOWN); 514 exit(STATE_UNKNOWN);
560 case 'H': /* hostname */ 515 case 'H': /* hostname */
561 server_address = optarg; 516 result.config.server_address = optarg;
562 break; 517 break;
563 case 's': /* password */ 518 case 's': /* password */
564 req_password = optarg; 519 result.config.req_password = optarg;
565 break; 520 break;
566 case 'p': /* port */ 521 case 'p': /* port */
567 if (is_intnonneg(optarg)) 522 if (is_intnonneg(optarg)) {
568 server_port=atoi(optarg); 523 result.config.server_port = atoi(optarg);
569 else 524 } else {
570 die(STATE_UNKNOWN,_("Server port must be an integer\n")); 525 die(STATE_UNKNOWN, _("Server port must be an integer\n"));
571 break;
572 case 'v':
573 if(strlen(optarg)<4)
574 return ERROR;
575 if(!strcmp(optarg,"CLIENTVERSION"))
576 vars_to_check=CHECK_CLIENTVERSION;
577 else if(!strcmp(optarg,"CPULOAD"))
578 vars_to_check=CHECK_CPULOAD;
579 else if(!strcmp(optarg,"UPTIME"))
580 vars_to_check=CHECK_UPTIME;
581 else if(!strcmp(optarg,"USEDDISKSPACE"))
582 vars_to_check=CHECK_USEDDISKSPACE;
583 else if(!strcmp(optarg,"SERVICESTATE"))
584 vars_to_check=CHECK_SERVICESTATE;
585 else if(!strcmp(optarg,"PROCSTATE"))
586 vars_to_check=CHECK_PROCSTATE;
587 else if(!strcmp(optarg,"MEMUSE"))
588 vars_to_check=CHECK_MEMUSE;
589 else if(!strcmp(optarg,"COUNTER"))
590 vars_to_check=CHECK_COUNTER;
591 else if(!strcmp(optarg,"FILEAGE"))
592 vars_to_check=CHECK_FILEAGE;
593 else if(!strcmp(optarg,"INSTANCES"))
594 vars_to_check=CHECK_INSTANCES;
595 else
596 return ERROR;
597 break;
598 case 'l': /* value list */
599 value_list = optarg;
600 break;
601 case 'w': /* warning threshold */
602 warning_value=strtoul(optarg,NULL,10);
603 check_warning_value=true;
604 break;
605 case 'c': /* critical threshold */
606 critical_value=strtoul(optarg,NULL,10);
607 check_critical_value=true;
608 break;
609 case 'd': /* Display select for services */
610 if (!strcmp(optarg,"SHOWALL"))
611 show_all = true;
612 break;
613 case 'u':
614 socket_timeout_state=STATE_UNKNOWN;
615 break;
616 case 't': /* timeout */
617 socket_timeout=atoi(optarg);
618 if(socket_timeout<=0)
619 return ERROR;
620 } 526 }
621 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"));
622 } 587 }
623 if (server_address == NULL)
624 usage4 (_("You must provide a server address or host name"));
625 588
626 if (vars_to_check==CHECK_NONE) 589 if (result.config.vars_to_check == CHECK_NONE) {
627 return ERROR; 590 result.errorcode = ERROR;
591 return result;
592 }
628 593
629 if (req_password == NULL) 594 if (result.config.req_password == NULL) {
630 req_password = strdup (_("None")); 595 result.config.req_password = strdup(_("None"));
596 }
631 597
632 return OK; 598 return result;
633} 599}
634 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));
635 603
604 if (result != STATE_OK) {
605 die(result, _("could not fetch information from server\n"));
606 }
636 607
637void fetch_data (const char *address, int port, const char *sendb) { 608 if (!strncmp(recv_buffer, "ERROR", 5)) {
638 int result; 609 die(STATE_UNKNOWN, "NSClient - %s\n", recv_buffer);
639 610 }
640 result=process_tcp_request(address, port, sendb, recv_buffer,sizeof(recv_buffer));
641
642 if(result!=STATE_OK)
643 die (result, _("could not fetch information from server\n"));
644
645 if (!strncmp(recv_buffer,"ERROR",5))
646 die (STATE_UNKNOWN, "NSClient - %s\n",recv_buffer);
647} 611}
648 612
649bool strtoularray(unsigned long *array, char *string, const char *delim) { 613bool strtoularray(unsigned long *array, char *string, const char *delim) {
650 /* split a <delim> delimited string into a long array */ 614 /* split a <delim> delimited string into a long array */
651 int idx=0; 615 for (int idx = 0; idx < MAX_VALUE_LIST; idx++) {
652 char *t1; 616 array[idx] = 0;
653 617 }
654 for (idx=0;idx<MAX_VALUE_LIST;idx++)
655 array[idx]=0;
656 618
657 idx=0; 619 int idx = 0;
658 for(t1 = strtok(string,delim);t1 != NULL; t1 = strtok(NULL, delim)) { 620 for (char *t1 = strtok(string, delim); t1 != NULL; t1 = strtok(NULL, delim)) {
659 if (is_numeric(t1) && idx<MAX_VALUE_LIST) { 621 if (is_numeric(t1) && idx < MAX_VALUE_LIST) {
660 array[idx]=strtoul(t1,NULL,10); 622 array[idx] = strtoul(t1, NULL, 10);
661 idx++; 623 idx++;
662 } else 624 } else {
663 return false; 625 return false;
626 }
664 } 627 }
665 return true; 628 return true;
666} 629}
667 630
668void preparelist(char *string) { 631void preparelist(char *string) {
669 /* Replace all , with & which is the delimiter for the request */ 632 /* Replace all , with & which is the delimiter for the request */
670 int i; 633 for (int i = 0; (size_t)i < strlen(string); i++) {
671
672 for (i = 0; (size_t)i < strlen(string); i++)
673 if (string[i] == ',') { 634 if (string[i] == ',') {
674 string[i]='&'; 635 string[i] = '&';
675 } 636 }
637 }
676} 638}
677 639
678 640void print_help(void) {
679
680void print_help(void)
681{
682 print_revision(progname, NP_VERSION); 641 print_revision(progname, NP_VERSION);
683 642
684 printf ("Copyright (c) 2000 Yves Rubin (rubiyz@yahoo.com)\n"); 643 printf("Copyright (c) 2000 Yves Rubin (rubiyz@yahoo.com)\n");
685 printf (COPYRIGHT, copyright, email); 644 printf(COPYRIGHT, copyright, email);
686 645
687 printf ("%s\n", _("This plugin collects data from the NSClient service running on a")); 646 printf("%s\n", _("This plugin collects data from the NSClient service running on a"));
688 printf ("%s\n", _("Windows NT/2000/XP/2003 server.")); 647 printf("%s\n", _("Windows NT/2000/XP/2003 server."));
689 648
690 printf ("\n\n"); 649 printf("\n\n");
691 650
692 print_usage(); 651 print_usage();
693 652
694 printf (UT_HELP_VRSN); 653 printf(UT_HELP_VRSN);
695 printf (UT_EXTRA_OPTS); 654 printf(UT_EXTRA_OPTS);
696 655
697 printf ("%s\n", _("Options:")); 656 printf("%s\n", _("Options:"));
698 printf (" %s\n", "-H, --hostname=HOST"); 657 printf(" %s\n", "-H, --hostname=HOST");
699 printf (" %s\n", _("Name of the host to check")); 658 printf(" %s\n", _("Name of the host to check"));
700 printf (" %s\n", "-p, --port=INTEGER"); 659 printf(" %s\n", "-p, --port=INTEGER");
701 printf (" %s", _("Optional port number (default: ")); 660 printf(" %s", _("Optional port number (default: "));
702 printf ("%d)\n", PORT); 661 printf("%d)\n", PORT);
703 printf (" %s\n", "-s, --secret=<password>"); 662 printf(" %s\n", "-s, --secret=<password>");
704 printf (" %s\n", _("Password needed for the request")); 663 printf(" %s\n", _("Password needed for the request"));
705 printf (" %s\n", "-w, --warning=INTEGER"); 664 printf(" %s\n", "-w, --warning=INTEGER");
706 printf (" %s\n", _("Threshold which will result in a warning status")); 665 printf(" %s\n", _("Threshold which will result in a warning status"));
707 printf (" %s\n", "-c, --critical=INTEGER"); 666 printf(" %s\n", "-c, --critical=INTEGER");
708 printf (" %s\n", _("Threshold which will result in a critical status")); 667 printf(" %s\n", _("Threshold which will result in a critical status"));
709 printf (" %s\n", "-t, --timeout=INTEGER"); 668 printf(" %s\n", "-t, --timeout=INTEGER");
710 printf (" %s", _("Seconds before connection attempt times out (default: ")); 669 printf(" %s", _("Seconds before connection attempt times out (default: "));
711 printf (" %s\n", "-l, --params=<parameters>"); 670 printf(" %s\n", "-l, --params=<parameters>");
712 printf (" %s", _("Parameters passed to specified check (see below)")); 671 printf(" %s", _("Parameters passed to specified check (see below)"));
713 printf (" %s\n", "-d, --display={SHOWALL}"); 672 printf(" %s\n", "-d, --display={SHOWALL}");
714 printf (" %s", _("Display options (currently only SHOWALL works)")); 673 printf(" %s", _("Display options (currently only SHOWALL works)"));
715 printf (" %s\n", "-u, --unknown-timeout"); 674 printf(" %s\n", "-u, --unknown-timeout");
716 printf (" %s", _("Return UNKNOWN on timeouts")); 675 printf(" %s", _("Return UNKNOWN on timeouts"));
717 printf ("%d)\n", DEFAULT_SOCKET_TIMEOUT); 676 printf("%d)\n", DEFAULT_SOCKET_TIMEOUT);
718 printf (" %s\n", "-h, --help"); 677 printf(" %s\n", "-h, --help");
719 printf (" %s\n", _("Print this help screen")); 678 printf(" %s\n", _("Print this help screen"));
720 printf (" %s\n", "-V, --version"); 679 printf(" %s\n", "-V, --version");
721 printf (" %s\n", _("Print version information")); 680 printf(" %s\n", _("Print version information"));
722 printf (" %s\n", "-v, --variable=STRING"); 681 printf(" %s\n", "-v, --variable=STRING");
723 printf (" %s\n\n", _("Variable to check")); 682 printf(" %s\n\n", _("Variable to check"));
724 printf ("%s\n", _("Valid variables are:")); 683 printf("%s\n", _("Valid variables are:"));
725 printf (" %s", "CLIENTVERSION ="); 684 printf(" %s", "CLIENTVERSION =");
726 printf (" %s\n", _("Get the NSClient version")); 685 printf(" %s\n", _("Get the NSClient version"));
727 printf (" %s\n", _("If -l <version> is specified, will return warning if versions differ.")); 686 printf(" %s\n", _("If -l <version> is specified, will return warning if versions differ."));
728 printf (" %s\n", "CPULOAD ="); 687 printf(" %s\n", "CPULOAD =");
729 printf (" %s\n", _("Average CPU load on last x minutes.")); 688 printf(" %s\n", _("Average CPU load on last x minutes."));
730 printf (" %s\n", _("Request a -l parameter with the following syntax:")); 689 printf(" %s\n", _("Request a -l parameter with the following syntax:"));
731 printf (" %s\n", _("-l <minutes range>,<warning threshold>,<critical threshold>.")); 690 printf(" %s\n", _("-l <minutes range>,<warning threshold>,<critical threshold>."));
732 printf (" %s\n", _("<minute range> should be less than 24*60.")); 691 printf(" %s\n", _("<minute range> should be less than 24*60."));
733 printf (" %s\n", _("Thresholds are percentage and up to 10 requests can be done in one shot.")); 692 printf(" %s\n", _("Thresholds are percentage and up to 10 requests can be done in one shot."));
734 printf (" %s\n", "ie: -l 60,90,95,120,90,95"); 693 printf(" %s\n", "ie: -l 60,90,95,120,90,95");
735 printf (" %s\n", "UPTIME ="); 694 printf(" %s\n", "UPTIME =");
736 printf (" %s\n", _("Get the uptime of the machine.")); 695 printf(" %s\n", _("Get the uptime of the machine."));
737 printf (" %s\n", _("-l <unit> ")); 696 printf(" %s\n", _("-l <unit> "));
738 printf (" %s\n", _("<unit> = seconds, minutes, hours, or days. (default: minutes)")); 697 printf(" %s\n", _("<unit> = seconds, minutes, hours, or days. (default: minutes)"));
739 printf (" %s\n", _("Thresholds will use the unit specified above.")); 698 printf(" %s\n", _("Thresholds will use the unit specified above."));
740 printf (" %s\n", "USEDDISKSPACE ="); 699 printf(" %s\n", "USEDDISKSPACE =");
741 printf (" %s\n", _("Size and percentage of disk use.")); 700 printf(" %s\n", _("Size and percentage of disk use."));
742 printf (" %s\n", _("Request a -l parameter containing the drive letter only.")); 701 printf(" %s\n", _("Request a -l parameter containing the drive letter only."));
743 printf (" %s\n", _("Warning and critical thresholds can be specified with -w and -c.")); 702 printf(" %s\n", _("Warning and critical thresholds can be specified with -w and -c."));
744 printf (" %s\n", "MEMUSE ="); 703 printf(" %s\n", "MEMUSE =");
745 printf (" %s\n", _("Memory use.")); 704 printf(" %s\n", _("Memory use."));
746 printf (" %s\n", _("Warning and critical thresholds can be specified with -w and -c.")); 705 printf(" %s\n", _("Warning and critical thresholds can be specified with -w and -c."));
747 printf (" %s\n", "SERVICESTATE ="); 706 printf(" %s\n", "SERVICESTATE =");
748 printf (" %s\n", _("Check the state of one or several services.")); 707 printf(" %s\n", _("Check the state of one or several services."));
749 printf (" %s\n", _("Request a -l parameters with the following syntax:")); 708 printf(" %s\n", _("Request a -l parameters with the following syntax:"));
750 printf (" %s\n", _("-l <service1>,<service2>,<service3>,...")); 709 printf(" %s\n", _("-l <service1>,<service2>,<service3>,..."));
751 printf (" %s\n", _("You can specify -d SHOWALL in case you want to see working services")); 710 printf(" %s\n", _("You can specify -d SHOWALL in case you want to see working services"));
752 printf (" %s\n", _("in the returned string.")); 711 printf(" %s\n", _("in the returned string."));
753 printf (" %s\n", "PROCSTATE ="); 712 printf(" %s\n", "PROCSTATE =");
754 printf (" %s\n", _("Check if one or several process are running.")); 713 printf(" %s\n", _("Check if one or several process are running."));
755 printf (" %s\n", _("Same syntax as SERVICESTATE.")); 714 printf(" %s\n", _("Same syntax as SERVICESTATE."));
756 printf (" %s\n", "COUNTER ="); 715 printf(" %s\n", "COUNTER =");
757 printf (" %s\n", _("Check any performance counter of Windows NT/2000.")); 716 printf(" %s\n", _("Check any performance counter of Windows NT/2000."));
758 printf (" %s\n", _("Request a -l parameters with the following syntax:")); 717 printf(" %s\n", _("Request a -l parameters with the following syntax:"));
759 printf (" %s\n", _("-l \"\\\\<performance object>\\\\counter\",\"<description>")); 718 printf(" %s\n", _("-l \"\\\\<performance object>\\\\counter\",\"<description>"));
760 printf (" %s\n", _("The <description> parameter is optional and is given to a printf ")); 719 printf(" %s\n", _("The <description> parameter is optional and is given to a printf "));
761 printf (" %s\n", _("output command which requires a float parameter.")); 720 printf(" %s\n", _("output command which requires a float parameter."));
762 printf (" %s\n", _("If <description> does not include \"%%\", it is used as a label.")); 721 printf(" %s\n", _("If <description> does not include \"%%\", it is used as a label."));
763 printf (" %s\n", _("Some examples:")); 722 printf(" %s\n", _("Some examples:"));
764 printf (" %s\n", "\"Paging file usage is %%.2f %%%%\""); 723 printf(" %s\n", "\"Paging file usage is %%.2f %%%%\"");
765 printf (" %s\n", "\"%%.f %%%% paging file used.\""); 724 printf(" %s\n", "\"%%.f %%%% paging file used.\"");
766 printf (" %s\n", "INSTANCES ="); 725 printf(" %s\n", "INSTANCES =");
767 printf (" %s\n", _("Check any performance counter object of Windows NT/2000.")); 726 printf(" %s\n", _("Check any performance counter object of Windows NT/2000."));
768 printf (" %s\n", _("Syntax: check_nt -H <hostname> -p <port> -v INSTANCES -l <counter object>")); 727 printf(" %s\n", _("Syntax: check_nt -H <hostname> -p <port> -v INSTANCES -l <counter object>"));
769 printf (" %s\n", _("<counter object> is a Windows Perfmon Counter object (eg. Process),")); 728 printf(" %s\n", _("<counter object> is a Windows Perfmon Counter object (eg. Process),"));
770 printf (" %s\n", _("if it is two words, it should be enclosed in quotes")); 729 printf(" %s\n", _("if it is two words, it should be enclosed in quotes"));
771 printf (" %s\n", _("The returned results will be a comma-separated list of instances on ")); 730 printf(" %s\n", _("The returned results will be a comma-separated list of instances on "));
772 printf (" %s\n", _(" the selected computer for that object.")); 731 printf(" %s\n", _(" the selected computer for that object."));
773 printf (" %s\n", _("The purpose of this is to be run from command line to determine what instances")); 732 printf(" %s\n", _("The purpose of this is to be run from command line to determine what instances"));
774 printf (" %s\n", _(" are available for monitoring without having to log onto the Windows server")); 733 printf(" %s\n", _(" are available for monitoring without having to log onto the Windows server"));
775 printf (" %s\n", _(" to run Perfmon directly.")); 734 printf(" %s\n", _(" to run Perfmon directly."));
776 printf (" %s\n", _("It can also be used in scripts that automatically create the monitoring service")); 735 printf(" %s\n", _("It can also be used in scripts that automatically create the monitoring service"));
777 printf (" %s\n", _(" configuration files.")); 736 printf(" %s\n", _(" configuration files."));
778 printf (" %s\n", _("Some examples:")); 737 printf(" %s\n", _("Some examples:"));
779 printf (" %s\n\n", _("check_nt -H 192.168.1.1 -p 1248 -v INSTANCES -l Process")); 738 printf(" %s\n\n", _("check_nt -H 192.168.1.1 -p 1248 -v INSTANCES -l Process"));
780 739
781 printf ("%s\n", _("Notes:")); 740 printf("%s\n", _("Notes:"));
782 printf (" %s\n", _("- The NSClient service should be running on the server to get any information")); 741 printf(" %s\n", _("- The NSClient service should be running on the server to get any information"));
783 printf (" %s\n", "(http://nsclient.ready2run.nl)."); 742 printf(" %s\n", "(http://nsclient.ready2run.nl).");
784 printf (" %s\n", _("- Critical thresholds should be lower than warning thresholds")); 743 printf(" %s\n", _("- Critical thresholds should be lower than warning thresholds"));
785 printf (" %s\n", _("- Default port 1248 is sometimes in use by other services. The error")); 744 printf(" %s\n", _("- Default port 1248 is sometimes in use by other services. The error"));
786 printf (" %s\n", _("output when this happens contains \"Cannot map xxxxx to protocol number\".")); 745 printf(" %s\n", _("output when this happens contains \"Cannot map xxxxx to protocol number\"."));
787 printf (" %s\n", _("One fix for this is to change the port to something else on check_nt ")); 746 printf(" %s\n", _("One fix for this is to change the port to something else on check_nt "));
788 printf (" %s\n", _("and on the client service it\'s connecting to.")); 747 printf(" %s\n", _("and on the client service it\'s connecting to."));
789 748
790 printf (UT_SUPPORT); 749 printf(UT_SUPPORT);
791} 750}
792 751
793 752void print_usage(void) {
794 753 printf("%s\n", _("Usage:"));
795void print_usage(void) 754 printf("%s -H host -v variable [-p port] [-w warning] [-c critical]\n", progname);
796{ 755 printf("[-l params] [-d SHOWALL] [-u] [-t timeout]\n");
797 printf ("%s\n", _("Usage:"));
798 printf ("%s -H host -v variable [-p port] [-w warning] [-c critical]\n",progname);
799 printf ("[-l params] [-d SHOWALL] [-u] [-t timeout]\n");
800} 756}
801
diff --git a/plugins/check_nt.d/config.h b/plugins/check_nt.d/config.h
new file mode 100644
index 00000000..431889cb
--- /dev/null
+++ b/plugins/check_nt.d/config.h
@@ -0,0 +1,53 @@
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
index 61b2d699..d33f8786 100644
--- a/plugins/check_ntp.c
+++ b/plugins/check_ntp.c
@@ -4,7 +4,7 @@
4* 4*
5* License: GPL 5* License: GPL
6* Copyright (c) 2006 Sean Finney <seanius@seanius.net> 6* Copyright (c) 2006 Sean Finney <seanius@seanius.net>
7* Copyright (c) 2006-2008 Monitoring Plugins Development Team 7* Copyright (c) 2006-2024 Monitoring Plugins Development Team
8* 8*
9* Description: 9* Description:
10* 10*
@@ -31,7 +31,7 @@
31*****************************************************************************/ 31*****************************************************************************/
32 32
33const char *progname = "check_ntp"; 33const char *progname = "check_ntp";
34const char *copyright = "2006-2008"; 34const char *copyright = "2006-2024";
35const char *email = "devel@monitoring-plugins.org"; 35const char *email = "devel@monitoring-plugins.org";
36 36
37#include "common.h" 37#include "common.h"
@@ -47,10 +47,10 @@ static bool do_jitter = false;
47static char *jwarn="5000"; 47static char *jwarn="5000";
48static char *jcrit="10000"; 48static char *jcrit="10000";
49 49
50int process_arguments (int, char **); 50static int process_arguments (int /*argc*/, char ** /*argv*/);
51thresholds *offset_thresholds = NULL; 51static thresholds *offset_thresholds = NULL;
52thresholds *jitter_thresholds = NULL; 52static thresholds *jitter_thresholds = NULL;
53void print_help (void); 53static void print_help (void);
54void print_usage (void); 54void print_usage (void);
55 55
56/* number of times to perform each request to get a good average. */ 56/* number of times to perform each request to get a good average. */
diff --git a/plugins/check_ntp_peer.c b/plugins/check_ntp_peer.c
index 464a9e10..6e76bf23 100644
--- a/plugins/check_ntp_peer.c
+++ b/plugins/check_ntp_peer.c
@@ -1,88 +1,77 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_ntp_peer plugin 3 * Monitoring check_ntp_peer plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2006 Sean Finney <seanius@seanius.net> 6 * Copyright (c) 2006 Sean Finney <seanius@seanius.net>
7* Copyright (c) 2006-2008 Monitoring Plugins Development Team 7 * Copyright (c) 2006-2024 Monitoring Plugins Development Team
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains the check_ntp_peer plugin 11 * This file contains the check_ntp_peer plugin
12* 12 *
13* This plugin checks an NTP server independent of any commandline 13 * This plugin checks an NTP server independent of any commandline
14* programs or external libraries. 14 * programs or external libraries.
15* 15 *
16* Use this plugin to check the health of an NTP server. It supports 16 * Use this plugin to check the health of an NTP server. It supports
17* checking the offset with the sync peer, the jitter and stratum. This 17 * checking the offset with the sync peer, the jitter and stratum. This
18* plugin will not check the clock offset between the local host and NTP 18 * plugin will not check the clock offset between the local host and NTP
19* server; please use check_ntp_time for that purpose. 19 * server; please use check_ntp_time for that purpose.
20* 20 *
21* 21 *
22* This program is free software: you can redistribute it and/or modify 22 * This program is free software: you can redistribute it and/or modify
23* it under the terms of the GNU General Public License as published by 23 * it under the terms of the GNU General Public License as published by
24* the Free Software Foundation, either version 3 of the License, or 24 * the Free Software Foundation, either version 3 of the License, or
25* (at your option) any later version. 25 * (at your option) any later version.
26* 26 *
27* 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,
28* but WITHOUT ANY WARRANTY; without even the implied warranty of 28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30* GNU General Public License for more details. 30 * GNU General Public License for more details.
31* 31 *
32* You should have received a copy of the GNU General Public License 32 * You should have received a copy of the GNU General Public License
33* along with this program. If not, see <http://www.gnu.org/licenses/>. 33 * along with this program. If not, see <http://www.gnu.org/licenses/>.
34* 34 *
35* 35 *
36*****************************************************************************/ 36 *****************************************************************************/
37 37
38#include "thresholds.h"
38const char *progname = "check_ntp_peer"; 39const char *progname = "check_ntp_peer";
39const char *copyright = "2006-2008"; 40const char *copyright = "2006-2024";
40const char *email = "devel@monitoring-plugins.org"; 41const char *email = "devel@monitoring-plugins.org";
41 42
42#include "common.h" 43#include "common.h"
43#include "netutils.h" 44#include "netutils.h"
44#include "utils.h" 45#include "utils.h"
46#include "../lib/states.h"
47#include "check_ntp_peer.d/config.h"
45 48
46static char *server_address=NULL; 49static int verbose = 0;
47static int port=123;
48static int verbose=0;
49static bool quiet = false;
50static char *owarn="60";
51static char *ocrit="120";
52static bool do_stratum = false;
53static char *swarn="-1:16";
54static char *scrit="-1:16";
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; 50static bool syncsource_found = false;
62static bool li_alarm = false; 51static bool li_alarm = false;
63 52
64int process_arguments (int, char **); 53typedef struct {
65thresholds *offset_thresholds = NULL; 54 int errorcode;
66thresholds *jitter_thresholds = NULL; 55 check_ntp_peer_config config;
67thresholds *stratum_thresholds = NULL; 56} check_ntp_peer_config_wrapper;
68thresholds *truechimer_thresholds = NULL; 57static check_ntp_peer_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
69void print_help (void); 58static void print_help(void);
70void print_usage (void); 59void print_usage(void);
71 60
72/* max size of control message data */ 61/* max size of control message data */
73#define MAX_CM_SIZE 468 62#define MAX_CM_SIZE 468
74 63
75/* this structure holds everything in an ntp control message as per rfc1305 */ 64/* this structure holds everything in an ntp control message as per rfc1305 */
76typedef struct { 65typedef struct {
77 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ 66 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
78 uint8_t op; /* R,E,M bits and Opcode */ 67 uint8_t op; /* R,E,M bits and Opcode */
79 uint16_t seq; /* Packet sequence */ 68 uint16_t seq; /* Packet sequence */
80 uint16_t status; /* Clock status */ 69 uint16_t status; /* Clock status */
81 uint16_t assoc; /* Association */ 70 uint16_t assoc; /* Association */
82 uint16_t offset; /* Similar to TCP sequence # */ 71 uint16_t offset; /* Similar to TCP sequence # */
83 uint16_t count; /* # bytes of data */ 72 uint16_t count; /* # bytes of data */
84 char data[MAX_CM_SIZE]; /* ASCII data of the request */ 73 char data[MAX_CM_SIZE]; /* ASCII data of the request */
85 /* NB: not necessarily NULL terminated! */ 74 /* NB: not necessarily NULL terminated! */
86} ntp_control_message; 75} ntp_control_message;
87 76
88/* this is an association/status-word pair found in control packet responses */ 77/* this is an association/status-word pair found in control packet responses */
@@ -93,82 +82,96 @@ typedef struct {
93 82
94/* bits 1,2 are the leap indicator */ 83/* bits 1,2 are the leap indicator */
95#define LI_MASK 0xc0 84#define LI_MASK 0xc0
96#define LI(x) ((x&LI_MASK)>>6) 85#define LI(x) ((x & LI_MASK) >> 6)
97#define LI_SET(x,y) do{ x |= ((y<<6)&LI_MASK); }while(0) 86#define LI_SET(x, y) \
87 do { \
88 x |= ((y << 6) & LI_MASK); \
89 } while (0)
98/* and these are the values of the leap indicator */ 90/* and these are the values of the leap indicator */
99#define LI_NOWARNING 0x00 91#define LI_NOWARNING 0x00
100#define LI_EXTRASEC 0x01 92#define LI_EXTRASEC 0x01
101#define LI_MISSINGSEC 0x02 93#define LI_MISSINGSEC 0x02
102#define LI_ALARM 0x03 94#define LI_ALARM 0x03
103/* bits 3,4,5 are the ntp version */ 95/* bits 3,4,5 are the ntp version */
104#define VN_MASK 0x38 96#define VN_MASK 0x38
105#define VN(x) ((x&VN_MASK)>>3) 97#define VN(x) ((x & VN_MASK) >> 3)
106#define VN_SET(x,y) do{ x |= ((y<<3)&VN_MASK); }while(0) 98#define VN_SET(x, y) \
99 do { \
100 x |= ((y << 3) & VN_MASK); \
101 } while (0)
107#define VN_RESERVED 0x02 102#define VN_RESERVED 0x02
108/* bits 6,7,8 are the ntp mode */ 103/* bits 6,7,8 are the ntp mode */
109#define MODE_MASK 0x07 104#define MODE_MASK 0x07
110#define MODE(x) (x&MODE_MASK) 105#define MODE(x) (x & MODE_MASK)
111#define MODE_SET(x,y) do{ x |= (y&MODE_MASK); }while(0) 106#define MODE_SET(x, y) \
107 do { \
108 x |= (y & MODE_MASK); \
109 } while (0)
112/* here are some values */ 110/* here are some values */
113#define MODE_CLIENT 0x03 111#define MODE_CLIENT 0x03
114#define MODE_CONTROLMSG 0x06 112#define MODE_CONTROLMSG 0x06
115/* In control message, bits 8-10 are R,E,M bits */ 113/* In control message, bits 8-10 are R,E,M bits */
116#define REM_MASK 0xe0 114#define REM_MASK 0xe0
117#define REM_RESP 0x80 115#define REM_RESP 0x80
118#define REM_ERROR 0x40 116#define REM_ERROR 0x40
119#define REM_MORE 0x20 117#define REM_MORE 0x20
120/* In control message, bits 11 - 15 are opcode */ 118/* In control message, bits 11 - 15 are opcode */
121#define OP_MASK 0x1f 119#define OP_MASK 0x1f
122#define OP_SET(x,y) do{ x |= (y&OP_MASK); }while(0) 120#define OP_SET(x, y) \
121 do { \
122 x |= (y & OP_MASK); \
123 } while (0)
123#define OP_READSTAT 0x01 124#define OP_READSTAT 0x01
124#define OP_READVAR 0x02 125#define OP_READVAR 0x02
125/* In peer status bytes, bits 6,7,8 determine clock selection status */ 126/* In peer status bytes, bits 6,7,8 determine clock selection status */
126#define PEER_SEL(x) ((ntohs(x)>>8)&0x07) 127#define PEER_SEL(x) ((ntohs(x) >> 8) & 0x07)
127#define PEER_TRUECHIMER 0x02 128#define PEER_TRUECHIMER 0x02
128#define PEER_INCLUDED 0x04 129#define PEER_INCLUDED 0x04
129#define PEER_SYNCSOURCE 0x06 130#define PEER_SYNCSOURCE 0x06
130 131
131/* NTP control message header is 12 bytes, plus any data in the data 132/* NTP control message header is 12 bytes, plus any data in the data
132 * field, plus null padding to the nearest 32-bit boundary per rfc. 133 * field, plus null padding to the nearest 32-bit boundary per rfc.
133 */ 134 */
134#define SIZEOF_NTPCM(m) (12+ntohs(m.count)+((ntohs(m.count)%4)?4-(ntohs(m.count)%4):0)) 135#define SIZEOF_NTPCM(m) (12 + ntohs(m.count) + ((ntohs(m.count) % 4) ? 4 - (ntohs(m.count) % 4) : 0))
135 136
136/* finally, a little helper or two for debugging: */ 137/* finally, a little helper or two for debugging: */
137#define DBG(x) do{if(verbose>1){ x; }}while(0); 138#define DBG(x) \
138#define PRINTSOCKADDR(x) \ 139 do { \
139 do{ \ 140 if (verbose > 1) { \
140 printf("%u.%u.%u.%u", (x>>24)&0xff, (x>>16)&0xff, (x>>8)&0xff, x&0xff);\ 141 x; \
141 }while(0); 142 } \
142 143 } while (0);
143void print_ntp_control_message(const ntp_control_message *p){ 144#define PRINTSOCKADDR(x) \
144 int i=0, numpeers=0; 145 do { \
145 const ntp_assoc_status_pair *peer=NULL; 146 printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \
146 147 } while (0);
148
149void print_ntp_control_message(const ntp_control_message *message) {
147 printf("control packet contents:\n"); 150 printf("control packet contents:\n");
148 printf("\tflags: 0x%.2x , 0x%.2x\n", p->flags, p->op); 151 printf("\tflags: 0x%.2x , 0x%.2x\n", message->flags, message->op);
149 printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags&LI_MASK); 152 printf("\t li=%d (0x%.2x)\n", LI(message->flags), message->flags & LI_MASK);
150 printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags&VN_MASK); 153 printf("\t vn=%d (0x%.2x)\n", VN(message->flags), message->flags & VN_MASK);
151 printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags&MODE_MASK); 154 printf("\t mode=%d (0x%.2x)\n", MODE(message->flags), message->flags & MODE_MASK);
152 printf("\t response=%d (0x%.2x)\n", (p->op&REM_RESP)>0, p->op&REM_RESP); 155 printf("\t response=%d (0x%.2x)\n", (message->op & REM_RESP) > 0, message->op & REM_RESP);
153 printf("\t more=%d (0x%.2x)\n", (p->op&REM_MORE)>0, p->op&REM_MORE); 156 printf("\t more=%d (0x%.2x)\n", (message->op & REM_MORE) > 0, message->op & REM_MORE);
154 printf("\t error=%d (0x%.2x)\n", (p->op&REM_ERROR)>0, p->op&REM_ERROR); 157 printf("\t error=%d (0x%.2x)\n", (message->op & REM_ERROR) > 0, message->op & REM_ERROR);
155 printf("\t op=%d (0x%.2x)\n", p->op&OP_MASK, p->op&OP_MASK); 158 printf("\t op=%d (0x%.2x)\n", message->op & OP_MASK, message->op & OP_MASK);
156 printf("\tsequence: %d (0x%.2x)\n", ntohs(p->seq), ntohs(p->seq)); 159 printf("\tsequence: %d (0x%.2x)\n", ntohs(message->seq), ntohs(message->seq));
157 printf("\tstatus: %d (0x%.2x)\n", ntohs(p->status), ntohs(p->status)); 160 printf("\tstatus: %d (0x%.2x)\n", ntohs(message->status), ntohs(message->status));
158 printf("\tassoc: %d (0x%.2x)\n", ntohs(p->assoc), ntohs(p->assoc)); 161 printf("\tassoc: %d (0x%.2x)\n", ntohs(message->assoc), ntohs(message->assoc));
159 printf("\toffset: %d (0x%.2x)\n", ntohs(p->offset), ntohs(p->offset)); 162 printf("\toffset: %d (0x%.2x)\n", ntohs(message->offset), ntohs(message->offset));
160 printf("\tcount: %d (0x%.2x)\n", ntohs(p->count), ntohs(p->count)); 163 printf("\tcount: %d (0x%.2x)\n", ntohs(message->count), ntohs(message->count));
161 numpeers=ntohs(p->count)/(sizeof(ntp_assoc_status_pair)); 164
162 if(p->op&REM_RESP && p->op&OP_READSTAT){ 165 int numpeers = ntohs(message->count) / (sizeof(ntp_assoc_status_pair));
163 peer=(ntp_assoc_status_pair*)p->data; 166 if (message->op & REM_RESP && message->op & OP_READSTAT) {
164 for(i=0;i<numpeers;i++){ 167 const ntp_assoc_status_pair *peer = (ntp_assoc_status_pair *)message->data;
165 printf("\tpeer id %.2x status %.2x", 168 for (int i = 0; i < numpeers; i++) {
166 ntohs(peer[i].assoc), ntohs(peer[i].status)); 169 printf("\tpeer id %.2x status %.2x", ntohs(peer[i].assoc), ntohs(peer[i].status));
167 if(PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE){ 170 if (PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE) {
168 printf(" <-- current sync source"); 171 printf(" <-- current sync source");
169 } else if(PEER_SEL(peer[i].status) >= PEER_INCLUDED){ 172 } else if (PEER_SEL(peer[i].status) >= PEER_INCLUDED) {
170 printf(" <-- current sync candidate"); 173 printf(" <-- current sync candidate");
171 } else if(PEER_SEL(peer[i].status) >= PEER_TRUECHIMER){ 174 } else if (PEER_SEL(peer[i].status) >= PEER_TRUECHIMER) {
172 printf(" <-- outlyer, but truechimer"); 175 printf(" <-- outlyer, but truechimer");
173 } 176 }
174 printf("\n"); 177 printf("\n");
@@ -176,14 +179,13 @@ void print_ntp_control_message(const ntp_control_message *p){
176 } 179 }
177} 180}
178 181
179void 182void setup_control_request(ntp_control_message *message, uint8_t opcode, uint16_t seq) {
180setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq){ 183 memset(message, 0, sizeof(ntp_control_message));
181 memset(p, 0, sizeof(ntp_control_message)); 184 LI_SET(message->flags, LI_NOWARNING);
182 LI_SET(p->flags, LI_NOWARNING); 185 VN_SET(message->flags, VN_RESERVED);
183 VN_SET(p->flags, VN_RESERVED); 186 MODE_SET(message->flags, MODE_CONTROLMSG);
184 MODE_SET(p->flags, MODE_CONTROLMSG); 187 OP_SET(message->op, opcode);
185 OP_SET(p->op, opcode); 188 message->seq = htons(seq);
186 p->seq = htons(seq);
187 /* Remaining fields are zero for requests */ 189 /* Remaining fields are zero for requests */
188} 190}
189 191
@@ -198,22 +200,23 @@ setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq){
198 * status is pretty much useless as syncsource_found is a global variable 200 * status is pretty much useless as syncsource_found is a global variable
199 * used later in main to check is the server was synchronized. It works 201 * used later in main to check is the server was synchronized. It works
200 * so I left it alone */ 202 * so I left it alone */
201int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum, int *num_truechimers){ 203typedef struct {
202 int conn=-1, i, npeers=0, num_candidates=0; 204 mp_state_enum state;
203 double tmp_offset = 0; 205 mp_state_enum offset_result;
204 int min_peer_sel=PEER_INCLUDED; 206 double offset;
205 int peers_size=0, peer_offset=0; 207 double jitter;
206 int status; 208 long stratum;
207 ntp_assoc_status_pair *peers=NULL; 209 int num_truechimers;
208 ntp_control_message req; 210} ntp_request_result;
209 const char *getvar = "stratum,offset,jitter"; 211ntp_request_result ntp_request(const check_ntp_peer_config config) {
210 char *data, *value, *nptr; 212
211 void *tmp; 213 ntp_request_result result = {
212 214 .state = STATE_OK,
213 status = STATE_OK; 215 .offset_result = STATE_UNKNOWN,
214 *offset_result = STATE_UNKNOWN; 216 .jitter = -1,
215 *jitter = *stratum = -1; 217 .stratum = -1,
216 *num_truechimers = 0; 218 .num_truechimers = 0,
219 };
217 220
218 /* Long-winded explanation: 221 /* Long-winded explanation:
219 * Getting the sync peer offset, jitter and stratum requires a number of 222 * Getting the sync peer offset, jitter and stratum requires a number of
@@ -231,11 +234,20 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
231 * 4) Extract the offset, jitter and stratum value from the data[] 234 * 4) Extract the offset, jitter and stratum value from the data[]
232 * (it's ASCII) 235 * (it's ASCII)
233 */ 236 */
234 my_udp_connect(server_address, port, &conn); 237 int min_peer_sel = PEER_INCLUDED;
238 int num_candidates = 0;
239 void *tmp;
240 ntp_assoc_status_pair *peers = NULL;
241 int peer_offset = 0;
242 size_t peers_size = 0;
243 size_t npeers = 0;
244 int conn = -1;
245 my_udp_connect(config.server_address, config.port, &conn);
235 246
236 /* keep sending requests until the server stops setting the 247 /* keep sending requests until the server stops setting the
237 * REM_MORE bit, though usually this is only 1 packet. */ 248 * REM_MORE bit, though usually this is only 1 packet. */
238 do{ 249 ntp_control_message req;
250 do {
239 setup_control_request(&req, OP_READSTAT, 1); 251 setup_control_request(&req, OP_READSTAT, 1);
240 DBG(printf("sending READSTAT request")); 252 DBG(printf("sending READSTAT request"));
241 write(conn, &req, SIZEOF_NTPCM(req)); 253 write(conn, &req, SIZEOF_NTPCM(req));
@@ -243,63 +255,81 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
243 255
244 do { 256 do {
245 /* Attempt to read the largest size packet possible */ 257 /* Attempt to read the largest size packet possible */
246 req.count=htons(MAX_CM_SIZE); 258 req.count = htons(MAX_CM_SIZE);
247 DBG(printf("receiving READSTAT response")) 259 DBG(printf("receiving READSTAT response"))
248 if(read(conn, &req, SIZEOF_NTPCM(req)) == -1) 260 if (read(conn, &req, SIZEOF_NTPCM(req)) == -1) {
249 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); 261 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
262 }
250 DBG(print_ntp_control_message(&req)); 263 DBG(print_ntp_control_message(&req));
251 /* discard obviously invalid packets */ 264 /* discard obviously invalid packets */
252 if (ntohs(req.count) > MAX_CM_SIZE) 265 if (ntohs(req.count) > MAX_CM_SIZE) {
253 die(STATE_CRITICAL, "NTP CRITICAL: Invalid packet received from NTP server\n"); 266 die(STATE_CRITICAL, "NTP CRITICAL: Invalid packet received from NTP server\n");
254 } while (!(req.op&OP_READSTAT && ntohs(req.seq) == 1)); 267 }
268 } while (!(req.op & OP_READSTAT && ntohs(req.seq) == 1));
255 269
256 if (LI(req.flags) == LI_ALARM) li_alarm = true; 270 if (LI(req.flags) == LI_ALARM) {
271 li_alarm = true;
272 }
257 /* Each peer identifier is 4 bytes in the data section, which 273 /* Each peer identifier is 4 bytes in the data section, which
258 * we represent as a ntp_assoc_status_pair datatype. 274 * we represent as a ntp_assoc_status_pair datatype.
259 */ 275 */
260 peers_size+=ntohs(req.count); 276 peers_size += ntohs(req.count);
261 if((tmp=realloc(peers, peers_size)) == NULL) 277 if ((tmp = realloc(peers, peers_size)) == NULL) {
262 free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n"); 278 free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n");
263 peers=tmp; 279 }
264 memcpy((void*)((ptrdiff_t)peers+peer_offset), (void*)req.data, ntohs(req.count)); 280 peers = tmp;
265 npeers=peers_size/sizeof(ntp_assoc_status_pair); 281 memcpy((peers + peer_offset), (void *)req.data, ntohs(req.count));
266 peer_offset+=ntohs(req.count); 282 npeers = peers_size / sizeof(ntp_assoc_status_pair);
267 } while(req.op&REM_MORE); 283 peer_offset += ntohs(req.count);
284 } while (req.op & REM_MORE);
268 285
269 /* first, let's find out if we have a sync source, or if there are 286 /* first, let's find out if we have a sync source, or if there are
270 * at least some candidates. In the latter case we'll issue 287 * at least some candidates. In the latter case we'll issue
271 * a warning but go ahead with the check on them. */ 288 * a warning but go ahead with the check on them. */
272 for (i = 0; i < npeers; i++){ 289 for (size_t i = 0; i < npeers; i++) {
273 if(PEER_SEL(peers[i].status) >= PEER_TRUECHIMER){ 290 if (PEER_SEL(peers[i].status) >= PEER_TRUECHIMER) {
274 (*num_truechimers)++; 291 result.num_truechimers++;
275 if(PEER_SEL(peers[i].status) >= PEER_INCLUDED){ 292 if (PEER_SEL(peers[i].status) >= PEER_INCLUDED) {
276 num_candidates++; 293 num_candidates++;
277 if(PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE){ 294 if (PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE) {
278 syncsource_found = true; 295 syncsource_found = true;
279 min_peer_sel=PEER_SYNCSOURCE; 296 min_peer_sel = PEER_SYNCSOURCE;
280 } 297 }
281 } 298 }
282 } 299 }
283 } 300 }
284 if(verbose) printf("%d candidate peers available\n", num_candidates); 301
285 if(verbose && syncsource_found) printf("synchronization source found\n"); 302 if (verbose) {
286 if(! syncsource_found){ 303 printf("%d candidate peers available\n", num_candidates);
287 status = STATE_WARNING;
288 if(verbose) printf("warning: no synchronization source found\n");
289 } 304 }
290 if(li_alarm){ 305 if (verbose && syncsource_found) {
291 status = STATE_WARNING; 306 printf("synchronization source found\n");
292 if(verbose) printf("warning: LI_ALARM bit is set\n");
293 } 307 }
294 308
309 if (!syncsource_found) {
310 result.state = STATE_WARNING;
311 if (verbose) {
312 printf("warning: no synchronization source found\n");
313 }
314 }
315 if (li_alarm) {
316 result.state = STATE_WARNING;
317 if (verbose) {
318 printf("warning: LI_ALARM bit is set\n");
319 }
320 }
295 321
296 for (i = 0; i < npeers; i++){ 322 const char *getvar = "stratum,offset,jitter";
323 char *data;
324 for (size_t i = 0; i < npeers; i++) {
297 /* Only query this server if it is the current sync source */ 325 /* Only query this server if it is the current sync source */
298 /* If there's no sync.peer, query all candidates and use the best one */ 326 /* If there's no sync.peer, query all candidates and use the best one */
299 if (PEER_SEL(peers[i].status) >= min_peer_sel){ 327 if (PEER_SEL(peers[i].status) >= min_peer_sel) {
300 if(verbose) printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc)); 328 if (verbose) {
329 printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc));
330 }
301 xasprintf(&data, ""); 331 xasprintf(&data, "");
302 do{ 332 do {
303 setup_control_request(&req, OP_READVAR, 2); 333 setup_control_request(&req, OP_READVAR, 2);
304 req.assoc = peers[i].assoc; 334 req.assoc = peers[i].assoc;
305 /* Putting the wanted variable names in the request 335 /* Putting the wanted variable names in the request
@@ -309,7 +339,7 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
309 */ 339 */
310 /* Older servers doesn't know what jitter is, so if we get an 340 /* Older servers doesn't know what jitter is, so if we get an
311 * error on the first pass we redo it with "dispersion" */ 341 * error on the first pass we redo it with "dispersion" */
312 strncpy(req.data, getvar, MAX_CM_SIZE-1); 342 strncpy(req.data, getvar, MAX_CM_SIZE - 1);
313 req.count = htons(strlen(getvar)); 343 req.count = htons(strlen(getvar));
314 DBG(printf("sending READVAR request...\n")); 344 DBG(printf("sending READVAR request...\n"));
315 write(conn, &req, SIZEOF_NTPCM(req)); 345 write(conn, &req, SIZEOF_NTPCM(req));
@@ -320,131 +350,151 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
320 DBG(printf("receiving READVAR response...\n")); 350 DBG(printf("receiving READVAR response...\n"));
321 read(conn, &req, SIZEOF_NTPCM(req)); 351 read(conn, &req, SIZEOF_NTPCM(req));
322 DBG(print_ntp_control_message(&req)); 352 DBG(print_ntp_control_message(&req));
323 } while (!(req.op&OP_READVAR && ntohs(req.seq) == 2)); 353 } while (!(req.op & OP_READVAR && ntohs(req.seq) == 2));
324 354
325 if(!(req.op&REM_ERROR)) 355 if (!(req.op & REM_ERROR)) {
326 xasprintf(&data, "%s%s", data, req.data); 356 xasprintf(&data, "%s%s", data, req.data);
327 } while(req.op&REM_MORE); 357 }
328 358 } while (req.op & REM_MORE);
329 if(req.op&REM_ERROR) { 359
330 if(strstr(getvar, "jitter")) { 360 if (req.op & REM_ERROR) {
331 if(verbose) printf("The command failed. This is usually caused by servers refusing the 'jitter'\nvariable. Restarting with 'dispersion'...\n"); 361 if (strstr(getvar, "jitter")) {
362 if (verbose) {
363 printf("The command failed. This is usually caused by servers refusing the 'jitter'\nvariable. Restarting with "
364 "'dispersion'...\n");
365 }
332 getvar = "stratum,offset,dispersion"; 366 getvar = "stratum,offset,dispersion";
333 i--; 367 i--;
334 continue; 368 continue;
335 } else if(strlen(getvar)) { 369 }
336 if(verbose) printf("Server didn't like dispersion either; will retrieve everything\n"); 370 if (strlen(getvar)) {
371 if (verbose) {
372 printf("Server didn't like dispersion either; will retrieve everything\n");
373 }
337 getvar = ""; 374 getvar = "";
338 i--; 375 i--;
339 continue; 376 continue;
340 } 377 }
341 } 378 }
342 379
343 if(verbose > 1) 380 if (verbose > 1) {
344 printf("Server responded: >>>%s<<<\n", data); 381 printf("Server responded: >>>%s<<<\n", data);
382 }
345 383
384 double tmp_offset = 0;
385 char *value;
386 char *nptr;
346 /* get the offset */ 387 /* get the offset */
347 if(verbose) 388 if (verbose) {
348 printf("parsing offset from peer %.2x: ", ntohs(peers[i].assoc)); 389 printf("parsing offset from peer %.2x: ", ntohs(peers[i].assoc));
390 }
349 391
350 value = np_extract_ntpvar(data, "offset"); 392 value = np_extract_ntpvar(data, "offset");
351 nptr=NULL; 393 nptr = NULL;
352 /* Convert the value if we have one */ 394 /* Convert the value if we have one */
353 if(value != NULL) 395 if (value != NULL) {
354 tmp_offset = strtod(value, &nptr) / 1000; 396 tmp_offset = strtod(value, &nptr) / 1000;
397 }
355 /* If value is null or no conversion was performed */ 398 /* If value is null or no conversion was performed */
356 if(value == NULL || value==nptr) { 399 if (value == NULL || value == nptr) {
357 if(verbose) printf("error: unable to read server offset response.\n"); 400 if (verbose) {
401 printf("error: unable to read server offset response.\n");
402 }
358 } else { 403 } else {
359 if(verbose) printf("%.10g\n", tmp_offset); 404 if (verbose) {
360 if(*offset_result == STATE_UNKNOWN || fabs(tmp_offset) < fabs(*offset)) { 405 printf("%.10g\n", tmp_offset);
361 *offset = tmp_offset; 406 }
362 *offset_result = STATE_OK; 407 if (result.offset_result == STATE_UNKNOWN || fabs(tmp_offset) < fabs(result.offset)) {
408 result.offset = tmp_offset;
409 result.offset_result = STATE_OK;
363 } else { 410 } else {
364 /* Skip this one; move to the next */ 411 /* Skip this one; move to the next */
365 continue; 412 continue;
366 } 413 }
367 } 414 }
368 415
369 if(do_jitter) { 416 if (config.do_jitter) {
370 /* get the jitter */ 417 /* get the jitter */
371 if(verbose) { 418 if (verbose) {
372 printf("parsing %s from peer %.2x: ", strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter", ntohs(peers[i].assoc)); 419 printf("parsing %s from peer %.2x: ", strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter",
420 ntohs(peers[i].assoc));
373 } 421 }
374 value = np_extract_ntpvar(data, strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter"); 422 value = np_extract_ntpvar(data, strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter");
375 nptr=NULL; 423 nptr = NULL;
376 /* Convert the value if we have one */ 424 /* Convert the value if we have one */
377 if(value != NULL) 425 if (value != NULL) {
378 *jitter = strtod(value, &nptr); 426 result.jitter = strtod(value, &nptr);
427 }
379 /* If value is null or no conversion was performed */ 428 /* If value is null or no conversion was performed */
380 if(value == NULL || value==nptr) { 429 if (value == NULL || value == nptr) {
381 if(verbose) printf("error: unable to read server jitter/dispersion response.\n"); 430 if (verbose) {
382 *jitter = -1; 431 printf("error: unable to read server jitter/dispersion response.\n");
383 } else if(verbose) { 432 }
384 printf("%.10g\n", *jitter); 433 result.jitter = -1;
434 } else if (verbose) {
435 printf("%.10g\n", result.jitter);
385 } 436 }
386 } 437 }
387 438
388 if(do_stratum) { 439 if (config.do_stratum) {
389 /* get the stratum */ 440 /* get the stratum */
390 if(verbose) { 441 if (verbose) {
391 printf("parsing stratum from peer %.2x: ", ntohs(peers[i].assoc)); 442 printf("parsing stratum from peer %.2x: ", ntohs(peers[i].assoc));
392 } 443 }
393 value = np_extract_ntpvar(data, "stratum"); 444 value = np_extract_ntpvar(data, "stratum");
394 nptr=NULL; 445 nptr = NULL;
395 /* Convert the value if we have one */ 446 /* Convert the value if we have one */
396 if(value != NULL) 447 if (value != NULL) {
397 *stratum = strtol(value, &nptr, 10); 448 result.stratum = strtol(value, &nptr, 10);
398 if(value == NULL || value==nptr) { 449 }
399 if(verbose) printf("error: unable to read server stratum response.\n"); 450 if (value == NULL || value == nptr) {
400 *stratum = -1; 451 if (verbose) {
452 printf("error: unable to read server stratum response.\n");
453 }
454 result.stratum = -1;
401 } else { 455 } else {
402 if(verbose) printf("%i\n", *stratum); 456 if (verbose) {
457 printf("%li\n", result.stratum);
458 }
403 } 459 }
404 } 460 }
405 } /* if (PEER_SEL(peers[i].status) >= min_peer_sel) */ 461 } /* if (PEER_SEL(peers[i].status) >= min_peer_sel) */
406 } /* for (i = 0; i < npeers; i++) */ 462 } /* for (i = 0; i < npeers; i++) */
407 463
408 close(conn); 464 close(conn);
409 if(peers!=NULL) free(peers); 465 if (peers != NULL) {
466 free(peers);
467 }
410 468
411 return status; 469 return result;
412} 470}
413 471
414int process_arguments(int argc, char **argv){ 472check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) {
415 int c;
416 int option=0;
417 static struct option longopts[] = { 473 static struct option longopts[] = {
418 {"version", no_argument, 0, 'V'}, 474 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"verbose", no_argument, 0, 'v'},
419 {"help", no_argument, 0, 'h'}, 475 {"use-ipv4", no_argument, 0, '4'}, {"use-ipv6", no_argument, 0, '6'}, {"quiet", no_argument, 0, 'q'},
420 {"verbose", no_argument, 0, 'v'}, 476 {"warning", required_argument, 0, 'w'}, {"critical", required_argument, 0, 'c'}, {"swarn", required_argument, 0, 'W'},
421 {"use-ipv4", no_argument, 0, '4'}, 477 {"scrit", required_argument, 0, 'C'}, {"jwarn", required_argument, 0, 'j'}, {"jcrit", required_argument, 0, 'k'},
422 {"use-ipv6", no_argument, 0, '6'}, 478 {"twarn", required_argument, 0, 'm'}, {"tcrit", required_argument, 0, 'n'}, {"timeout", required_argument, 0, 't'},
423 {"quiet", no_argument, 0, 'q'}, 479 {"hostname", required_argument, 0, 'H'}, {"port", required_argument, 0, 'p'}, {0, 0, 0, 0}};
424 {"warning", required_argument, 0, 'w'}, 480
425 {"critical", required_argument, 0, 'c'}, 481 if (argc < 2) {
426 {"swarn", required_argument, 0, 'W'}, 482 usage("\n");
427 {"scrit", required_argument, 0, 'C'}, 483 }
428 {"jwarn", required_argument, 0, 'j'},
429 {"jcrit", required_argument, 0, 'k'},
430 {"twarn", required_argument, 0, 'm'},
431 {"tcrit", required_argument, 0, 'n'},
432 {"timeout", required_argument, 0, 't'},
433 {"hostname", required_argument, 0, 'H'},
434 {"port", required_argument, 0, 'p'},
435 {0, 0, 0, 0}
436 };
437
438 484
439 if (argc < 2) 485 check_ntp_peer_config_wrapper result = {
440 usage ("\n"); 486 .errorcode = OK,
487 .config = check_ntp_peer_config_init(),
488 };
441 489
442 while (true) { 490 while (true) {
443 c = getopt_long (argc, argv, "Vhv46qw:c:W:C:j:k:m:n:t:H:p:", longopts, &option); 491 int option = 0;
444 if (c == -1 || c == EOF || c == 1) 492 int option_char = getopt_long(argc, argv, "Vhv46qw:c:W:C:j:k:m:n:t:H:p:", longopts, &option);
493 if (option_char == -1 || option_char == EOF || option_char == 1) {
445 break; 494 break;
495 }
446 496
447 switch (c) { 497 switch (option_char) {
448 case 'h': 498 case 'h':
449 print_help(); 499 print_help();
450 exit(STATE_UNKNOWN); 500 exit(STATE_UNKNOWN);
@@ -457,48 +507,49 @@ int process_arguments(int argc, char **argv){
457 verbose++; 507 verbose++;
458 break; 508 break;
459 case 'q': 509 case 'q':
460 quiet = true; 510 result.config.quiet = true;
461 break; 511 break;
462 case 'w': 512 case 'w':
463 owarn = optarg; 513 result.config.owarn = optarg;
464 break; 514 break;
465 case 'c': 515 case 'c':
466 ocrit = optarg; 516 result.config.ocrit = optarg;
467 break; 517 break;
468 case 'W': 518 case 'W':
469 do_stratum = true; 519 result.config.do_stratum = true;
470 swarn = optarg; 520 result.config.swarn = optarg;
471 break; 521 break;
472 case 'C': 522 case 'C':
473 do_stratum = true; 523 result.config.do_stratum = true;
474 scrit = optarg; 524 result.config.scrit = optarg;
475 break; 525 break;
476 case 'j': 526 case 'j':
477 do_jitter = true; 527 result.config.do_jitter = true;
478 jwarn = optarg; 528 result.config.jwarn = optarg;
479 break; 529 break;
480 case 'k': 530 case 'k':
481 do_jitter = true; 531 result.config.do_jitter = true;
482 jcrit = optarg; 532 result.config.jcrit = optarg;
483 break; 533 break;
484 case 'm': 534 case 'm':
485 do_truechimers = true; 535 result.config.do_truechimers = true;
486 twarn = optarg; 536 result.config.twarn = optarg;
487 break; 537 break;
488 case 'n': 538 case 'n':
489 do_truechimers = true; 539 result.config.do_truechimers = true;
490 tcrit = optarg; 540 result.config.tcrit = optarg;
491 break; 541 break;
492 case 'H': 542 case 'H':
493 if(!is_host(optarg)) 543 if (!is_host(optarg)) {
494 usage2(_("Invalid hostname/address"), optarg); 544 usage2(_("Invalid hostname/address"), optarg);
495 server_address = strdup(optarg); 545 }
546 result.config.server_address = strdup(optarg);
496 break; 547 break;
497 case 'p': 548 case 'p':
498 port=atoi(optarg); 549 result.config.port = atoi(optarg);
499 break; 550 break;
500 case 't': 551 case 't':
501 socket_timeout=atoi(optarg); 552 socket_timeout = atoi(optarg);
502 break; 553 break;
503 case '4': 554 case '4':
504 address_family = AF_INET; 555 address_family = AF_INET;
@@ -507,222 +558,220 @@ int process_arguments(int argc, char **argv){
507#ifdef USE_IPV6 558#ifdef USE_IPV6
508 address_family = AF_INET6; 559 address_family = AF_INET6;
509#else 560#else
510 usage4 (_("IPv6 support not available")); 561 usage4(_("IPv6 support not available"));
511#endif 562#endif
512 break; 563 break;
513 case '?': 564 case '?':
514 /* print short usage statement if args not parsable */ 565 /* print short usage statement if args not parsable */
515 usage5 (); 566 usage5();
516 break; 567 break;
517 } 568 }
518 } 569 }
519 570
520 if(server_address == NULL){ 571 if (result.config.server_address == NULL) {
521 usage4(_("Hostname was not supplied")); 572 usage4(_("Hostname was not supplied"));
522 } 573 }
523 574
524 return 0; 575 set_thresholds(&result.config.offset_thresholds, result.config.owarn, result.config.ocrit);
525} 576 set_thresholds(&result.config.jitter_thresholds, result.config.jwarn, result.config.jcrit);
577 set_thresholds(&result.config.stratum_thresholds, result.config.swarn, result.config.scrit);
578 set_thresholds(&result.config.truechimer_thresholds, result.config.twarn, result.config.tcrit);
526 579
527char *perfd_offset (double offset) 580 return result;
528{
529 return fperfdata ("offset", offset, "s",
530 true, offset_thresholds->warning->end,
531 true, offset_thresholds->critical->end,
532 false, 0, false, 0);
533} 581}
534 582
535char *perfd_jitter (double jitter) 583char *perfd_offset(double offset, thresholds *offset_thresholds) {
536{ 584 return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true, offset_thresholds->critical->end, false, 0, false,
537 return fperfdata ("jitter", jitter, "", 585 0);
538 do_jitter, jitter_thresholds->warning->end,
539 do_jitter, jitter_thresholds->critical->end,
540 true, 0, false, 0);
541} 586}
542 587
543char *perfd_stratum (int stratum) 588char *perfd_jitter(double jitter, bool do_jitter, thresholds *jitter_thresholds) {
544{ 589 return fperfdata("jitter", jitter, "", do_jitter, jitter_thresholds->warning->end, do_jitter, jitter_thresholds->critical->end, true, 0,
545 return perfdata ("stratum", stratum, "", 590 false, 0);
546 do_stratum, (int)stratum_thresholds->warning->end,
547 do_stratum, (int)stratum_thresholds->critical->end,
548 true, 0, true, 16);
549} 591}
550 592
551char *perfd_truechimers (int num_truechimers) 593char *perfd_stratum(int stratum, bool do_stratum, thresholds *stratum_thresholds) {
552{ 594 return perfdata("stratum", stratum, "", do_stratum, (int)stratum_thresholds->warning->end, do_stratum,
553 return perfdata ("truechimers", num_truechimers, "", 595 (int)stratum_thresholds->critical->end, true, 0, true, 16);
554 do_truechimers, (int)truechimer_thresholds->warning->end,
555 do_truechimers, (int)truechimer_thresholds->critical->end,
556 true, 0, false, 0);
557} 596}
558 597
559int main(int argc, char *argv[]){ 598char *perfd_truechimers(int num_truechimers, const bool do_truechimers, thresholds *truechimer_thresholds) {
560 int result, offset_result, stratum, num_truechimers; 599 return perfdata("truechimers", num_truechimers, "", do_truechimers, (int)truechimer_thresholds->warning->end, do_truechimers,
561 double offset=0, jitter=0; 600 (int)truechimer_thresholds->critical->end, true, 0, false, 0);
562 char *result_line, *perfdata_line; 601}
563 602
564 setlocale (LC_ALL, ""); 603int main(int argc, char *argv[]) {
565 bindtextdomain (PACKAGE, LOCALEDIR); 604 setlocale(LC_ALL, "");
566 textdomain (PACKAGE); 605 bindtextdomain(PACKAGE, LOCALEDIR);
606 textdomain(PACKAGE);
567 607
568 /* Parse extra opts if any */ 608 /* Parse extra opts if any */
569 argv=np_extra_opts (&argc, argv, progname); 609 argv = np_extra_opts(&argc, argv, progname);
570 610
571 if (process_arguments (argc, argv) == ERROR) 611 check_ntp_peer_config_wrapper tmp_config = process_arguments(argc, argv);
572 usage4 (_("Could not parse arguments"));
573 612
574 set_thresholds(&offset_thresholds, owarn, ocrit); 613 if (tmp_config.errorcode == ERROR) {
575 set_thresholds(&jitter_thresholds, jwarn, jcrit); 614 usage4(_("Could not parse arguments"));
576 set_thresholds(&stratum_thresholds, swarn, scrit); 615 }
577 set_thresholds(&truechimer_thresholds, twarn, tcrit); 616
617 const check_ntp_peer_config config = tmp_config.config;
578 618
579 /* initialize alarm signal handling */ 619 /* initialize alarm signal handling */
580 signal (SIGALRM, socket_timeout_alarm_handler); 620 signal(SIGALRM, socket_timeout_alarm_handler);
581 621
582 /* set socket timeout */ 622 /* set socket timeout */
583 alarm (socket_timeout); 623 alarm(socket_timeout);
584 624
585 /* This returns either OK or WARNING (See comment preceding ntp_request) */ 625 /* This returns either OK or WARNING (See comment preceding ntp_request) */
586 result = ntp_request(&offset, &offset_result, &jitter, &stratum, &num_truechimers); 626 ntp_request_result ntp_res = ntp_request(config);
627 mp_state_enum result = STATE_UNKNOWN;
587 628
588 if(offset_result == STATE_UNKNOWN) { 629 if (ntp_res.offset_result == STATE_UNKNOWN) {
589 /* if there's no sync peer (this overrides ntp_request output): */ 630 /* if there's no sync peer (this overrides ntp_request output): */
590 result = (quiet ? STATE_UNKNOWN : STATE_CRITICAL); 631 result = (config.quiet ? STATE_UNKNOWN : STATE_CRITICAL);
591 } else { 632 } else {
592 /* Be quiet if there's no candidates either */ 633 /* Be quiet if there's no candidates either */
593 if (quiet && result == STATE_WARNING) 634 if (config.quiet && result == STATE_WARNING) {
594 result = STATE_UNKNOWN; 635 result = STATE_UNKNOWN;
595 result = max_state_alt(result, get_status(fabs(offset), offset_thresholds)); 636 }
637 result = max_state_alt(result, get_status(fabs(ntp_res.offset), config.offset_thresholds));
596 } 638 }
597 639
598 int oresult = result; 640 mp_state_enum oresult = result;
599 641 mp_state_enum tresult = STATE_UNKNOWN;
600 642
601 int tresult = STATE_UNKNOWN; 643 if (config.do_truechimers) {
602 644 tresult = get_status(ntp_res.num_truechimers, config.truechimer_thresholds);
603 if(do_truechimers) {
604 tresult = get_status(num_truechimers, truechimer_thresholds);
605 result = max_state_alt(result, tresult); 645 result = max_state_alt(result, tresult);
606 } 646 }
607 647
648 mp_state_enum sresult = STATE_UNKNOWN;
608 649
609 int sresult = STATE_UNKNOWN; 650 if (config.do_stratum) {
610 651 sresult = get_status((double)ntp_res.stratum, config.stratum_thresholds);
611 if(do_stratum) {
612 sresult = get_status(stratum, stratum_thresholds);
613 result = max_state_alt(result, sresult); 652 result = max_state_alt(result, sresult);
614 } 653 }
615 654
655 mp_state_enum jresult = STATE_UNKNOWN;
616 656
617 int jresult = STATE_UNKNOWN; 657 if (config.do_jitter) {
618 658 jresult = get_status(ntp_res.jitter, config.jitter_thresholds);
619 if(do_jitter) {
620 jresult = get_status(jitter, jitter_thresholds);
621 result = max_state_alt(result, jresult); 659 result = max_state_alt(result, jresult);
622 } 660 }
623 661
662 char *result_line;
624 switch (result) { 663 switch (result) {
625 case STATE_CRITICAL : 664 case STATE_CRITICAL:
626 xasprintf(&result_line, _("NTP CRITICAL:")); 665 xasprintf(&result_line, _("NTP CRITICAL:"));
627 break; 666 break;
628 case STATE_WARNING : 667 case STATE_WARNING:
629 xasprintf(&result_line, _("NTP WARNING:")); 668 xasprintf(&result_line, _("NTP WARNING:"));
630 break; 669 break;
631 case STATE_OK : 670 case STATE_OK:
632 xasprintf(&result_line, _("NTP OK:")); 671 xasprintf(&result_line, _("NTP OK:"));
633 break; 672 break;
634 default : 673 default:
635 xasprintf(&result_line, _("NTP UNKNOWN:")); 674 xasprintf(&result_line, _("NTP UNKNOWN:"));
636 break; 675 break;
637 } 676 }
638 if(!syncsource_found) 677
678 if (!syncsource_found) {
639 xasprintf(&result_line, "%s %s,", result_line, _("Server not synchronized")); 679 xasprintf(&result_line, "%s %s,", result_line, _("Server not synchronized"));
640 else if(li_alarm) 680 } else if (li_alarm) {
641 xasprintf(&result_line, "%s %s,", result_line, _("Server has the LI_ALARM bit set")); 681 xasprintf(&result_line, "%s %s,", result_line, _("Server has the LI_ALARM bit set"));
682 }
642 683
643 if(offset_result == STATE_UNKNOWN){ 684 char *perfdata_line;
685 if (ntp_res.offset_result == STATE_UNKNOWN) {
644 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown")); 686 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
645 xasprintf(&perfdata_line, ""); 687 xasprintf(&perfdata_line, "");
646 } else if (oresult == STATE_WARNING) { 688 } else if (oresult == STATE_WARNING) {
647 xasprintf(&result_line, "%s %s %.10g secs (WARNING)", result_line, _("Offset"), offset); 689 xasprintf(&result_line, "%s %s %.10g secs (WARNING)", result_line, _("Offset"), ntp_res.offset);
648 } else if (oresult == STATE_CRITICAL) { 690 } else if (oresult == STATE_CRITICAL) {
649 xasprintf(&result_line, "%s %s %.10g secs (CRITICAL)", result_line, _("Offset"), offset); 691 xasprintf(&result_line, "%s %s %.10g secs (CRITICAL)", result_line, _("Offset"), ntp_res.offset);
650 } else { 692 } else {
651 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset); 693 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), ntp_res.offset);
652 } 694 }
653 xasprintf(&perfdata_line, "%s", perfd_offset(offset)); 695 xasprintf(&perfdata_line, "%s", perfd_offset(ntp_res.offset, config.offset_thresholds));
654 696
655 if (do_jitter) { 697 if (config.do_jitter) {
656 if (jresult == STATE_WARNING) { 698 if (jresult == STATE_WARNING) {
657 xasprintf(&result_line, "%s, jitter=%f (WARNING)", result_line, jitter); 699 xasprintf(&result_line, "%s, jitter=%f (WARNING)", result_line, ntp_res.jitter);
658 } else if (jresult == STATE_CRITICAL) { 700 } else if (jresult == STATE_CRITICAL) {
659 xasprintf(&result_line, "%s, jitter=%f (CRITICAL)", result_line, jitter); 701 xasprintf(&result_line, "%s, jitter=%f (CRITICAL)", result_line, ntp_res.jitter);
660 } else { 702 } else {
661 xasprintf(&result_line, "%s, jitter=%f", result_line, jitter); 703 xasprintf(&result_line, "%s, jitter=%f", result_line, ntp_res.jitter);
662 } 704 }
663 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_jitter(jitter)); 705 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_jitter(ntp_res.jitter, config.do_jitter, config.jitter_thresholds));
664 } 706 }
665 if (do_stratum) { 707
708 if (config.do_stratum) {
666 if (sresult == STATE_WARNING) { 709 if (sresult == STATE_WARNING) {
667 xasprintf(&result_line, "%s, stratum=%i (WARNING)", result_line, stratum); 710 xasprintf(&result_line, "%s, stratum=%l (WARNING)", result_line, ntp_res.stratum);
668 } else if (sresult == STATE_CRITICAL) { 711 } else if (sresult == STATE_CRITICAL) {
669 xasprintf(&result_line, "%s, stratum=%i (CRITICAL)", result_line, stratum); 712 xasprintf(&result_line, "%s, stratum=%l (CRITICAL)", result_line, ntp_res.stratum);
670 } else { 713 } else {
671 xasprintf(&result_line, "%s, stratum=%i", result_line, stratum); 714 xasprintf(&result_line, "%s, stratum=%l", result_line, ntp_res.stratum);
672 } 715 }
673 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_stratum(stratum)); 716 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_stratum(ntp_res.stratum, config.do_stratum, config.stratum_thresholds));
674 } 717 }
675 if (do_truechimers) { 718
719 if (config.do_truechimers) {
676 if (tresult == STATE_WARNING) { 720 if (tresult == STATE_WARNING) {
677 xasprintf(&result_line, "%s, truechimers=%i (WARNING)", result_line, num_truechimers); 721 xasprintf(&result_line, "%s, truechimers=%i (WARNING)", result_line, ntp_res.num_truechimers);
678 } else if (tresult == STATE_CRITICAL) { 722 } else if (tresult == STATE_CRITICAL) {
679 xasprintf(&result_line, "%s, truechimers=%i (CRITICAL)", result_line, num_truechimers); 723 xasprintf(&result_line, "%s, truechimers=%i (CRITICAL)", result_line, ntp_res.num_truechimers);
680 } else { 724 } else {
681 xasprintf(&result_line, "%s, truechimers=%i", result_line, num_truechimers); 725 xasprintf(&result_line, "%s, truechimers=%i", result_line, ntp_res.num_truechimers);
682 } 726 }
683 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_truechimers(num_truechimers)); 727 xasprintf(&perfdata_line, "%s %s", perfdata_line,
728 perfd_truechimers(ntp_res.num_truechimers, config.do_truechimers, config.truechimer_thresholds));
684 } 729 }
730
685 printf("%s|%s\n", result_line, perfdata_line); 731 printf("%s|%s\n", result_line, perfdata_line);
686 732
687 if(server_address!=NULL) free(server_address); 733 if (config.server_address != NULL) {
688 return result; 734 free(config.server_address);
735 }
736
737 exit(result);
689} 738}
690 739
691void print_help(void){ 740void print_help(void) {
692 print_revision(progname, NP_VERSION); 741 print_revision(progname, NP_VERSION);
693 742
694 printf ("Copyright (c) 2006 Sean Finney\n"); 743 printf("Copyright (c) 2006 Sean Finney\n");
695 printf (COPYRIGHT, copyright, email); 744 printf(COPYRIGHT, copyright, email);
696 745
697 printf ("%s\n", _("This plugin checks the selected ntp server")); 746 printf("%s\n", _("This plugin checks the selected ntp server"));
698 747
699 printf ("\n\n"); 748 printf("\n\n");
700 749
701 print_usage(); 750 print_usage();
702 printf (UT_HELP_VRSN); 751 printf(UT_HELP_VRSN);
703 printf (UT_EXTRA_OPTS); 752 printf(UT_EXTRA_OPTS);
704 printf (UT_IPv46); 753 printf(UT_IPv46);
705 printf (UT_HOST_PORT, 'p', "123"); 754 printf(UT_HOST_PORT, 'p', "123");
706 printf (" %s\n", "-q, --quiet"); 755 printf(" %s\n", "-q, --quiet");
707 printf (" %s\n", _("Returns UNKNOWN instead of CRITICAL or WARNING if server isn't synchronized")); 756 printf(" %s\n", _("Returns UNKNOWN instead of CRITICAL or WARNING if server isn't synchronized"));
708 printf (" %s\n", "-w, --warning=THRESHOLD"); 757 printf(" %s\n", "-w, --warning=THRESHOLD");
709 printf (" %s\n", _("Offset to result in warning status (seconds)")); 758 printf(" %s\n", _("Offset to result in warning status (seconds)"));
710 printf (" %s\n", "-c, --critical=THRESHOLD"); 759 printf(" %s\n", "-c, --critical=THRESHOLD");
711 printf (" %s\n", _("Offset to result in critical status (seconds)")); 760 printf(" %s\n", _("Offset to result in critical status (seconds)"));
712 printf (" %s\n", "-W, --swarn=THRESHOLD"); 761 printf(" %s\n", "-W, --swarn=THRESHOLD");
713 printf (" %s\n", _("Warning threshold for stratum of server's synchronization peer")); 762 printf(" %s\n", _("Warning threshold for stratum of server's synchronization peer"));
714 printf (" %s\n", "-C, --scrit=THRESHOLD"); 763 printf(" %s\n", "-C, --scrit=THRESHOLD");
715 printf (" %s\n", _("Critical threshold for stratum of server's synchronization peer")); 764 printf(" %s\n", _("Critical threshold for stratum of server's synchronization peer"));
716 printf (" %s\n", "-j, --jwarn=THRESHOLD"); 765 printf(" %s\n", "-j, --jwarn=THRESHOLD");
717 printf (" %s\n", _("Warning threshold for jitter")); 766 printf(" %s\n", _("Warning threshold for jitter"));
718 printf (" %s\n", "-k, --jcrit=THRESHOLD"); 767 printf(" %s\n", "-k, --jcrit=THRESHOLD");
719 printf (" %s\n", _("Critical threshold for jitter")); 768 printf(" %s\n", _("Critical threshold for jitter"));
720 printf (" %s\n", "-m, --twarn=THRESHOLD"); 769 printf(" %s\n", "-m, --twarn=THRESHOLD");
721 printf (" %s\n", _("Warning threshold for number of usable time sources (\"truechimers\")")); 770 printf(" %s\n", _("Warning threshold for number of usable time sources (\"truechimers\")"));
722 printf (" %s\n", "-n, --tcrit=THRESHOLD"); 771 printf(" %s\n", "-n, --tcrit=THRESHOLD");
723 printf (" %s\n", _("Critical threshold for number of usable time sources (\"truechimers\")")); 772 printf(" %s\n", _("Critical threshold for number of usable time sources (\"truechimers\")"));
724 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 773 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
725 printf (UT_VERBOSE); 774 printf(UT_VERBOSE);
726 775
727 printf("\n"); 776 printf("\n");
728 printf("%s\n", _("This plugin checks an NTP server independent of any commandline")); 777 printf("%s\n", _("This plugin checks an NTP server independent of any commandline"));
@@ -751,13 +800,11 @@ void print_help(void){
751 printf(" %s\n", _("Check only stratum:")); 800 printf(" %s\n", _("Check only stratum:"));
752 printf(" %s\n", ("./check_ntp_peer -H ntpserv -W 4 -C 6")); 801 printf(" %s\n", ("./check_ntp_peer -H ntpserv -W 4 -C 6"));
753 802
754 printf (UT_SUPPORT); 803 printf(UT_SUPPORT);
755} 804}
756 805
757void 806void print_usage(void) {
758print_usage(void) 807 printf("%s\n", _("Usage:"));
759{
760 printf ("%s\n", _("Usage:"));
761 printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-W <warn>] [-C <crit>]\n", progname); 808 printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-W <warn>] [-C <crit>]\n", progname);
762 printf(" [-j <warn>] [-k <crit>] [-v verbose]\n"); 809 printf(" [-j <warn>] [-k <crit>] [-v verbose]\n");
763} 810}
diff --git a/plugins/check_ntp_peer.d/config.h b/plugins/check_ntp_peer.d/config.h
new file mode 100644
index 00000000..00e6b05d
--- /dev/null
+++ b/plugins/check_ntp_peer.d/config.h
@@ -0,0 +1,67 @@
1#pragma once
2
3#include "../../config.h"
4#include "thresholds.h"
5#include <stddef.h>
6
7enum {
8 DEFAULT_NTP_PORT = 123,
9};
10
11typedef struct {
12 char *server_address;
13 int port;
14
15 bool quiet;
16
17 // truechimer stuff
18 bool do_truechimers;
19 char *twarn;
20 char *tcrit;
21 thresholds *truechimer_thresholds;
22
23 char *owarn;
24 char *ocrit;
25 thresholds *offset_thresholds;
26
27 // stratum stuff
28 bool do_stratum;
29 char *swarn;
30 char *scrit;
31 thresholds *stratum_thresholds;
32
33 // jitter stuff
34 bool do_jitter;
35 char *jwarn;
36 char *jcrit;
37 thresholds *jitter_thresholds;
38
39} check_ntp_peer_config;
40
41check_ntp_peer_config check_ntp_peer_config_init() {
42 check_ntp_peer_config tmp = {
43 .server_address = NULL,
44 .port = DEFAULT_NTP_PORT,
45
46 .quiet = false,
47 .do_truechimers = false,
48 .twarn = "0:",
49 .tcrit = "0:",
50 .truechimer_thresholds = NULL,
51
52 .owarn = "60",
53 .ocrit = "120",
54 .offset_thresholds = NULL,
55
56 .do_stratum = false,
57 .swarn = "-1:16",
58 .scrit = "-1:16",
59 .stratum_thresholds = NULL,
60
61 .do_jitter = false,
62 .jwarn = "-1:5000",
63 .jcrit = "-1:10000",
64 .jitter_thresholds = NULL,
65 };
66 return tmp;
67}
diff --git a/plugins/check_ntp_time.c b/plugins/check_ntp_time.c
index b2e16556..31162883 100644
--- a/plugins/check_ntp_time.c
+++ b/plugins/check_ntp_time.c
@@ -1,63 +1,64 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_ntp_time plugin 3 * Monitoring check_ntp_time plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2006 Sean Finney <seanius@seanius.net> 6 * Copyright (c) 2006 Sean Finney <seanius@seanius.net>
7* Copyright (c) 2006-2008 Monitoring Plugins Development Team 7 * Copyright (c) 2006-2024 Monitoring Plugins Development Team
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains the check_ntp_time plugin 11 * This file contains the check_ntp_time plugin
12* 12 *
13* This plugin checks the clock offset between the local host and a 13 * This plugin checks the clock offset between the local host and a
14* remote NTP server. It is independent of any commandline programs or 14 * remote NTP server. It is independent of any commandline programs or
15* external libraries. 15 * external libraries.
16* 16 *
17* If you'd rather want to monitor an NTP server, please use 17 * If you'd rather want to monitor an NTP server, please use
18* check_ntp_peer. 18 * check_ntp_peer.
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_ntp_time"; 37const char *progname = "check_ntp_time";
38const char *copyright = "2006-2008"; 38const char *copyright = "2006-2024";
39const char *email = "devel@monitoring-plugins.org"; 39const char *email = "devel@monitoring-plugins.org";
40 40
41#include "common.h" 41#include "common.h"
42#include "netutils.h" 42#include "netutils.h"
43#include "utils.h" 43#include "utils.h"
44#include "states.h"
45#include "thresholds.h"
46#include "check_ntp_time.d/config.h"
44 47
45static char *server_address=NULL; 48static int verbose = 0;
46static char *port="123";
47static int verbose=0;
48static bool quiet = false;
49static char *owarn="60";
50static char *ocrit="120";
51static int time_offset=0;
52 49
53int process_arguments (int, char **); 50typedef struct {
54thresholds *offset_thresholds = NULL; 51 int errorcode;
55void print_help (void); 52 check_ntp_time_config config;
56void print_usage (void); 53} check_ntp_time_config_wrapper;
54static check_ntp_time_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
55
56static void print_help(void);
57void print_usage(void);
57 58
58/* number of times to perform each request to get a good average. */ 59/* number of times to perform each request to get a good average. */
59#ifndef AVG_NUM 60#ifndef AVG_NUM
60#define AVG_NUM 4 61# define AVG_NUM 4
61#endif 62#endif
62 63
63/* max size of control message data */ 64/* max size of control message data */
@@ -65,17 +66,17 @@ void print_usage (void);
65 66
66/* this structure holds everything in an ntp request/response as per rfc1305 */ 67/* this structure holds everything in an ntp request/response as per rfc1305 */
67typedef struct { 68typedef struct {
68 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ 69 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
69 uint8_t stratum; /* clock stratum */ 70 uint8_t stratum; /* clock stratum */
70 int8_t poll; /* polling interval */ 71 int8_t poll; /* polling interval */
71 int8_t precision; /* precision of the local clock */ 72 int8_t precision; /* precision of the local clock */
72 int32_t rtdelay; /* total rt delay, as a fixed point num. see macros */ 73 int32_t rtdelay; /* total rt delay, as a fixed point num. see macros */
73 uint32_t rtdisp; /* like above, but for max err to primary src */ 74 uint32_t rtdisp; /* like above, but for max err to primary src */
74 uint32_t refid; /* ref clock identifier */ 75 uint32_t refid; /* ref clock identifier */
75 uint64_t refts; /* reference timestamp. local time local clock */ 76 uint64_t refts; /* reference timestamp. local time local clock */
76 uint64_t origts; /* time at which request departed client */ 77 uint64_t origts; /* time at which request departed client */
77 uint64_t rxts; /* time at which request arrived at server */ 78 uint64_t rxts; /* time at which request arrived at server */
78 uint64_t txts; /* time at which request departed server */ 79 uint64_t txts; /* time at which request departed server */
79} ntp_message; 80} ntp_message;
80 81
81/* this structure holds data about results from querying offset from a peer */ 82/* this structure holds data about results from querying offset from a peer */
@@ -86,43 +87,55 @@ typedef struct {
86 double rtdelay; /* converted from the ntp_message */ 87 double rtdelay; /* converted from the ntp_message */
87 double rtdisp; /* converted from the ntp_message */ 88 double rtdisp; /* converted from the ntp_message */
88 double offset[AVG_NUM]; /* offsets from each response */ 89 double offset[AVG_NUM]; /* offsets from each response */
89 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ 90 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
90} ntp_server_results; 91} ntp_server_results;
91 92
92/* bits 1,2 are the leap indicator */ 93/* bits 1,2 are the leap indicator */
93#define LI_MASK 0xc0 94#define LI_MASK 0xc0
94#define LI(x) ((x&LI_MASK)>>6) 95#define LI(x) ((x & LI_MASK) >> 6)
95#define LI_SET(x,y) do{ x |= ((y<<6)&LI_MASK); }while(0) 96#define LI_SET(x, y) \
97 do { \
98 x |= ((y << 6) & LI_MASK); \
99 } while (0)
96/* and these are the values of the leap indicator */ 100/* and these are the values of the leap indicator */
97#define LI_NOWARNING 0x00 101#define LI_NOWARNING 0x00
98#define LI_EXTRASEC 0x01 102#define LI_EXTRASEC 0x01
99#define LI_MISSINGSEC 0x02 103#define LI_MISSINGSEC 0x02
100#define LI_ALARM 0x03 104#define LI_ALARM 0x03
101/* bits 3,4,5 are the ntp version */ 105/* bits 3,4,5 are the ntp version */
102#define VN_MASK 0x38 106#define VN_MASK 0x38
103#define VN(x) ((x&VN_MASK)>>3) 107#define VN(x) ((x & VN_MASK) >> 3)
104#define VN_SET(x,y) do{ x |= ((y<<3)&VN_MASK); }while(0) 108#define VN_SET(x, y) \
109 do { \
110 x |= ((y << 3) & VN_MASK); \
111 } while (0)
105#define VN_RESERVED 0x02 112#define VN_RESERVED 0x02
106/* bits 6,7,8 are the ntp mode */ 113/* bits 6,7,8 are the ntp mode */
107#define MODE_MASK 0x07 114#define MODE_MASK 0x07
108#define MODE(x) (x&MODE_MASK) 115#define MODE(x) (x & MODE_MASK)
109#define MODE_SET(x,y) do{ x |= (y&MODE_MASK); }while(0) 116#define MODE_SET(x, y) \
117 do { \
118 x |= (y & MODE_MASK); \
119 } while (0)
110/* here are some values */ 120/* here are some values */
111#define MODE_CLIENT 0x03 121#define MODE_CLIENT 0x03
112#define MODE_CONTROLMSG 0x06 122#define MODE_CONTROLMSG 0x06
113/* In control message, bits 8-10 are R,E,M bits */ 123/* In control message, bits 8-10 are R,E,M bits */
114#define REM_MASK 0xe0 124#define REM_MASK 0xe0
115#define REM_RESP 0x80 125#define REM_RESP 0x80
116#define REM_ERROR 0x40 126#define REM_ERROR 0x40
117#define REM_MORE 0x20 127#define REM_MORE 0x20
118/* In control message, bits 11 - 15 are opcode */ 128/* In control message, bits 11 - 15 are opcode */
119#define OP_MASK 0x1f 129#define OP_MASK 0x1f
120#define OP_SET(x,y) do{ x |= (y&OP_MASK); }while(0) 130#define OP_SET(x, y) \
131 do { \
132 x |= (y & OP_MASK); \
133 } while (0)
121#define OP_READSTAT 0x01 134#define OP_READSTAT 0x01
122#define OP_READVAR 0x02 135#define OP_READVAR 0x02
123/* In peer status bytes, bits 6,7,8 determine clock selection status */ 136/* In peer status bytes, bits 6,7,8 determine clock selection status */
124#define PEER_SEL(x) ((ntohs(x)>>8)&0x07) 137#define PEER_SEL(x) ((ntohs(x) >> 8) & 0x07)
125#define PEER_INCLUDED 0x04 138#define PEER_INCLUDED 0x04
126#define PEER_SYNCSOURCE 0x06 139#define PEER_SYNCSOURCE 0x06
127 140
128/** 141/**
@@ -136,129 +149,137 @@ typedef struct {
136 149
137/* macros to access the left/right 16 bits of a 32-bit ntp "fixed point" 150/* macros to access the left/right 16 bits of a 32-bit ntp "fixed point"
138 number. note that these can be used as lvalues too */ 151 number. note that these can be used as lvalues too */
139#define L16(x) (((uint16_t*)&x)[0]) 152#define L16(x) (((uint16_t *)&x)[0])
140#define R16(x) (((uint16_t*)&x)[1]) 153#define R16(x) (((uint16_t *)&x)[1])
141/* macros to access the left/right 32 bits of a 64-bit ntp "fixed point" 154/* macros to access the left/right 32 bits of a 64-bit ntp "fixed point"
142 number. these too can be used as lvalues */ 155 number. these too can be used as lvalues */
143#define L32(x) (((uint32_t*)&x)[0]) 156#define L32(x) (((uint32_t *)&x)[0])
144#define R32(x) (((uint32_t*)&x)[1]) 157#define R32(x) (((uint32_t *)&x)[1])
145 158
146/* ntp wants seconds since 1/1/00, epoch is 1/1/70. this is the difference */ 159/* ntp wants seconds since 1/1/00, epoch is 1/1/70. this is the difference */
147#define EPOCHDIFF 0x83aa7e80UL 160#define EPOCHDIFF 0x83aa7e80UL
148 161
149/* extract a 32-bit ntp fixed point number into a double */ 162/* extract a 32-bit ntp fixed point number into a double */
150#define NTP32asDOUBLE(x) (ntohs(L16(x)) + (double)ntohs(R16(x))/65536.0) 163#define NTP32asDOUBLE(x) (ntohs(L16(x)) + ((double)ntohs(R16(x)) / 65536.0))
151 164
152/* likewise for a 64-bit ntp fp number */ 165/* likewise for a 64-bit ntp fp number */
153#define NTP64asDOUBLE(n) (double)(((uint64_t)n)?\ 166#define NTP64asDOUBLE(n) \
154 (ntohl(L32(n))-EPOCHDIFF) + \ 167 (double)(((uint64_t)n) ? (ntohl(L32(n)) - EPOCHDIFF) + (.00000001 * (0.5 + (double)(ntohl(R32(n)) / 42.94967296))) : 0)
155 (.00000001*(0.5+(double)(ntohl(R32(n))/42.94967296))):\
156 0)
157 168
158/* convert a struct timeval to a double */ 169/* convert a struct timeval to a double */
159#define TVasDOUBLE(x) (double)(x.tv_sec+(0.000001*x.tv_usec)) 170#define TVasDOUBLE(x) (double)(x.tv_sec + (0.000001 * x.tv_usec))
160 171
161/* convert an ntp 64-bit fp number to a struct timeval */ 172/* convert an ntp 64-bit fp number to a struct timeval */
162#define NTP64toTV(n,t) \ 173#define NTP64toTV(n, t) \
163 do{ if(!n) t.tv_sec = t.tv_usec = 0; \ 174 do { \
164 else { \ 175 if (!n) \
165 t.tv_sec=ntohl(L32(n))-EPOCHDIFF; \ 176 t.tv_sec = t.tv_usec = 0; \
166 t.tv_usec=(int)(0.5+(double)(ntohl(R32(n))/4294.967296)); \ 177 else { \
167 } \ 178 t.tv_sec = ntohl(L32(n)) - EPOCHDIFF; \
168 }while(0) 179 t.tv_usec = (int)(0.5 + (double)(ntohl(R32(n)) / 4294.967296)); \
180 } \
181 } while (0)
169 182
170/* convert a struct timeval to an ntp 64-bit fp number */ 183/* convert a struct timeval to an ntp 64-bit fp number */
171#define TVtoNTP64(t,n) \ 184#define TVtoNTP64(t, n) \
172 do{ if(!t.tv_usec && !t.tv_sec) n=0x0UL; \ 185 do { \
173 else { \ 186 if (!t.tv_usec && !t.tv_sec) \
174 L32(n)=htonl(t.tv_sec + EPOCHDIFF); \ 187 n = 0x0UL; \
175 R32(n)=htonl((uint64_t)((4294.967296*t.tv_usec)+.5)); \ 188 else { \
176 } \ 189 L32(n) = htonl(t.tv_sec + EPOCHDIFF); \
177 } while(0) 190 R32(n) = htonl((uint64_t)((4294.967296 * t.tv_usec) + .5)); \
191 } \
192 } while (0)
178 193
179/* NTP control message header is 12 bytes, plus any data in the data 194/* NTP control message header is 12 bytes, plus any data in the data
180 * field, plus null padding to the nearest 32-bit boundary per rfc. 195 * field, plus null padding to the nearest 32-bit boundary per rfc.
181 */ 196 */
182#define SIZEOF_NTPCM(m) (12+ntohs(m.count)+((m.count)?4-(ntohs(m.count)%4):0)) 197#define SIZEOF_NTPCM(m) (12 + ntohs(m.count) + ((m.count) ? 4 - (ntohs(m.count) % 4) : 0))
183 198
184/* finally, a little helper or two for debugging: */ 199/* finally, a little helper or two for debugging: */
185#define DBG(x) do{if(verbose>1){ x; }}while(0); 200#define DBG(x) \
186#define PRINTSOCKADDR(x) \ 201 do { \
187 do{ \ 202 if (verbose > 1) { \
188 printf("%u.%u.%u.%u", (x>>24)&0xff, (x>>16)&0xff, (x>>8)&0xff, x&0xff);\ 203 x; \
189 }while(0); 204 } \
205 } while (0);
206#define PRINTSOCKADDR(x) \
207 do { \
208 printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \
209 } while (0);
190 210
191/* calculate the offset of the local clock */ 211/* calculate the offset of the local clock */
192static inline double calc_offset(const ntp_message *m, const struct timeval *t){ 212static inline double calc_offset(const ntp_message *message, const struct timeval *time_value) {
193 double client_tx, peer_rx, peer_tx, client_rx; 213 double client_tx = NTP64asDOUBLE(message->origts);
194 client_tx = NTP64asDOUBLE(m->origts); 214 double peer_rx = NTP64asDOUBLE(message->rxts);
195 peer_rx = NTP64asDOUBLE(m->rxts); 215 double peer_tx = NTP64asDOUBLE(message->txts);
196 peer_tx = NTP64asDOUBLE(m->txts); 216 double client_rx = TVasDOUBLE((*time_value));
197 client_rx=TVasDOUBLE((*t)); 217 return (((peer_tx - client_rx) + (peer_rx - client_tx)) / 2);
198 return (.5*((peer_tx-client_rx)+(peer_rx-client_tx)));
199} 218}
200 219
201/* print out a ntp packet in human readable/debuggable format */ 220/* print out a ntp packet in human readable/debuggable format */
202void print_ntp_message(const ntp_message *p){ 221void print_ntp_message(const ntp_message *message) {
203 struct timeval ref, orig, rx, tx; 222 struct timeval ref;
223 struct timeval orig;
204 224
205 NTP64toTV(p->refts,ref); 225 NTP64toTV(message->refts, ref);
206 NTP64toTV(p->origts,orig); 226 NTP64toTV(message->origts, orig);
207 NTP64toTV(p->rxts,rx);
208 NTP64toTV(p->txts,tx);
209 227
210 printf("packet contents:\n"); 228 printf("packet contents:\n");
211 printf("\tflags: 0x%.2x\n", p->flags); 229 printf("\tflags: 0x%.2x\n", message->flags);
212 printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags&LI_MASK); 230 printf("\t li=%d (0x%.2x)\n", LI(message->flags), message->flags & LI_MASK);
213 printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags&VN_MASK); 231 printf("\t vn=%d (0x%.2x)\n", VN(message->flags), message->flags & VN_MASK);
214 printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags&MODE_MASK); 232 printf("\t mode=%d (0x%.2x)\n", MODE(message->flags), message->flags & MODE_MASK);
215 printf("\tstratum = %d\n", p->stratum); 233 printf("\tstratum = %d\n", message->stratum);
216 printf("\tpoll = %g\n", pow(2, p->poll)); 234 printf("\tpoll = %g\n", pow(2, message->poll));
217 printf("\tprecision = %g\n", pow(2, p->precision)); 235 printf("\tprecision = %g\n", pow(2, message->precision));
218 printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(p->rtdelay)); 236 printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(message->rtdelay));
219 printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(p->rtdisp)); 237 printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(message->rtdisp));
220 printf("\trefid = %x\n", p->refid); 238 printf("\trefid = %x\n", message->refid);
221 printf("\trefts = %-.16g\n", NTP64asDOUBLE(p->refts)); 239 printf("\trefts = %-.16g\n", NTP64asDOUBLE(message->refts));
222 printf("\torigts = %-.16g\n", NTP64asDOUBLE(p->origts)); 240 printf("\torigts = %-.16g\n", NTP64asDOUBLE(message->origts));
223 printf("\trxts = %-.16g\n", NTP64asDOUBLE(p->rxts)); 241 printf("\trxts = %-.16g\n", NTP64asDOUBLE(message->rxts));
224 printf("\ttxts = %-.16g\n", NTP64asDOUBLE(p->txts)); 242 printf("\ttxts = %-.16g\n", NTP64asDOUBLE(message->txts));
225} 243}
226 244
227void setup_request(ntp_message *p){ 245void setup_request(ntp_message *message) {
228 struct timeval t; 246 memset(message, 0, sizeof(ntp_message));
229 247 LI_SET(message->flags, LI_ALARM);
230 memset(p, 0, sizeof(ntp_message)); 248 VN_SET(message->flags, 4);
231 LI_SET(p->flags, LI_ALARM); 249 MODE_SET(message->flags, MODE_CLIENT);
232 VN_SET(p->flags, 4); 250 message->poll = 4;
233 MODE_SET(p->flags, MODE_CLIENT); 251 message->precision = (int8_t)0xfa;
234 p->poll=4; 252 L16(message->rtdelay) = htons(1);
235 p->precision=(int8_t)0xfa; 253 L16(message->rtdisp) = htons(1);
236 L16(p->rtdelay)=htons(1);
237 L16(p->rtdisp)=htons(1);
238 254
255 struct timeval t;
239 gettimeofday(&t, NULL); 256 gettimeofday(&t, NULL);
240 TVtoNTP64(t,p->txts); 257 TVtoNTP64(t, message->txts);
241} 258}
242 259
243/* select the "best" server from a list of servers, and return its index. 260/* select the "best" server from a list of servers, and return its index.
244 * this is done by filtering servers based on stratum, dispersion, and 261 * this is done by filtering servers based on stratum, dispersion, and
245 * finally round-trip delay. */ 262 * finally round-trip delay. */
246int best_offset_server(const ntp_server_results *slist, int nservers){ 263int best_offset_server(const ntp_server_results *slist, int nservers) {
247 int cserver=0, best_server=-1; 264 int best_server = -1;
248 265
249 /* for each server */ 266 /* for each server */
250 for(cserver=0; cserver<nservers; cserver++){ 267 for (int cserver = 0; cserver < nservers; cserver++) {
251 /* We don't want any servers that fails these tests */ 268 /* We don't want any servers that fails these tests */
252 /* Sort out servers that didn't respond or responede with a 0 stratum; 269 /* Sort out servers that didn't respond or responede with a 0 stratum;
253 * stratum 0 is for reference clocks so no NTP server should ever report 270 * stratum 0 is for reference clocks so no NTP server should ever report
254 * a stratum 0 */ 271 * a stratum 0 */
255 if ( slist[cserver].stratum == 0){ 272 if (slist[cserver].stratum == 0) {
256 if (verbose) printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum); 273 if (verbose) {
274 printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum);
275 }
257 continue; 276 continue;
258 } 277 }
259 /* Sort out servers with error flags */ 278 /* Sort out servers with error flags */
260 if ( LI(slist[cserver].flags) == LI_ALARM ){ 279 if (LI(slist[cserver].flags) == LI_ALARM) {
261 if (verbose) printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags)); 280 if (verbose) {
281 printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags));
282 }
262 continue; 283 continue;
263 } 284 }
264 285
@@ -272,13 +293,13 @@ int best_offset_server(const ntp_server_results *slist, int nservers){
272 /* compare the server to the best one we've seen so far */ 293 /* compare the server to the best one we've seen so far */
273 /* does it have an equal or better stratum? */ 294 /* does it have an equal or better stratum? */
274 DBG(printf("comparing peer %d with peer %d\n", cserver, best_server)); 295 DBG(printf("comparing peer %d with peer %d\n", cserver, best_server));
275 if(slist[cserver].stratum <= slist[best_server].stratum){ 296 if (slist[cserver].stratum <= slist[best_server].stratum) {
276 DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server)); 297 DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server));
277 /* does it have an equal or better dispersion? */ 298 /* does it have an equal or better dispersion? */
278 if(slist[cserver].rtdisp <= slist[best_server].rtdisp){ 299 if (slist[cserver].rtdisp <= slist[best_server].rtdisp) {
279 DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server)); 300 DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server));
280 /* does it have a better rtdelay? */ 301 /* does it have a better rtdelay? */
281 if(slist[cserver].rtdelay < slist[best_server].rtdelay){ 302 if (slist[cserver].rtdelay < slist[best_server].rtdelay) {
282 DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server)); 303 DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server));
283 best_server = cserver; 304 best_server = cserver;
284 DBG(printf("peer %d is now our best candidate\n", best_server)); 305 DBG(printf("peer %d is now our best candidate\n", best_server));
@@ -287,13 +308,12 @@ int best_offset_server(const ntp_server_results *slist, int nservers){
287 } 308 }
288 } 309 }
289 310
290 if(best_server >= 0) { 311 if (best_server >= 0) {
291 DBG(printf("best server selected: peer %d\n", best_server)); 312 DBG(printf("best server selected: peer %d\n", best_server));
292 return best_server; 313 return best_server;
293 } else {
294 DBG(printf("no peers meeting synchronization criteria :(\n"));
295 return -1;
296 } 314 }
315 DBG(printf("no peers meeting synchronization criteria :(\n"));
316 return -1;
297} 317}
298 318
299/* do everything we need to get the total average offset 319/* do everything we need to get the total average offset
@@ -301,178 +321,208 @@ int best_offset_server(const ntp_server_results *slist, int nservers){
301 * we don't waste time sitting around waiting for single packets. 321 * we don't waste time sitting around waiting for single packets.
302 * - we also "manually" handle resolving host names and connecting, because 322 * - we also "manually" handle resolving host names and connecting, because
303 * we have to do it in a way that our lazy macros don't handle currently :( */ 323 * we have to do it in a way that our lazy macros don't handle currently :( */
304double offset_request(const char *host, int *status){ 324double offset_request(const char *host, const char *port, mp_state_enum *status, int time_offset) {
305 int i=0, j=0, ga_result=0, num_hosts=0, *socklist=NULL, respnum=0;
306 int servers_completed=0, one_read=0, servers_readable=0, best_index=-1;
307 time_t now_time=0, start_ts=0;
308 ntp_message *req=NULL;
309 double avg_offset=0.;
310 struct timeval recv_time;
311 struct addrinfo *ai=NULL, *ai_tmp=NULL, hints;
312 struct pollfd *ufds=NULL;
313 ntp_server_results *servers=NULL;
314
315 /* setup hints to only return results from getaddrinfo that we'd like */ 325 /* setup hints to only return results from getaddrinfo that we'd like */
326 struct addrinfo hints;
316 memset(&hints, 0, sizeof(struct addrinfo)); 327 memset(&hints, 0, sizeof(struct addrinfo));
317 hints.ai_family = address_family; 328 hints.ai_family = address_family;
318 hints.ai_protocol = IPPROTO_UDP; 329 hints.ai_protocol = IPPROTO_UDP;
319 hints.ai_socktype = SOCK_DGRAM; 330 hints.ai_socktype = SOCK_DGRAM;
320 331
321 /* fill in ai with the list of hosts resolved by the host name */ 332 /* fill in ai with the list of hosts resolved by the host name */
322 ga_result = getaddrinfo(host, port, &hints, &ai); 333 struct addrinfo *addresses = NULL;
323 if(ga_result!=0){ 334 int ga_result = getaddrinfo(host, port, &hints, &addresses);
324 die(STATE_UNKNOWN, "error getting address for %s: %s\n", 335 if (ga_result != 0) {
325 host, gai_strerror(ga_result)); 336 die(STATE_UNKNOWN, "error getting address for %s: %s\n", host, gai_strerror(ga_result));
326 } 337 }
327 338
328 /* count the number of returned hosts, and allocate stuff accordingly */ 339 /* count the number of returned hosts, and allocate stuff accordingly */
329 for(ai_tmp=ai; ai_tmp!=NULL; ai_tmp=ai_tmp->ai_next){ num_hosts++; } 340 size_t num_hosts = 0;
330 req=(ntp_message*)malloc(sizeof(ntp_message)*num_hosts); 341 for (struct addrinfo *ai_tmp = addresses; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) {
331 if(req==NULL) die(STATE_UNKNOWN, "can not allocate ntp message array"); 342 num_hosts++;
332 socklist=(int*)malloc(sizeof(int)*num_hosts); 343 }
333 if(socklist==NULL) die(STATE_UNKNOWN, "can not allocate socket array"); 344
334 ufds=(struct pollfd*)malloc(sizeof(struct pollfd)*num_hosts); 345 ntp_message *req = (ntp_message *)malloc(sizeof(ntp_message) * num_hosts);
335 if(ufds==NULL) die(STATE_UNKNOWN, "can not allocate socket array"); 346
336 servers=(ntp_server_results*)malloc(sizeof(ntp_server_results)*num_hosts); 347 if (req == NULL) {
337 if(servers==NULL) die(STATE_UNKNOWN, "can not allocate server array"); 348 die(STATE_UNKNOWN, "can not allocate ntp message array");
338 memset(servers, 0, sizeof(ntp_server_results)*num_hosts); 349 }
339 DBG(printf("Found %d peers to check\n", num_hosts)); 350 int *socklist = (int *)malloc(sizeof(int) * num_hosts);
351
352 if (socklist == NULL) {
353 die(STATE_UNKNOWN, "can not allocate socket array");
354 }
355
356 struct pollfd *ufds = (struct pollfd *)malloc(sizeof(struct pollfd) * num_hosts);
357 if (ufds == NULL) {
358 die(STATE_UNKNOWN, "can not allocate socket array");
359 }
360
361 ntp_server_results *servers = (ntp_server_results *)malloc(sizeof(ntp_server_results) * num_hosts);
362 if (servers == NULL) {
363 die(STATE_UNKNOWN, "can not allocate server array");
364 }
365 memset(servers, 0, sizeof(ntp_server_results) * num_hosts);
366 DBG(printf("Found %zu peers to check\n", num_hosts));
340 367
341 /* setup each socket for writing, and the corresponding struct pollfd */ 368 /* setup each socket for writing, and the corresponding struct pollfd */
342 ai_tmp=ai; 369 struct addrinfo *ai_tmp = addresses;
343 for(i=0;ai_tmp;i++){ 370 for (int i = 0; ai_tmp; i++) {
344 socklist[i]=socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP); 371 socklist[i] = socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP);
345 if(socklist[i] == -1) { 372 if (socklist[i] == -1) {
346 perror(NULL); 373 perror(NULL);
347 die(STATE_UNKNOWN, "can not create new socket"); 374 die(STATE_UNKNOWN, "can not create new socket");
348 } 375 }
349 if(connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)){ 376 if (connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)) {
350 /* don't die here, because it is enough if there is one server 377 /* don't die here, because it is enough if there is one server
351 answering in time. This also would break for dual ipv4/6 stacked 378 answering in time. This also would break for dual ipv4/6 stacked
352 ntp servers when the client only supports on of them. 379 ntp servers when the client only supports on of them.
353 */ 380 */
354 DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno))); 381 DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno)));
355 } else { 382 } else {
356 ufds[i].fd=socklist[i]; 383 ufds[i].fd = socklist[i];
357 ufds[i].events=POLLIN; 384 ufds[i].events = POLLIN;
358 ufds[i].revents=0; 385 ufds[i].revents = 0;
359 } 386 }
360 ai_tmp = ai_tmp->ai_next; 387 ai_tmp = ai_tmp->ai_next;
361 } 388 }
362 389
363 /* now do AVG_NUM checks to each host. We stop before timeout/2 seconds 390 /* now do AVG_NUM checks to each host. We stop before timeout/2 seconds
364 * have passed in order to ensure post-processing and jitter time. */ 391 * have passed in order to ensure post-processing and jitter time. */
365 now_time=start_ts=time(NULL); 392 time_t start_ts = 0;
366 while(servers_completed<num_hosts && now_time-start_ts <= socket_timeout/2){ 393 time_t now_time = 0;
394 now_time = start_ts = time(NULL);
395 size_t servers_completed = 0;
396 bool one_read = false;
397 while (servers_completed < num_hosts && now_time - start_ts <= socket_timeout / 2) {
367 /* loop through each server and find each one which hasn't 398 /* loop through each server and find each one which hasn't
368 * been touched in the past second or so and is still lacking 399 * been touched in the past second or so and is still lacking
369 * some responses. For each of these servers, send a new request, 400 * some responses. For each of these servers, send a new request,
370 * and update the "waiting" timestamp with the current time. */ 401 * and update the "waiting" timestamp with the current time. */
371 now_time=time(NULL); 402 now_time = time(NULL);
372 403
373 for(i=0; i<num_hosts; i++){ 404 for (size_t i = 0; i < num_hosts; i++) {
374 if(servers[i].waiting<now_time && servers[i].num_responses<AVG_NUM){ 405 if (servers[i].waiting < now_time && servers[i].num_responses < AVG_NUM) {
375 if(verbose && servers[i].waiting != 0) printf("re-"); 406 if (verbose && servers[i].waiting != 0) {
376 if(verbose) printf("sending request to peer %d\n", i); 407 printf("re-");
408 }
409 if (verbose) {
410 printf("sending request to peer %zu\n", i);
411 }
377 setup_request(&req[i]); 412 setup_request(&req[i]);
378 write(socklist[i], &req[i], sizeof(ntp_message)); 413 write(socklist[i], &req[i], sizeof(ntp_message));
379 servers[i].waiting=now_time; 414 servers[i].waiting = now_time;
380 break; 415 break;
381 } 416 }
382 } 417 }
383 418
384 /* quickly poll for any sockets with pending data */ 419 /* quickly poll for any sockets with pending data */
385 servers_readable=poll(ufds, num_hosts, 100); 420 int servers_readable = poll(ufds, num_hosts, 100);
386 if(servers_readable==-1){ 421 if (servers_readable == -1) {
387 perror("polling ntp sockets"); 422 perror("polling ntp sockets");
388 die(STATE_UNKNOWN, "communication errors"); 423 die(STATE_UNKNOWN, "communication errors");
389 } 424 }
390 425
391 /* read from any sockets with pending data */ 426 /* read from any sockets with pending data */
392 for(i=0; servers_readable && i<num_hosts; i++){ 427 for (size_t i = 0; servers_readable && i < num_hosts; i++) {
393 if(ufds[i].revents&POLLIN && servers[i].num_responses < AVG_NUM){ 428 if (ufds[i].revents & POLLIN && servers[i].num_responses < AVG_NUM) {
394 if(verbose) { 429 if (verbose) {
395 printf("response from peer %d: ", i); 430 printf("response from peer %zu: ", i);
396 } 431 }
397 432
398 read(ufds[i].fd, &req[i], sizeof(ntp_message)); 433 read(ufds[i].fd, &req[i], sizeof(ntp_message));
434
435 struct timeval recv_time;
399 gettimeofday(&recv_time, NULL); 436 gettimeofday(&recv_time, NULL);
400 DBG(print_ntp_message(&req[i])); 437 DBG(print_ntp_message(&req[i]));
401 respnum=servers[i].num_responses++; 438 int respnum = servers[i].num_responses++;
402 servers[i].offset[respnum]=calc_offset(&req[i], &recv_time)+time_offset; 439 servers[i].offset[respnum] = calc_offset(&req[i], &recv_time) + time_offset;
403 if(verbose) { 440 if (verbose) {
404 printf("offset %.10g\n", servers[i].offset[respnum]); 441 printf("offset %.10g\n", servers[i].offset[respnum]);
405 } 442 }
406 servers[i].stratum=req[i].stratum; 443 servers[i].stratum = req[i].stratum;
407 servers[i].rtdisp=NTP32asDOUBLE(req[i].rtdisp); 444 servers[i].rtdisp = NTP32asDOUBLE(req[i].rtdisp);
408 servers[i].rtdelay=NTP32asDOUBLE(req[i].rtdelay); 445 servers[i].rtdelay = NTP32asDOUBLE(req[i].rtdelay);
409 servers[i].waiting=0; 446 servers[i].waiting = 0;
410 servers[i].flags=req[i].flags; 447 servers[i].flags = req[i].flags;
411 servers_readable--; 448 servers_readable--;
412 one_read = 1; 449 one_read = true;
413 if(servers[i].num_responses==AVG_NUM) servers_completed++; 450 if (servers[i].num_responses == AVG_NUM) {
451 servers_completed++;
452 }
414 } 453 }
415 } 454 }
416 /* lather, rinse, repeat. */ 455 /* lather, rinse, repeat. */
417 } 456 }
418 457
419 if (one_read == 0) { 458 if (!one_read) {
420 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); 459 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
421 } 460 }
422 461
423 /* now, pick the best server from the list */ 462 /* now, pick the best server from the list */
424 best_index=best_offset_server(servers, num_hosts); 463 double avg_offset = 0.;
425 if(best_index < 0){ 464 int best_index = best_offset_server(servers, num_hosts);
426 *status=STATE_UNKNOWN; 465 if (best_index < 0) {
466 *status = STATE_UNKNOWN;
427 } else { 467 } else {
428 /* finally, calculate the average offset */ 468 /* finally, calculate the average offset */
429 for(i=0; i<servers[best_index].num_responses;i++){ 469 for (int i = 0; i < servers[best_index].num_responses; i++) {
430 avg_offset+=servers[best_index].offset[i]; 470 avg_offset += servers[best_index].offset[i];
431 } 471 }
432 avg_offset/=servers[best_index].num_responses; 472 avg_offset /= servers[best_index].num_responses;
433 } 473 }
434 474
435 /* cleanup */ 475 /* cleanup */
436 for(j=0; j<num_hosts; j++){ close(socklist[j]); } 476 for (size_t j = 0; j < num_hosts; j++) {
477 close(socklist[j]);
478 }
437 free(socklist); 479 free(socklist);
438 free(ufds); 480 free(ufds);
439 free(servers); 481 free(servers);
440 free(req); 482 free(req);
441 freeaddrinfo(ai); 483 freeaddrinfo(addresses);
442 484
443 if(verbose) printf("overall average offset: %.10g\n", avg_offset); 485 if (verbose) {
486 printf("overall average offset: %.10g\n", avg_offset);
487 }
444 return avg_offset; 488 return avg_offset;
445} 489}
446 490
447int process_arguments(int argc, char **argv){ 491check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
448 int c; 492 static struct option longopts[] = {{"version", no_argument, 0, 'V'},
449 int option=0; 493 {"help", no_argument, 0, 'h'},
450 static struct option longopts[] = { 494 {"verbose", no_argument, 0, 'v'},
451 {"version", no_argument, 0, 'V'}, 495 {"use-ipv4", no_argument, 0, '4'},
452 {"help", no_argument, 0, 'h'}, 496 {"use-ipv6", no_argument, 0, '6'},
453 {"verbose", no_argument, 0, 'v'}, 497 {"quiet", no_argument, 0, 'q'},
454 {"use-ipv4", no_argument, 0, '4'}, 498 {"time-offset", optional_argument, 0, 'o'},
455 {"use-ipv6", no_argument, 0, '6'}, 499 {"warning", required_argument, 0, 'w'},
456 {"quiet", no_argument, 0, 'q'}, 500 {"critical", required_argument, 0, 'c'},
457 {"time-offset", optional_argument, 0, 'o'}, 501 {"timeout", required_argument, 0, 't'},
458 {"warning", required_argument, 0, 'w'}, 502 {"hostname", required_argument, 0, 'H'},
459 {"critical", required_argument, 0, 'c'}, 503 {"port", required_argument, 0, 'p'},
460 {"timeout", required_argument, 0, 't'}, 504 {0, 0, 0, 0}};
461 {"hostname", required_argument, 0, 'H'}, 505
462 {"port", required_argument, 0, 'p'}, 506 if (argc < 2) {
463 {0, 0, 0, 0} 507 usage("\n");
464 }; 508 }
465 509
510 check_ntp_time_config_wrapper result = {
511 .errorcode = OK,
512 .config = check_ntp_time_config_init(),
513 };
466 514
467 if (argc < 2) 515 char *owarn = "60";
468 usage ("\n"); 516 char *ocrit = "120";
469 517
470 while (1) { 518 while (true) {
471 c = getopt_long (argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option); 519 int option = 0;
472 if (c == -1 || c == EOF || c == 1) 520 int option_char = getopt_long(argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option);
521 if (option_char == -1 || option_char == EOF || option_char == 1) {
473 break; 522 break;
523 }
474 524
475 switch (c) { 525 switch (option_char) {
476 case 'h': 526 case 'h':
477 print_help(); 527 print_help();
478 exit(STATE_UNKNOWN); 528 exit(STATE_UNKNOWN);
@@ -485,7 +535,7 @@ int process_arguments(int argc, char **argv){
485 verbose++; 535 verbose++;
486 break; 536 break;
487 case 'q': 537 case 'q':
488 quiet = true; 538 result.config.quiet = true;
489 break; 539 break;
490 case 'w': 540 case 'w':
491 owarn = optarg; 541 owarn = optarg;
@@ -494,19 +544,20 @@ int process_arguments(int argc, char **argv){
494 ocrit = optarg; 544 ocrit = optarg;
495 break; 545 break;
496 case 'H': 546 case 'H':
497 if(!is_host(optarg)) 547 if (!is_host(optarg)) {
498 usage2(_("Invalid hostname/address"), optarg); 548 usage2(_("Invalid hostname/address"), optarg);
499 server_address = strdup(optarg); 549 }
550 result.config.server_address = strdup(optarg);
500 break; 551 break;
501 case 'p': 552 case 'p':
502 port = strdup(optarg); 553 result.config.port = strdup(optarg);
503 break; 554 break;
504 case 't': 555 case 't':
505 socket_timeout=atoi(optarg); 556 socket_timeout = atoi(optarg);
506 break; 557 break;
507 case 'o': 558 case 'o':
508 time_offset=atoi(optarg); 559 result.config.time_offset = atoi(optarg);
509 break; 560 break;
510 case '4': 561 case '4':
511 address_family = AF_INET; 562 address_family = AF_INET;
512 break; 563 break;
@@ -514,114 +565,118 @@ int process_arguments(int argc, char **argv){
514#ifdef USE_IPV6 565#ifdef USE_IPV6
515 address_family = AF_INET6; 566 address_family = AF_INET6;
516#else 567#else
517 usage4 (_("IPv6 support not available")); 568 usage4(_("IPv6 support not available"));
518#endif 569#endif
519 break; 570 break;
520 case '?': 571 case '?':
521 /* print short usage statement if args not parsable */ 572 /* print short usage statement if args not parsable */
522 usage5 (); 573 usage5();
523 break; 574 break;
524 } 575 }
525 } 576 }
526 577
527 if(server_address == NULL){ 578 if (result.config.server_address == NULL) {
528 usage4(_("Hostname was not supplied")); 579 usage4(_("Hostname was not supplied"));
529 } 580 }
530 581
531 return 0; 582 set_thresholds(&result.config.offset_thresholds, owarn, ocrit);
532}
533 583
534char *perfd_offset (double offset) { 584 return result;
535 return fperfdata ("offset", offset, "s",
536 true, offset_thresholds->warning->end,
537 true, offset_thresholds->critical->end,
538 false, 0, false, 0);
539} 585}
540 586
541int main(int argc, char *argv[]){ 587char *perfd_offset(double offset, thresholds *offset_thresholds) {
542 int result, offset_result; 588 return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true, offset_thresholds->critical->end, false, 0, false,
543 double offset=0; 589 0);
544 char *result_line, *perfdata_line; 590}
545
546 setlocale (LC_ALL, "");
547 bindtextdomain (PACKAGE, LOCALEDIR);
548 textdomain (PACKAGE);
549 591
550 result = offset_result = STATE_OK; 592int main(int argc, char *argv[]) {
593 setlocale(LC_ALL, "");
594 bindtextdomain(PACKAGE, LOCALEDIR);
595 textdomain(PACKAGE);
551 596
552 /* Parse extra opts if any */ 597 /* Parse extra opts if any */
553 argv=np_extra_opts (&argc, argv, progname); 598 argv = np_extra_opts(&argc, argv, progname);
554 599
555 if (process_arguments (argc, argv) == ERROR) 600 check_ntp_time_config_wrapper tmp_config = process_arguments(argc, argv);
556 usage4 (_("Could not parse arguments"));
557 601
558 set_thresholds(&offset_thresholds, owarn, ocrit); 602 if (tmp_config.errorcode == ERROR) {
603 usage4(_("Could not parse arguments"));
604 }
605
606 const check_ntp_time_config config = tmp_config.config;
559 607
560 /* initialize alarm signal handling */ 608 /* initialize alarm signal handling */
561 signal (SIGALRM, socket_timeout_alarm_handler); 609 signal(SIGALRM, socket_timeout_alarm_handler);
562 610
563 /* set socket timeout */ 611 /* set socket timeout */
564 alarm (socket_timeout); 612 alarm(socket_timeout);
565 613
566 offset = offset_request(server_address, &offset_result); 614 mp_state_enum offset_result = STATE_OK;
615 mp_state_enum result = STATE_OK;
616 double offset = offset_request(config.server_address, config.port, &offset_result, config.time_offset);
567 if (offset_result == STATE_UNKNOWN) { 617 if (offset_result == STATE_UNKNOWN) {
568 result = ( (!quiet) ? STATE_UNKNOWN : STATE_CRITICAL); 618 result = ((!config.quiet) ? STATE_UNKNOWN : STATE_CRITICAL);
569 } else { 619 } else {
570 result = get_status(fabs(offset), offset_thresholds); 620 result = get_status(fabs(offset), config.offset_thresholds);
571 } 621 }
572 622
623 char *result_line;
573 switch (result) { 624 switch (result) {
574 case STATE_CRITICAL : 625 case STATE_CRITICAL:
575 xasprintf(&result_line, _("NTP CRITICAL:")); 626 xasprintf(&result_line, _("NTP CRITICAL:"));
576 break; 627 break;
577 case STATE_WARNING : 628 case STATE_WARNING:
578 xasprintf(&result_line, _("NTP WARNING:")); 629 xasprintf(&result_line, _("NTP WARNING:"));
579 break; 630 break;
580 case STATE_OK : 631 case STATE_OK:
581 xasprintf(&result_line, _("NTP OK:")); 632 xasprintf(&result_line, _("NTP OK:"));
582 break; 633 break;
583 default : 634 default:
584 xasprintf(&result_line, _("NTP UNKNOWN:")); 635 xasprintf(&result_line, _("NTP UNKNOWN:"));
585 break; 636 break;
586 } 637 }
587 if(offset_result == STATE_UNKNOWN){ 638
639 char *perfdata_line;
640 if (offset_result == STATE_UNKNOWN) {
588 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown")); 641 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
589 xasprintf(&perfdata_line, ""); 642 xasprintf(&perfdata_line, "");
590 } else { 643 } else {
591 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset); 644 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset);
592 xasprintf(&perfdata_line, "%s", perfd_offset(offset)); 645 xasprintf(&perfdata_line, "%s", perfd_offset(offset, config.offset_thresholds));
593 } 646 }
594 printf("%s|%s\n", result_line, perfdata_line); 647 printf("%s|%s\n", result_line, perfdata_line);
595 648
596 if(server_address!=NULL) free(server_address); 649 if (config.server_address != NULL) {
597 return result; 650 free(config.server_address);
651 }
652 exit(result);
598} 653}
599 654
600void print_help(void){ 655void print_help(void) {
601 print_revision(progname, NP_VERSION); 656 print_revision(progname, NP_VERSION);
602 657
603 printf ("Copyright (c) 2006 Sean Finney\n"); 658 printf("Copyright (c) 2006 Sean Finney\n");
604 printf (COPYRIGHT, copyright, email); 659 printf(COPYRIGHT, copyright, email);
605 660
606 printf ("%s\n", _("This plugin checks the clock offset with the ntp server")); 661 printf("%s\n", _("This plugin checks the clock offset with the ntp server"));
607 662
608 printf ("\n\n"); 663 printf("\n\n");
609 664
610 print_usage(); 665 print_usage();
611 printf (UT_HELP_VRSN); 666 printf(UT_HELP_VRSN);
612 printf (UT_EXTRA_OPTS); 667 printf(UT_EXTRA_OPTS);
613 printf (UT_IPv46); 668 printf(UT_IPv46);
614 printf (UT_HOST_PORT, 'p', "123"); 669 printf(UT_HOST_PORT, 'p', "123");
615 printf (" %s\n", "-q, --quiet"); 670 printf(" %s\n", "-q, --quiet");
616 printf (" %s\n", _("Returns UNKNOWN instead of CRITICAL if offset cannot be found")); 671 printf(" %s\n", _("Returns UNKNOWN instead of CRITICAL if offset cannot be found"));
617 printf (" %s\n", "-w, --warning=THRESHOLD"); 672 printf(" %s\n", "-w, --warning=THRESHOLD");
618 printf (" %s\n", _("Offset to result in warning status (seconds)")); 673 printf(" %s\n", _("Offset to result in warning status (seconds)"));
619 printf (" %s\n", "-c, --critical=THRESHOLD"); 674 printf(" %s\n", "-c, --critical=THRESHOLD");
620 printf (" %s\n", _("Offset to result in critical status (seconds)")); 675 printf(" %s\n", _("Offset to result in critical status (seconds)"));
621 printf (" %s\n", "-o, --time_offset=INTEGER"); 676 printf(" %s\n", "-o, --time_offset=INTEGER");
622 printf (" %s\n", _("Expected offset of the ntp server relative to local server (seconds)")); 677 printf(" %s\n", _("Expected offset of the ntp server relative to local server (seconds)"));
623 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 678 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
624 printf (UT_VERBOSE); 679 printf(UT_VERBOSE);
625 680
626 printf("\n"); 681 printf("\n");
627 printf("%s\n", _("This plugin checks the clock offset between the local host and a")); 682 printf("%s\n", _("This plugin checks the clock offset between the local host and a"));
@@ -641,13 +696,10 @@ void print_help(void){
641 printf("%s\n", _("Examples:")); 696 printf("%s\n", _("Examples:"));
642 printf(" %s\n", ("./check_ntp_time -H ntpserv -w 0.5 -c 1")); 697 printf(" %s\n", ("./check_ntp_time -H ntpserv -w 0.5 -c 1"));
643 698
644 printf (UT_SUPPORT); 699 printf(UT_SUPPORT);
645} 700}
646 701
647void 702void print_usage(void) {
648print_usage(void) 703 printf("%s\n", _("Usage:"));
649{
650 printf ("%s\n", _("Usage:"));
651 printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-v verbose] [-o <time offset>]\n", progname); 704 printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-v verbose] [-o <time offset>]\n", progname);
652} 705}
653
diff --git a/plugins/check_ntp_time.d/config.h b/plugins/check_ntp_time.d/config.h
new file mode 100644
index 00000000..99dabbbd
--- /dev/null
+++ b/plugins/check_ntp_time.d/config.h
@@ -0,0 +1,28 @@
1#pragma once
2
3#include "../../config.h"
4#include "thresholds.h"
5#include <stddef.h>
6
7typedef struct {
8 char *server_address;
9 char *port;
10
11 bool quiet;
12 int time_offset;
13
14 thresholds *offset_thresholds;
15} check_ntp_time_config;
16
17check_ntp_time_config check_ntp_time_config_init() {
18 check_ntp_time_config tmp = {
19 .server_address = NULL,
20 .port = "123",
21
22 .quiet = false,
23 .time_offset = 0,
24
25 .offset_thresholds = NULL,
26 };
27 return tmp;
28}
diff --git a/plugins/check_nwstat.c b/plugins/check_nwstat.c
deleted file mode 100644
index 10c493b6..00000000
--- a/plugins/check_nwstat.c
+++ /dev/null
@@ -1,1740 +0,0 @@
1/*****************************************************************************
2*
3* Monitoring check_nwstat plugin
4*
5* License: GPL
6* Copyright (c) 2000-2007 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-2007";
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
92char *server_address=NULL;
93char *volume_name=NULL;
94char *nlm_name=NULL;
95char *nrmp_name=NULL;
96char *nrmm_name=NULL;
97char *nrms_name=NULL;
98char *nss1_name=NULL;
99char *nss2_name=NULL;
100char *nss3_name=NULL;
101char *nss4_name=NULL;
102char *nss5_name=NULL;
103char *nss6_name=NULL;
104char *nss7_name=NULL;
105int server_port=PORT;
106unsigned long warning_value=0L;
107unsigned long critical_value=0L;
108bool check_warning_value = false;
109bool check_critical_value = false;
110bool check_netware_version = false;
111enum checkvar vars_to_check = NONE;
112int sap_number=-1;
113
114int process_arguments(int, char **);
115void print_help(void);
116void print_usage(void);
117
118
119
120int
121main(int argc, char **argv) {
122 int result = STATE_UNKNOWN;
123 int sd;
124 char *send_buffer=NULL;
125 char recv_buffer[MAX_INPUT_BUFFER];
126 char *output_message=NULL;
127 char *temp_buffer=NULL;
128 char *netware_version=NULL;
129
130 int time_sync_status=0;
131 int nrm_health_status=0;
132 unsigned long total_cache_buffers=0;
133 unsigned long dirty_cache_buffers=0;
134 unsigned long open_files=0;
135 unsigned long abended_threads=0;
136 unsigned long max_service_processes=0;
137 unsigned long current_service_processes=0;
138 unsigned long free_disk_space=0L;
139 unsigned long nrmp_value=0L;
140 unsigned long nrmm_value=0L;
141 unsigned long nrms_value=0L;
142 unsigned long nss1_value=0L;
143 unsigned long nss2_value=0L;
144 unsigned long nss3_value=0L;
145 unsigned long nss4_value=0L;
146 unsigned long nss5_value=0L;
147 unsigned long nss6_value=0L;
148 unsigned long nss7_value=0L;
149 unsigned long total_disk_space=0L;
150 unsigned long used_disk_space=0L;
151 unsigned long percent_used_disk_space=0L;
152 unsigned long purgeable_disk_space=0L;
153 unsigned long non_purgeable_disk_space=0L;
154 unsigned long percent_free_space=0;
155 unsigned long percent_purgeable_space=0;
156 unsigned long percent_non_purgeable_space=0;
157 unsigned long current_connections=0L;
158 unsigned long utilization=0L;
159 unsigned long cache_hits=0;
160 unsigned long cache_buffers=0L;
161 unsigned long lru_time=0L;
162 unsigned long max_packet_receive_buffers=0;
163 unsigned long used_packet_receive_buffers=0;
164 unsigned long percent_used_packet_receive_buffers=0L;
165 unsigned long sap_entries=0;
166 char uptime[MAX_INPUT_BUFFER];
167
168 setlocale (LC_ALL, "");
169 bindtextdomain (PACKAGE, LOCALEDIR);
170 textdomain (PACKAGE);
171
172 /* Parse extra opts if any */
173 argv=np_extra_opts(&argc, argv, progname);
174
175 if (process_arguments(argc,argv) == ERROR)
176 usage4 (_("Could not parse arguments"));
177
178 /* initialize alarm signal handling */
179 signal(SIGALRM,socket_timeout_alarm_handler);
180
181 /* set socket timeout */
182 alarm(socket_timeout);
183
184 /* open connection */
185 my_tcp_connect (server_address, server_port, &sd);
186
187 /* get OS version string */
188 if (check_netware_version) {
189 send_buffer = strdup ("S19\r\n");
190 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
191 if (result!=STATE_OK)
192 return result;
193 if (!strcmp(recv_buffer,"-1\n"))
194 netware_version = strdup("");
195 else {
196 recv_buffer[strlen(recv_buffer)-1]=0;
197 xasprintf (&netware_version,_("NetWare %s: "),recv_buffer);
198 }
199 } else
200 netware_version = strdup("");
201
202
203 /* check CPU load */
204 if (vars_to_check==LOAD1 || vars_to_check==LOAD5 || vars_to_check==LOAD15) {
205
206 switch(vars_to_check) {
207 case LOAD1:
208 temp_buffer = strdup ("1");
209 break;
210 case LOAD5:
211 temp_buffer = strdup ("5");
212 break;
213 default:
214 temp_buffer = strdup ("15");
215 break;
216 }
217
218 close(sd);
219 my_tcp_connect (server_address, server_port, &sd);
220
221 xasprintf (&send_buffer,"UTIL%s\r\n",temp_buffer);
222 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
223 if (result!=STATE_OK)
224 return result;
225 utilization=strtoul(recv_buffer,NULL,10);
226
227 close(sd);
228 my_tcp_connect (server_address, server_port, &sd);
229
230 send_buffer = strdup ("UPTIME\r\n");
231 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
232 if (result!=STATE_OK)
233 return result;
234 recv_buffer[strlen(recv_buffer)-1]=0;
235 sprintf(uptime,_("Up %s,"),recv_buffer);
236
237 if (check_critical_value && utilization >= critical_value)
238 result=STATE_CRITICAL;
239 else if (check_warning_value && utilization >= warning_value)
240 result=STATE_WARNING;
241
242 xasprintf (&output_message,
243 _("Load %s - %s %s-min load average = %lu%%|load%s=%lu;%lu;%lu;0;100"),
244 state_text(result),
245 uptime,
246 temp_buffer,
247 utilization,
248 temp_buffer,
249 utilization,
250 warning_value,
251 critical_value);
252
253 /* check number of user connections */
254 } else if (vars_to_check==CONNS) {
255
256 close(sd);
257 my_tcp_connect (server_address, server_port, &sd);
258
259 send_buffer = strdup ("CONNECT\r\n");
260 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
261 if (result!=STATE_OK)
262 return result;
263 current_connections=strtoul(recv_buffer,NULL,10);
264
265 if (check_critical_value && current_connections >= critical_value)
266 result=STATE_CRITICAL;
267 else if (check_warning_value && current_connections >= warning_value)
268 result=STATE_WARNING;
269
270 xasprintf (&output_message,
271 _("Conns %s - %lu current connections|Conns=%lu;%lu;%lu;;"),
272 state_text(result),
273 current_connections,
274 current_connections,
275 warning_value,
276 critical_value);
277
278 /* check % long term cache hits */
279 } else if (vars_to_check==LTCH) {
280
281 close(sd);
282 my_tcp_connect (server_address, server_port, &sd);
283
284 send_buffer = strdup ("S1\r\n");
285 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
286 if (result!=STATE_OK)
287 return result;
288 cache_hits=atoi(recv_buffer);
289
290 if (check_critical_value && cache_hits <= critical_value)
291 result=STATE_CRITICAL;
292 else if (check_warning_value && cache_hits <= warning_value)
293 result=STATE_WARNING;
294
295 xasprintf (&output_message,
296 _("%s: Long term cache hits = %lu%%"),
297 state_text(result),
298 cache_hits);
299
300 /* check cache buffers */
301 } else if (vars_to_check==CBUFF) {
302
303 close(sd);
304 my_tcp_connect (server_address, server_port, &sd);
305
306 send_buffer = strdup ("S2\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,
318 _("%s: Total cache buffers = %lu|Cachebuffers=%lu;%lu;%lu;;"),
319 state_text(result),
320 cache_buffers,
321 cache_buffers,
322 warning_value,
323 critical_value);
324
325 /* check dirty cache buffers */
326 } else if (vars_to_check==CDBUFF) {
327
328 close(sd);
329 my_tcp_connect (server_address, server_port, &sd);
330
331 send_buffer = strdup ("S3\r\n");
332 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
333 if (result!=STATE_OK)
334 return result;
335 cache_buffers=strtoul(recv_buffer,NULL,10);
336
337 if (check_critical_value && cache_buffers >= critical_value)
338 result=STATE_CRITICAL;
339 else if (check_warning_value && cache_buffers >= warning_value)
340 result=STATE_WARNING;
341
342 xasprintf (&output_message,
343 _("%s: Dirty cache buffers = %lu|Dirty-Cache-Buffers=%lu;%lu;%lu;;"),
344 state_text(result),
345 cache_buffers,
346 cache_buffers,
347 warning_value,
348 critical_value);
349
350 /* check LRU sitting time in minutes */
351 } else if (vars_to_check==LRUM) {
352
353 close(sd);
354 my_tcp_connect (server_address, server_port, &sd);
355
356 send_buffer = strdup ("S5\r\n");
357 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
358 if (result!=STATE_OK)
359 return result;
360 lru_time=strtoul(recv_buffer,NULL,10);
361
362 if (check_critical_value && lru_time <= critical_value)
363 result=STATE_CRITICAL;
364 else if (check_warning_value && lru_time <= warning_value)
365 result=STATE_WARNING;
366
367 xasprintf (&output_message,
368 _("%s: LRU sitting time = %lu minutes"),
369 state_text(result),
370 lru_time);
371
372
373 /* check KB free space on volume */
374 } else if (vars_to_check==VKF) {
375
376 close(sd);
377 my_tcp_connect (server_address, server_port, &sd);
378
379 xasprintf (&send_buffer,"VKF%s\r\n",volume_name);
380 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
381 if (result!=STATE_OK)
382 return result;
383
384 if (!strcmp(recv_buffer,"-1\n")) {
385 xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
386 result=STATE_CRITICAL;
387 } else {
388 free_disk_space=strtoul(recv_buffer,NULL,10);
389 if (check_critical_value && free_disk_space <= critical_value)
390 result=STATE_CRITICAL;
391 else if (check_warning_value && free_disk_space <= warning_value)
392 result=STATE_WARNING;
393 xasprintf (&output_message,
394 _("%s%lu KB free on volume %s|KBFree%s=%lu;%lu;%lu;;"),
395 (result==STATE_OK)?"":_("Only "),
396 free_disk_space,
397 volume_name,
398 volume_name,
399 free_disk_space,
400 warning_value,
401 critical_value);
402 }
403
404 /* check MB free space on volume */
405 } else if (vars_to_check==VMF) {
406
407 xasprintf (&send_buffer,"VMF%s\r\n",volume_name);
408 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
409 if (result!=STATE_OK)
410 return result;
411
412 if (!strcmp(recv_buffer,"-1\n")) {
413 xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
414 result=STATE_CRITICAL;
415 } else {
416 free_disk_space=strtoul(recv_buffer,NULL,10);
417 if (check_critical_value && free_disk_space <= critical_value)
418 result=STATE_CRITICAL;
419 else if (check_warning_value && free_disk_space <= warning_value)
420 result=STATE_WARNING;
421 xasprintf (&output_message,
422 _("%s%lu MB free on volume %s|MBFree%s=%lu;%lu;%lu;;"),
423 (result==STATE_OK)?"":_("Only "),
424 free_disk_space,
425 volume_name,
426 volume_name,
427 free_disk_space,
428 warning_value,
429 critical_value);
430 }
431 /* check MB used space on volume */
432 } else if (vars_to_check==VMU) {
433
434 xasprintf (&send_buffer,"VMU%s\r\n",volume_name);
435 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
436 if (result!=STATE_OK)
437 return result;
438
439 if (!strcmp(recv_buffer,"-1\n")) {
440 xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
441 result=STATE_CRITICAL;
442 } else {
443 free_disk_space=strtoul(recv_buffer,NULL,10);
444 if (check_critical_value && free_disk_space <= critical_value)
445 result=STATE_CRITICAL;
446 else if (check_warning_value && free_disk_space <= warning_value)
447 result=STATE_WARNING;
448 xasprintf (&output_message,
449 _("%s%lu MB used on volume %s|MBUsed%s=%lu;%lu;%lu;;"),
450 (result==STATE_OK)?"":_("Only "),
451 free_disk_space,
452 volume_name,
453 volume_name,
454 free_disk_space,
455 warning_value,
456 critical_value);
457 }
458 /* check % used space on volume */
459 } else if (vars_to_check==VPU) {
460 close(sd);
461 my_tcp_connect (server_address, server_port, &sd);
462
463 asprintf (&send_buffer,"VMU%s\r\n",volume_name);
464 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
465
466 if (result!=STATE_OK)
467 return result;
468
469 if (!strcmp(recv_buffer,"-1\n")) {
470 asprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
471 result=STATE_CRITICAL;
472
473 } else {
474 used_disk_space=strtoul(recv_buffer,NULL,10);
475 close(sd);
476 my_tcp_connect (server_address, server_port, &sd);
477 /* get total volume in MB */
478 asprintf (&send_buffer,"VMS%s\r\n",volume_name);
479 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
480 if (result!=STATE_OK)
481 return result;
482 total_disk_space=strtoul(recv_buffer,NULL,10);
483 /* calculate percent used on volume */
484 percent_used_disk_space=(unsigned long)(((double)used_disk_space/(double)total_disk_space)*100.0);
485
486 if (check_critical_value && percent_used_disk_space >= critical_value)
487 result=STATE_CRITICAL;
488 else if (check_warning_value && percent_used_disk_space >= warning_value)
489 result=STATE_WARNING;
490
491 asprintf (&output_message,_("%lu MB (%lu%%) used on volume %s - total %lu MB|Used space in percent on %s=%lu;%lu;%lu;0;100"),
492 used_disk_space,
493 percent_used_disk_space,
494 volume_name,
495 total_disk_space,
496 volume_name,
497 percent_used_disk_space,
498 warning_value,
499 critical_value
500 );
501 }
502
503 /* check % free space on volume */
504 } else if (vars_to_check==VPF) {
505
506 close(sd);
507 my_tcp_connect (server_address, server_port, &sd);
508
509 xasprintf (&send_buffer,"VKF%s\r\n",volume_name);
510 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
511 if (result!=STATE_OK)
512 return result;
513
514 if (!strcmp(recv_buffer,"-1\n")) {
515
516 xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
517 result=STATE_CRITICAL;
518
519 } else {
520
521 free_disk_space=strtoul(recv_buffer,NULL,10);
522
523 close(sd);
524 my_tcp_connect (server_address, server_port, &sd);
525
526 xasprintf (&send_buffer,"VKS%s\r\n",volume_name);
527 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
528 if (result!=STATE_OK)
529 return result;
530 total_disk_space=strtoul(recv_buffer,NULL,10);
531
532 percent_free_space=(unsigned long)(((double)free_disk_space/(double)total_disk_space)*100.0);
533
534 if (check_critical_value && percent_free_space <= critical_value)
535 result=STATE_CRITICAL;
536 else if (check_warning_value && percent_free_space <= warning_value)
537 result=STATE_WARNING;
538 free_disk_space/=1024;
539 total_disk_space/=1024;
540 xasprintf (&output_message,_("%lu MB (%lu%%) free on volume %s - total %lu MB|FreeMB%s=%lu;%lu;%lu;0;100"),
541 free_disk_space,
542 percent_free_space,
543 volume_name,
544 total_disk_space,
545 volume_name,
546 percent_free_space,
547 warning_value,
548 critical_value
549 );
550 }
551
552 /* check to see if DS Database is open or closed */
553 } else if (vars_to_check==DSDB) {
554
555 close(sd);
556 my_tcp_connect (server_address, server_port, &sd);
557
558 send_buffer = strdup ("S11\r\n");
559 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
560 if (result!=STATE_OK)
561 return result;
562 if (atoi(recv_buffer)==1)
563 result=STATE_OK;
564 else
565 result=STATE_WARNING;
566
567 close(sd);
568 my_tcp_connect (server_address, server_port, &sd);
569
570 send_buffer = strdup ("S13\r\n");
571 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
572 temp_buffer=strtok(recv_buffer,"\r\n");
573
574 xasprintf (&output_message,_("Directory Services Database is %s (DS version %s)"),(result==STATE_OK)?"open":"closed",temp_buffer);
575
576 /* check to see if logins are enabled */
577 } else if (vars_to_check==LOGINS) {
578
579 close(sd);
580 my_tcp_connect (server_address, server_port, &sd);
581
582 send_buffer = strdup ("S12\r\n");
583 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
584 if (result!=STATE_OK)
585 return result;
586 if (atoi(recv_buffer)==1)
587 result=STATE_OK;
588 else
589 result=STATE_WARNING;
590
591 xasprintf (&output_message,_("Logins are %s"),(result==STATE_OK)?_("enabled"):_("disabled"));
592
593
594 /* check NRM Health Status Summary*/
595 } else if (vars_to_check==NRMH) {
596
597 xasprintf (&send_buffer,"NRMH\r\n");
598 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
599 if (result!=STATE_OK)
600 return result;
601
602 nrm_health_status=atoi(recv_buffer);
603
604 if (nrm_health_status==2) {
605 result=STATE_OK;
606 xasprintf (&output_message,_("CRITICAL - NRM Status is bad!"));
607 }
608 else {
609 if (nrm_health_status==1) {
610 result=STATE_WARNING;
611 xasprintf (&output_message,_("Warning - NRM Status is suspect!"));
612 }
613
614 xasprintf (&output_message,_("OK - NRM Status is good!"));
615 }
616
617
618
619 /* check packet receive buffers */
620 } else if (vars_to_check==UPRB || vars_to_check==PUPRB) {
621
622 close(sd);
623 my_tcp_connect (server_address, server_port, &sd);
624
625 xasprintf (&send_buffer,"S15\r\n");
626 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
627 if (result!=STATE_OK)
628 return result;
629
630 used_packet_receive_buffers=atoi(recv_buffer);
631
632 close(sd);
633 my_tcp_connect (server_address, server_port, &sd);
634
635 xasprintf (&send_buffer,"S16\r\n");
636 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
637 if (result!=STATE_OK)
638 return result;
639
640 max_packet_receive_buffers=atoi(recv_buffer);
641
642 percent_used_packet_receive_buffers=(unsigned long)(((double)used_packet_receive_buffers/(double)max_packet_receive_buffers)*100.0);
643
644 if (vars_to_check==UPRB) {
645 if (check_critical_value && used_packet_receive_buffers >= critical_value)
646 result=STATE_CRITICAL;
647 else if (check_warning_value && used_packet_receive_buffers >= warning_value)
648 result=STATE_WARNING;
649 } else {
650 if (check_critical_value && percent_used_packet_receive_buffers >= critical_value)
651 result=STATE_CRITICAL;
652 else if (check_warning_value && percent_used_packet_receive_buffers >= warning_value)
653 result=STATE_WARNING;
654 }
655
656 xasprintf (&output_message,_("%lu of %lu (%lu%%) packet receive buffers used"),used_packet_receive_buffers,max_packet_receive_buffers,percent_used_packet_receive_buffers);
657
658 /* check SAP table entries */
659 } else if (vars_to_check==SAPENTRIES) {
660
661 close(sd);
662 my_tcp_connect (server_address, server_port, &sd);
663
664 if (sap_number==-1)
665 xasprintf (&send_buffer,"S9\r\n");
666 else
667 xasprintf (&send_buffer,"S9.%d\r\n",sap_number);
668 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
669 if (result!=STATE_OK)
670 return result;
671
672 sap_entries=atoi(recv_buffer);
673
674 if (check_critical_value && sap_entries >= critical_value)
675 result=STATE_CRITICAL;
676 else if (check_warning_value && sap_entries >= warning_value)
677 result=STATE_WARNING;
678
679 if (sap_number==-1)
680 xasprintf (&output_message,_("%lu entries in SAP table"),sap_entries);
681 else
682 xasprintf (&output_message,_("%lu entries in SAP table for SAP type %d"),sap_entries,sap_number);
683
684 /* check KB purgeable space on volume */
685 } else if (vars_to_check==VKP) {
686
687 close(sd);
688 my_tcp_connect (server_address, server_port, &sd);
689
690 xasprintf (&send_buffer,"VKP%s\r\n",volume_name);
691 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
692 if (result!=STATE_OK)
693 return result;
694
695 if (!strcmp(recv_buffer,"-1\n")) {
696 xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
697 result=STATE_CRITICAL;
698 } else {
699 purgeable_disk_space=strtoul(recv_buffer,NULL,10);
700 if (check_critical_value && purgeable_disk_space >= critical_value)
701 result=STATE_CRITICAL;
702 else if (check_warning_value && purgeable_disk_space >= warning_value)
703 result=STATE_WARNING;
704 xasprintf (&output_message,_("%s%lu KB purgeable on volume %s|Purge%s=%lu;%lu;%lu;;"),
705 (result==STATE_OK)?"":_("Only "),
706 purgeable_disk_space,
707 volume_name,
708 volume_name,
709 purgeable_disk_space,
710 warning_value,
711 critical_value);
712 }
713 /* check MB purgeable space on volume */
714 } else if (vars_to_check==VMP) {
715
716 xasprintf (&send_buffer,"VMP%s\r\n",volume_name);
717 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
718 if (result!=STATE_OK)
719 return result;
720
721 if (!strcmp(recv_buffer,"-1\n")) {
722 xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
723 result=STATE_CRITICAL;
724 } else {
725 purgeable_disk_space=strtoul(recv_buffer,NULL,10);
726 if (check_critical_value && purgeable_disk_space >= critical_value)
727 result=STATE_CRITICAL;
728 else if (check_warning_value && purgeable_disk_space >= warning_value)
729 result=STATE_WARNING;
730 xasprintf (&output_message,_("%s%lu MB purgeable on volume %s|Purge%s=%lu;%lu;%lu;;"),
731 (result==STATE_OK)?"":_("Only "),
732 purgeable_disk_space,
733 volume_name,
734 volume_name,
735 purgeable_disk_space,
736 warning_value,
737 critical_value);
738 }
739
740 /* check % purgeable space on volume */
741 } else if (vars_to_check==VPP) {
742
743 close(sd);
744 my_tcp_connect (server_address, server_port, &sd);
745
746 xasprintf (&send_buffer,"VKP%s\r\n",volume_name);
747 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
748 if (result!=STATE_OK)
749 return result;
750
751 if (!strcmp(recv_buffer,"-1\n")) {
752
753 xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
754 result=STATE_CRITICAL;
755
756 } else {
757
758 purgeable_disk_space=strtoul(recv_buffer,NULL,10);
759
760 close(sd);
761 my_tcp_connect (server_address, server_port, &sd);
762
763 xasprintf (&send_buffer,"VKS%s\r\n",volume_name);
764 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
765 if (result!=STATE_OK)
766 return result;
767 total_disk_space=strtoul(recv_buffer,NULL,10);
768
769 percent_purgeable_space=(unsigned long)(((double)purgeable_disk_space/(double)total_disk_space)*100.0);
770
771 if (check_critical_value && percent_purgeable_space >= critical_value)
772 result=STATE_CRITICAL;
773 else if (check_warning_value && percent_purgeable_space >= warning_value)
774 result=STATE_WARNING;
775 purgeable_disk_space/=1024;
776 xasprintf (&output_message,_("%lu MB (%lu%%) purgeable on volume %s|Purgeable%s=%lu;%lu;%lu;0;100"),
777 purgeable_disk_space,
778 percent_purgeable_space,
779 volume_name,
780 volume_name,
781 percent_purgeable_space,
782 warning_value,
783 critical_value
784 );
785 }
786
787 /* check KB not yet purgeable space on volume */
788 } else if (vars_to_check==VKNP) {
789
790 close(sd);
791 my_tcp_connect (server_address, server_port, &sd);
792
793 xasprintf (&send_buffer,"VKNP%s\r\n",volume_name);
794 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
795 if (result!=STATE_OK)
796 return result;
797
798 if (!strcmp(recv_buffer,"-1\n")) {
799 xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
800 result=STATE_CRITICAL;
801 } else {
802 non_purgeable_disk_space=strtoul(recv_buffer,NULL,10);
803 if (check_critical_value && non_purgeable_disk_space >= critical_value)
804 result=STATE_CRITICAL;
805 else if (check_warning_value && non_purgeable_disk_space >= warning_value)
806 result=STATE_WARNING;
807 xasprintf (&output_message,_("%s%lu KB not yet purgeable on volume %s"),(result==STATE_OK)?"":_("Only "),non_purgeable_disk_space,volume_name);
808 }
809
810 /* check % not yet purgeable space on volume */
811 } else if (vars_to_check==VPNP) {
812
813 close(sd);
814 my_tcp_connect (server_address, server_port, &sd);
815
816 xasprintf (&send_buffer,"VKNP%s\r\n",volume_name);
817 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
818 if (result!=STATE_OK)
819 return result;
820
821 if (!strcmp(recv_buffer,"-1\n")) {
822
823 xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
824 result=STATE_CRITICAL;
825
826 } else {
827
828 non_purgeable_disk_space=strtoul(recv_buffer,NULL,10);
829
830 close(sd);
831 my_tcp_connect (server_address, server_port, &sd);
832
833 xasprintf (&send_buffer,"VKS%s\r\n",volume_name);
834 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
835 if (result!=STATE_OK)
836 return result;
837 total_disk_space=strtoul(recv_buffer,NULL,10);
838
839 percent_non_purgeable_space=(unsigned long)(((double)non_purgeable_disk_space/(double)total_disk_space)*100.0);
840
841 if (check_critical_value && percent_non_purgeable_space >= critical_value)
842 result=STATE_CRITICAL;
843 else if (check_warning_value && percent_non_purgeable_space >= warning_value)
844 result=STATE_WARNING;
845 purgeable_disk_space/=1024;
846 xasprintf (&output_message,_("%lu MB (%lu%%) not yet purgeable on volume %s"),non_purgeable_disk_space,percent_non_purgeable_space,volume_name);
847 }
848
849 /* check # of open files */
850 } else if (vars_to_check==OFILES) {
851
852 close(sd);
853 my_tcp_connect (server_address, server_port, &sd);
854
855 xasprintf (&send_buffer,"S18\r\n");
856 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
857 if (result!=STATE_OK)
858 return result;
859
860 open_files=atoi(recv_buffer);
861
862 if (check_critical_value && open_files >= critical_value)
863 result=STATE_CRITICAL;
864 else if (check_warning_value && open_files >= warning_value)
865 result=STATE_WARNING;
866
867 xasprintf (&output_message,_("%lu open files|Openfiles=%lu;%lu;%lu;0,0"),
868 open_files,
869 open_files,
870 warning_value,
871 critical_value);
872
873
874 /* check # of abended threads (Netware > 5.x only) */
875 } else if (vars_to_check==ABENDS) {
876
877 close(sd);
878 my_tcp_connect (server_address, server_port, &sd);
879
880 xasprintf (&send_buffer,"S17\r\n");
881 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
882 if (result!=STATE_OK)
883 return result;
884
885 abended_threads=atoi(recv_buffer);
886
887 if (check_critical_value && abended_threads >= critical_value)
888 result=STATE_CRITICAL;
889 else if (check_warning_value && abended_threads >= warning_value)
890 result=STATE_WARNING;
891
892 xasprintf (&output_message,_("%lu abended threads|Abends=%lu;%lu;%lu;;"),
893 abended_threads,
894 abended_threads,
895 warning_value,
896 critical_value);
897
898 /* check # of current service processes (Netware 5.x only) */
899 } else if (vars_to_check==CSPROCS) {
900
901 close(sd);
902 my_tcp_connect (server_address, server_port, &sd);
903
904 xasprintf (&send_buffer,"S20\r\n");
905 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
906 if (result!=STATE_OK)
907 return result;
908
909 max_service_processes=atoi(recv_buffer);
910
911 close(sd);
912 my_tcp_connect (server_address, server_port, &sd);
913
914 xasprintf (&send_buffer,"S21\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 current_service_processes=atoi(recv_buffer);
920
921 if (check_critical_value && current_service_processes >= critical_value)
922 result=STATE_CRITICAL;
923 else if (check_warning_value && current_service_processes >= warning_value)
924 result=STATE_WARNING;
925
926 xasprintf (&output_message,
927 _("%lu current service processes (%lu max)|Processes=%lu;%lu;%lu;0;%lu"),
928 current_service_processes,
929 max_service_processes,
930 current_service_processes,
931 warning_value,
932 critical_value,
933 max_service_processes);
934
935 /* check # Timesync Status */
936 } else if (vars_to_check==TSYNC) {
937
938 close(sd);
939 my_tcp_connect (server_address, server_port, &sd);
940
941 xasprintf (&send_buffer,"S22\r\n");
942 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
943 if (result!=STATE_OK)
944 return result;
945
946 time_sync_status=atoi(recv_buffer);
947
948 if (time_sync_status==0) {
949 result=STATE_CRITICAL;
950 xasprintf (&output_message,_("CRITICAL - Time not in sync with network!"));
951 }
952 else {
953 xasprintf (&output_message,_("OK - Time in sync with network!"));
954 }
955
956
957
958
959
960 /* check LRU sitting time in secondss */
961 } else if (vars_to_check==LRUS) {
962
963 close(sd);
964 my_tcp_connect (server_address, server_port, &sd);
965
966 send_buffer = strdup ("S4\r\n");
967 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
968 if (result!=STATE_OK)
969 return result;
970 lru_time=strtoul(recv_buffer,NULL,10);
971
972 if (check_critical_value && lru_time <= critical_value)
973 result=STATE_CRITICAL;
974 else if (check_warning_value && lru_time <= warning_value)
975 result=STATE_WARNING;
976 xasprintf (&output_message,_("LRU sitting time = %lu seconds"),lru_time);
977
978
979 /* check % dirty cacheobuffers as a percentage of the total*/
980 } else if (vars_to_check==DCB) {
981
982 close(sd);
983 my_tcp_connect (server_address, server_port, &sd);
984
985 send_buffer = strdup ("S6\r\n");
986 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
987 if (result!=STATE_OK)
988 return result;
989 dirty_cache_buffers=atoi(recv_buffer);
990
991 if (check_critical_value && dirty_cache_buffers <= critical_value)
992 result=STATE_CRITICAL;
993 else if (check_warning_value && dirty_cache_buffers <= warning_value)
994 result=STATE_WARNING;
995 xasprintf (&output_message,_("Dirty cache buffers = %lu%% of the total|DCB=%lu;%lu;%lu;0;100"),
996 dirty_cache_buffers,
997 dirty_cache_buffers,
998 warning_value,
999 critical_value);
1000
1001 /* check % total cache buffers as a percentage of the original*/
1002 } else if (vars_to_check==TCB) {
1003
1004 close(sd);
1005 my_tcp_connect (server_address, server_port, &sd);
1006
1007 send_buffer = strdup ("S7\r\n");
1008 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1009 if (result!=STATE_OK)
1010 return result;
1011 total_cache_buffers=atoi(recv_buffer);
1012
1013 if (check_critical_value && total_cache_buffers <= critical_value)
1014 result=STATE_CRITICAL;
1015 else if (check_warning_value && total_cache_buffers <= warning_value)
1016 result=STATE_WARNING;
1017 xasprintf (&output_message,_("Total cache buffers = %lu%% of the original|TCB=%lu;%lu;%lu;0;100"),
1018 total_cache_buffers,
1019 total_cache_buffers,
1020 warning_value,
1021 critical_value);
1022
1023 } else if (vars_to_check==DSVER) {
1024
1025 close(sd);
1026 my_tcp_connect (server_address, server_port, &sd);
1027
1028 xasprintf (&send_buffer,"S13\r\n");
1029 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1030 if (result!=STATE_OK)
1031 return result;
1032
1033 recv_buffer[strlen(recv_buffer)-1]=0;
1034
1035 xasprintf (&output_message,_("NDS Version %s"),recv_buffer);
1036
1037 } else if (vars_to_check==UPTIME) {
1038
1039 close(sd);
1040 my_tcp_connect (server_address, server_port, &sd);
1041
1042 xasprintf (&send_buffer,"UPTIME\r\n");
1043 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1044 if (result!=STATE_OK)
1045 return result;
1046
1047
1048 recv_buffer[sizeof(recv_buffer)-1]=0;
1049 recv_buffer[strlen(recv_buffer)-1]=0;
1050
1051 xasprintf (&output_message,_("Up %s"),recv_buffer);
1052
1053 } else if (vars_to_check==NLM) {
1054
1055 close(sd);
1056 my_tcp_connect (server_address, server_port, &sd);
1057
1058 xasprintf (&send_buffer,"S24:%s\r\n",nlm_name);
1059 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1060 if (result!=STATE_OK)
1061 return result;
1062
1063 recv_buffer[strlen(recv_buffer)-1]=0;
1064 if (strcmp(recv_buffer,"-1")) {
1065 xasprintf (&output_message,_("Module %s version %s is loaded"),nlm_name,recv_buffer);
1066 } else {
1067 result=STATE_CRITICAL;
1068 xasprintf (&output_message,_("Module %s is not loaded"),nlm_name);
1069
1070 }
1071 } else if (vars_to_check==NRMP) {
1072
1073 xasprintf (&send_buffer,"NRMP:%s\r\n",nrmp_name);
1074 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1075 if (result!=STATE_OK)
1076 return result;
1077
1078 if (!strcmp(recv_buffer,"-1\n")) {
1079 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nrmp_name);
1080 result=STATE_CRITICAL;
1081 } else {
1082 nrmp_value=strtoul(recv_buffer,NULL,10);
1083 if (check_critical_value && nrmp_value <= critical_value)
1084 result=STATE_CRITICAL;
1085 else if (check_warning_value && nrmp_value <= warning_value)
1086 result=STATE_WARNING;
1087 xasprintf (&output_message,
1088 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1089 nrmp_name,
1090 nrmp_value,
1091 nrmp_name,
1092 nrmp_value,
1093 warning_value,
1094 critical_value);
1095 }
1096
1097 } else if (vars_to_check==NRMM) {
1098
1099 xasprintf (&send_buffer,"NRMM:%s\r\n",nrmm_name);
1100 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1101 if (result!=STATE_OK)
1102 return result;
1103
1104 if (!strcmp(recv_buffer,"-1\n")) {
1105 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nrmm_name);
1106 result=STATE_CRITICAL;
1107 } else {
1108 nrmm_value=strtoul(recv_buffer,NULL,10);
1109 if (check_critical_value && nrmm_value <= critical_value)
1110 result=STATE_CRITICAL;
1111 else if (check_warning_value && nrmm_value <= warning_value)
1112 result=STATE_WARNING;
1113 xasprintf (&output_message,
1114 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1115 nrmm_name,
1116 nrmm_value,
1117 nrmm_name,
1118 nrmm_value,
1119 warning_value,
1120 critical_value);
1121 }
1122
1123 } else if (vars_to_check==NRMS) {
1124
1125 xasprintf (&send_buffer,"NRMS:%s\r\n",nrms_name);
1126 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1127 if (result!=STATE_OK)
1128 return result;
1129
1130 if (!strcmp(recv_buffer,"-1\n")) {
1131 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nrms_name);
1132 result=STATE_CRITICAL;
1133 } else {
1134 nrms_value=strtoul(recv_buffer,NULL,10);
1135 if (check_critical_value && nrms_value >= critical_value)
1136 result=STATE_CRITICAL;
1137 else if (check_warning_value && nrms_value >= warning_value)
1138 result=STATE_WARNING;
1139 xasprintf (&output_message,
1140 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1141 nrms_name,
1142 nrms_value,
1143 nrms_name,
1144 nrms_value,
1145 warning_value,
1146 critical_value);
1147 }
1148
1149 } else if (vars_to_check==NSS1) {
1150
1151 xasprintf (&send_buffer,"NSS1:%s\r\n",nss1_name);
1152 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1153 if (result!=STATE_OK)
1154 return result;
1155
1156 if (!strcmp(recv_buffer,"-1\n")) {
1157 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss1_name);
1158 result=STATE_CRITICAL;
1159 } else {
1160 nss1_value=strtoul(recv_buffer,NULL,10);
1161 if (check_critical_value && nss1_value >= critical_value)
1162 result=STATE_CRITICAL;
1163 else if (check_warning_value && nss1_value >= warning_value)
1164 result=STATE_WARNING;
1165 xasprintf (&output_message,
1166 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1167 nss1_name,
1168 nss1_value,
1169 nss1_name,
1170 nss1_value,
1171 warning_value,
1172 critical_value);
1173 }
1174
1175 } else if (vars_to_check==NSS2) {
1176
1177 xasprintf (&send_buffer,"NSS2:%s\r\n",nss2_name);
1178 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1179 if (result!=STATE_OK)
1180 return result;
1181
1182 if (!strcmp(recv_buffer,"-1\n")) {
1183 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss2_name);
1184 result=STATE_CRITICAL;
1185 } else {
1186 nss2_value=strtoul(recv_buffer,NULL,10);
1187 if (check_critical_value && nss2_value >= critical_value)
1188 result=STATE_CRITICAL;
1189 else if (check_warning_value && nss2_value >= warning_value)
1190 result=STATE_WARNING;
1191 xasprintf (&output_message,
1192 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1193 nss2_name,
1194 nss2_value,
1195 nss2_name,
1196 nss2_value,
1197 warning_value,
1198 critical_value);
1199 }
1200
1201 } else if (vars_to_check==NSS3) {
1202
1203 xasprintf (&send_buffer,"NSS3:%s\r\n",nss3_name);
1204 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1205 if (result!=STATE_OK)
1206 return result;
1207
1208 if (!strcmp(recv_buffer,"-1\n")) {
1209 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss3_name);
1210 result=STATE_CRITICAL;
1211 } else {
1212 nss3_value=strtoul(recv_buffer,NULL,10);
1213 if (check_critical_value && nss3_value >= critical_value)
1214 result=STATE_CRITICAL;
1215 else if (check_warning_value && nss3_value >= warning_value)
1216 result=STATE_WARNING;
1217 xasprintf (&output_message,
1218 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1219 nss3_name,
1220 nss3_value,
1221 nss3_name,
1222 nss3_value,
1223 warning_value,
1224 critical_value);
1225 }
1226
1227 } else if (vars_to_check==NSS4) {
1228
1229 xasprintf (&send_buffer,"NSS4:%s\r\n",nss4_name);
1230 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1231 if (result!=STATE_OK)
1232 return result;
1233
1234 if (!strcmp(recv_buffer,"-1\n")) {
1235 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss4_name);
1236 result=STATE_CRITICAL;
1237 } else {
1238 nss4_value=strtoul(recv_buffer,NULL,10);
1239 if (check_critical_value && nss4_value >= critical_value)
1240 result=STATE_CRITICAL;
1241 else if (check_warning_value && nss4_value >= warning_value)
1242 result=STATE_WARNING;
1243 xasprintf (&output_message,
1244 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1245 nss4_name,
1246 nss4_value,
1247 nss4_name,
1248 nss4_value,
1249 warning_value,
1250 critical_value);
1251 }
1252
1253 } else if (vars_to_check==NSS5) {
1254
1255 xasprintf (&send_buffer,"NSS5:%s\r\n",nss5_name);
1256 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1257 if (result!=STATE_OK)
1258 return result;
1259
1260 if (!strcmp(recv_buffer,"-1\n")) {
1261 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss5_name);
1262 result=STATE_CRITICAL;
1263 } else {
1264 nss5_value=strtoul(recv_buffer,NULL,10);
1265 if (check_critical_value && nss5_value >= critical_value)
1266 result=STATE_CRITICAL;
1267 else if (check_warning_value && nss5_value >= warning_value)
1268 result=STATE_WARNING;
1269 xasprintf (&output_message,
1270 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1271 nss5_name,
1272 nss5_value,
1273 nss5_name,
1274 nss5_value,
1275 warning_value,
1276 critical_value);
1277 }
1278
1279 } else if (vars_to_check==NSS6) {
1280
1281 xasprintf (&send_buffer,"NSS6:%s\r\n",nss6_name);
1282 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1283 if (result!=STATE_OK)
1284 return result;
1285
1286 if (!strcmp(recv_buffer,"-1\n")) {
1287 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss6_name);
1288 result=STATE_CRITICAL;
1289 } else {
1290 nss6_value=strtoul(recv_buffer,NULL,10);
1291 if (check_critical_value && nss6_value >= critical_value)
1292 result=STATE_CRITICAL;
1293 else if (check_warning_value && nss6_value >= warning_value)
1294 result=STATE_WARNING;
1295 xasprintf (&output_message,
1296 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1297 nss6_name,
1298 nss6_value,
1299 nss6_name,
1300 nss6_value,
1301 warning_value,
1302 critical_value);
1303 }
1304
1305 } else if (vars_to_check==NSS7) {
1306
1307 xasprintf (&send_buffer,"NSS7:%s\r\n",nss7_name);
1308 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1309 if (result!=STATE_OK)
1310 return result;
1311
1312 if (!strcmp(recv_buffer,"-1\n")) {
1313 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss7_name);
1314 result=STATE_CRITICAL;
1315 } else {
1316 nss7_value=strtoul(recv_buffer,NULL,10);
1317 if (check_critical_value && nss7_value >= critical_value)
1318 result=STATE_CRITICAL;
1319 else if (check_warning_value && nss7_value >= warning_value)
1320 result=STATE_WARNING;
1321 xasprintf (&output_message,
1322 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1323 nss7_name,
1324 nss7_value,
1325 nss7_name,
1326 nss7_value,
1327 warning_value,
1328 critical_value);
1329 }
1330
1331
1332}
1333 else {
1334
1335 output_message = strdup (_("Nothing to check!\n"));
1336 result=STATE_UNKNOWN;
1337
1338 }
1339
1340 close (sd);
1341
1342 /* reset timeout */
1343 alarm(0);
1344
1345 printf("%s%s\n",netware_version,output_message);
1346
1347 return result;
1348}
1349
1350
1351
1352/* process command-line arguments */
1353int process_arguments(int argc, char **argv) {
1354 int c;
1355
1356 int option = 0;
1357 static struct option longopts[] =
1358 {
1359 {"port", required_argument,0,'p'},
1360 {"timeout", required_argument,0,'t'},
1361 {"critical", required_argument,0,'c'},
1362 {"warning", required_argument,0,'w'},
1363 {"variable", required_argument,0,'v'},
1364 {"hostname", required_argument,0,'H'},
1365 {"osversion",no_argument, 0,'o'},
1366 {"version", no_argument, 0,'V'},
1367 {"help", no_argument, 0,'h'},
1368 {0,0,0,0}
1369 };
1370
1371 /* no options were supplied */
1372 if (argc<2) return ERROR;
1373
1374 /* backwards compatibility */
1375 if (! is_option(argv[1])) {
1376 server_address=argv[1];
1377 argv[1]=argv[0];
1378 argv=&argv[1];
1379 argc--;
1380 }
1381
1382 for (c=1;c<argc;c++) {
1383 if (strcmp("-to",argv[c])==0)
1384 strcpy(argv[c],"-t");
1385 else if (strcmp("-wv",argv[c])==0)
1386 strcpy(argv[c],"-w");
1387 else if (strcmp("-cv",argv[c])==0)
1388 strcpy(argv[c],"-c");
1389 }
1390
1391 while (1) {
1392 c = getopt_long(argc,argv,"+hoVH:t:c:w:p:v:",longopts,&option);
1393
1394 if (c==-1||c==EOF||c==1)
1395 break;
1396
1397 switch (c)
1398 {
1399 case '?': /* print short usage statement if args not parsable */
1400 usage5 ();
1401 case 'h': /* help */
1402 print_help();
1403 exit(STATE_UNKNOWN);
1404 case 'V': /* version */
1405 print_revision(progname, NP_VERSION);
1406 exit(STATE_UNKNOWN);
1407 case 'H': /* hostname */
1408 server_address=optarg;
1409 break;
1410 case 'o': /* display nos version */
1411 check_netware_version = true;
1412 break;
1413 case 'p': /* port */
1414 if (is_intnonneg(optarg))
1415 server_port=atoi(optarg);
1416 else
1417 die(STATE_UNKNOWN,_("Server port an integer\n"));
1418 break;
1419 case 'v':
1420 if (strlen(optarg)<3)
1421 return ERROR;
1422 if (!strcmp(optarg,"LOAD1"))
1423 vars_to_check=LOAD1;
1424 else if (!strcmp(optarg,"LOAD5"))
1425 vars_to_check=LOAD5;
1426 else if (!strcmp(optarg,"LOAD15"))
1427 vars_to_check=LOAD15;
1428 else if (!strcmp(optarg,"CONNS"))
1429 vars_to_check=CONNS;
1430 else if (!strcmp(optarg,"LTCH"))
1431 vars_to_check=LTCH;
1432 else if (!strcmp(optarg,"DCB"))
1433 vars_to_check=DCB;
1434 else if (!strcmp(optarg,"TCB"))
1435 vars_to_check=TCB;
1436 else if (!strcmp(optarg,"CBUFF"))
1437 vars_to_check=CBUFF;
1438 else if (!strcmp(optarg,"CDBUFF"))
1439 vars_to_check=CDBUFF;
1440 else if (!strcmp(optarg,"LRUM"))
1441 vars_to_check=LRUM;
1442 else if (!strcmp(optarg,"LRUS"))
1443 vars_to_check=LRUS;
1444 else if (strncmp(optarg,"VPF",3)==0) {
1445 vars_to_check=VPF;
1446 volume_name = strdup (optarg+3);
1447 if (!strcmp(volume_name,""))
1448 volume_name = strdup ("SYS");
1449 }
1450 else if (strncmp(optarg,"VKF",3)==0) {
1451 vars_to_check=VKF;
1452 volume_name = strdup (optarg+3);
1453 if (!strcmp(volume_name,""))
1454 volume_name = strdup ("SYS");
1455 }
1456 else if (strncmp(optarg,"VMF",3)==0) {
1457 vars_to_check=VMF;
1458 volume_name = strdup (optarg+3);
1459 if (!strcmp(volume_name,""))
1460 volume_name = strdup ("SYS");
1461 }
1462 else if (!strcmp(optarg,"DSDB"))
1463 vars_to_check=DSDB;
1464 else if (!strcmp(optarg,"LOGINS"))
1465 vars_to_check=LOGINS;
1466 else if (!strcmp(optarg,"NRMH"))
1467 vars_to_check=NRMH;
1468 else if (!strcmp(optarg,"UPRB"))
1469 vars_to_check=UPRB;
1470 else if (!strcmp(optarg,"PUPRB"))
1471 vars_to_check=PUPRB;
1472 else if (!strncmp(optarg,"SAPENTRIES",10)) {
1473 vars_to_check=SAPENTRIES;
1474 if (strlen(optarg)>10)
1475 sap_number=atoi(optarg+10);
1476 else
1477 sap_number=-1;
1478 }
1479 else if (!strcmp(optarg,"OFILES"))
1480 vars_to_check=OFILES;
1481 else if (strncmp(optarg,"VKP",3)==0) {
1482 vars_to_check=VKP;
1483 volume_name = strdup (optarg+3);
1484 if (!strcmp(volume_name,""))
1485 volume_name = strdup ("SYS");
1486 }
1487 else if (strncmp(optarg,"VMP",3)==0) {
1488 vars_to_check=VMP;
1489 volume_name = strdup (optarg+3);
1490 if (!strcmp(volume_name,""))
1491 volume_name = strdup ("SYS");
1492 }
1493 else if (strncmp(optarg,"VMU",3)==0) {
1494 vars_to_check=VMU;
1495 volume_name = strdup (optarg+3);
1496 if (!strcmp(volume_name,""))
1497 volume_name = strdup ("SYS");
1498 }
1499 else if (strncmp(optarg,"VPU",3)==0) {
1500 vars_to_check=VPU;
1501 volume_name = strdup (optarg+3);
1502 if (!strcmp(volume_name,""))
1503 volume_name = strdup ("SYS");
1504 }
1505 else if (strncmp(optarg,"VPP",3)==0) {
1506 vars_to_check=VPP;
1507 volume_name = strdup (optarg+3);
1508 if (!strcmp(volume_name,""))
1509 volume_name = strdup ("SYS");
1510 }
1511 else if (strncmp(optarg,"VKNP",4)==0) {
1512 vars_to_check=VKNP;
1513 volume_name = strdup (optarg+4);
1514 if (!strcmp(volume_name,""))
1515 volume_name = strdup ("SYS");
1516 }
1517 else if (strncmp(optarg,"VPNP",4)==0) {
1518 vars_to_check=VPNP;
1519 volume_name = strdup (optarg+4);
1520 if (!strcmp(volume_name,""))
1521 volume_name = strdup("SYS");
1522 }
1523 else if (!strcmp(optarg,"ABENDS"))
1524 vars_to_check=ABENDS;
1525 else if (!strcmp(optarg,"CSPROCS"))
1526 vars_to_check=CSPROCS;
1527 else if (!strcmp(optarg,"TSYNC"))
1528 vars_to_check=TSYNC;
1529 else if (!strcmp(optarg,"DSVER"))
1530 vars_to_check=DSVER;
1531 else if (!strcmp(optarg,"UPTIME")) {
1532 vars_to_check=UPTIME;
1533 }
1534 else if (strncmp(optarg,"NLM:",4)==0) {
1535 vars_to_check=NLM;
1536 nlm_name=strdup (optarg+4);
1537 }
1538 else if (strncmp(optarg,"NRMP",4)==0) {
1539 vars_to_check=NRMP;
1540 nrmp_name = strdup (optarg+4);
1541 if (!strcmp(nrmp_name,""))
1542 nrmp_name = strdup ("AVAILABLE_MEMORY");
1543 }
1544 else if (strncmp(optarg,"NRMM",4)==0) {
1545 vars_to_check=NRMM;
1546 nrmm_name = strdup (optarg+4);
1547 if (!strcmp(nrmm_name,""))
1548 nrmm_name = strdup ("AVAILABLE_CACHE_MEMORY");
1549
1550 }
1551
1552 else if (strncmp(optarg,"NRMS",4)==0) {
1553 vars_to_check=NRMS;
1554 nrms_name = strdup (optarg+4);
1555 if (!strcmp(nrms_name,""))
1556 nrms_name = strdup ("USED_SWAP_SPACE");
1557
1558 }
1559
1560 else if (strncmp(optarg,"NSS1",4)==0) {
1561 vars_to_check=NSS1;
1562 nss1_name = strdup (optarg+4);
1563 if (!strcmp(nss1_name,""))
1564 nss1_name = strdup ("CURRENTBUFFERCACHESIZE");
1565
1566 }
1567
1568 else if (strncmp(optarg,"NSS2",4)==0) {
1569 vars_to_check=NSS2;
1570 nss2_name = strdup (optarg+4);
1571 if (!strcmp(nss2_name,""))
1572 nss2_name = strdup ("CACHEHITS");
1573
1574 }
1575
1576 else if (strncmp(optarg,"NSS3",4)==0) {
1577 vars_to_check=NSS3;
1578 nss3_name = strdup (optarg+4);
1579 if (!strcmp(nss3_name,""))
1580 nss3_name = strdup ("CACHEGITPERCENT");
1581
1582 }
1583
1584 else if (strncmp(optarg,"NSS4",4)==0) {
1585 vars_to_check=NSS4;
1586 nss4_name = strdup (optarg+4);
1587 if (!strcmp(nss4_name,""))
1588 nss4_name = strdup ("CURRENTOPENCOUNT");
1589
1590 }
1591
1592 else if (strncmp(optarg,"NSS5",4)==0) {
1593 vars_to_check=NSS5;
1594 nss5_name = strdup (optarg+4);
1595 if (!strcmp(nss5_name,""))
1596 nss5_name = strdup ("CACHEMISSES");
1597
1598 }
1599
1600
1601 else if (strncmp(optarg,"NSS6",4)==0) {
1602 vars_to_check=NSS6;
1603 nss6_name = strdup (optarg+4);
1604 if (!strcmp(nss6_name,""))
1605 nss6_name = strdup ("PENDINGWORKSCOUNT");
1606
1607 }
1608
1609
1610 else if (strncmp(optarg,"NSS7",4)==0) {
1611 vars_to_check=NSS7;
1612 nss7_name = strdup (optarg+4);
1613 if (!strcmp(nss7_name,""))
1614 nss7_name = strdup ("CACHESIZE");
1615
1616 }
1617
1618
1619 else
1620 return ERROR;
1621 break;
1622 case 'w': /* warning threshold */
1623 warning_value=strtoul(optarg,NULL,10);
1624 check_warning_value = true;
1625 break;
1626 case 'c': /* critical threshold */
1627 critical_value=strtoul(optarg,NULL,10);
1628 check_critical_value = true;
1629 break;
1630 case 't': /* timeout */
1631 socket_timeout=atoi(optarg);
1632 if (socket_timeout<=0)
1633 return ERROR;
1634 }
1635
1636 }
1637
1638 return OK;
1639}
1640
1641
1642
1643void print_help(void)
1644{
1645 char *myport;
1646 xasprintf (&myport, "%d", PORT);
1647
1648 print_revision (progname, NP_VERSION);
1649
1650 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1651 printf (COPYRIGHT, copyright, email);
1652
1653 printf ("%s\n", _("This plugin attempts to contact the MRTGEXT NLM running on a"));
1654 printf ("%s\n", _("Novell server to gather the requested system information."));
1655
1656 printf ("\n\n");
1657
1658 print_usage();
1659
1660 printf (UT_HELP_VRSN);
1661 printf (UT_EXTRA_OPTS);
1662
1663 printf (UT_HOST_PORT, 'p', myport);
1664
1665 printf (" %s\n", "-v, --variable=STRING");
1666 printf (" %s\n", _("Variable to check. Valid variables include:"));
1667 printf (" %s\n", _("LOAD1 = 1 minute average CPU load"));
1668 printf (" %s\n", _("LOAD5 = 5 minute average CPU load"));
1669 printf (" %s\n", _("LOAD15 = 15 minute average CPU load"));
1670 printf (" %s\n", _("CSPROCS = number of current service processes (NW 5.x only)"));
1671 printf (" %s\n", _("ABENDS = number of abended threads (NW 5.x only)"));
1672 printf (" %s\n", _("UPTIME = server uptime"));
1673 printf (" %s\n", _("LTCH = percent long term cache hits"));
1674 printf (" %s\n", _("CBUFF = current number of cache buffers"));
1675 printf (" %s\n", _("CDBUFF = current number of dirty cache buffers"));
1676 printf (" %s\n", _("DCB = dirty cache buffers as a percentage of the total"));
1677 printf (" %s\n", _("TCB = dirty cache buffers as a percentage of the original"));
1678 printf (" %s\n", _("OFILES = number of open files"));
1679 printf (" %s\n", _(" VMF<vol> = MB of free space on Volume <vol>"));
1680 printf (" %s\n", _(" VMU<vol> = MB used space on Volume <vol>"));
1681 printf (" %s\n", _(" VPU<vol> = percent used space on Volume <vol>"));
1682 printf (" %s\n", _(" VMP<vol> = MB of purgeable space on Volume <vol>"));
1683 printf (" %s\n", _(" VPF<vol> = percent free space on volume <vol>"));
1684 printf (" %s\n", _(" VKF<vol> = KB of free space on volume <vol>"));
1685 printf (" %s\n", _(" VPP<vol> = percent purgeable space on volume <vol>"));
1686 printf (" %s\n", _(" VKP<vol> = KB of purgeable space on volume <vol>"));
1687 printf (" %s\n", _(" VPNP<vol> = percent not yet purgeable space on volume <vol>"));
1688 printf (" %s\n", _(" VKNP<vol> = KB of not yet purgeable space on volume <vol>"));
1689 printf (" %s\n", _(" LRUM = LRU sitting time in minutes"));
1690 printf (" %s\n", _(" LRUS = LRU sitting time in seconds"));
1691 printf (" %s\n", _(" DSDB = check to see if DS Database is open"));
1692 printf (" %s\n", _(" DSVER = NDS version"));
1693 printf (" %s\n", _(" UPRB = used packet receive buffers"));
1694 printf (" %s\n", _(" PUPRB = percent (of max) used packet receive buffers"));
1695 printf (" %s\n", _(" SAPENTRIES = number of entries in the SAP table"));
1696 printf (" %s\n", _(" SAPENTRIES<n> = number of entries in the SAP table for SAP type <n>"));
1697 printf (" %s\n", _(" TSYNC = timesync status"));
1698 printf (" %s\n", _(" LOGINS = check to see if logins are enabled"));
1699 printf (" %s\n", _(" CONNS = number of currently licensed connections"));
1700 printf (" %s\n", _(" NRMH = NRM Summary Status"));
1701 printf (" %s\n", _(" NRMP<stat> = Returns the current value for a NRM health item"));
1702 printf (" %s\n", _(" NRMM<stat> = Returns the current memory stats from NRM"));
1703 printf (" %s\n", _(" NRMS<stat> = Returns the current Swapfile stats from NRM"));
1704 printf (" %s\n", _(" NSS1<stat> = Statistics from _Admin:Manage_NSS\\GeneralStats.xml"));
1705 printf (" %s\n", _(" NSS3<stat> = Statistics from _Admin:Manage_NSS\\NameCache.xml"));
1706 printf (" %s\n", _(" NSS4<stat> = Statistics from _Admin:Manage_NSS\\FileStats.xml"));
1707 printf (" %s\n", _(" NSS5<stat> = Statistics from _Admin:Manage_NSS\\ObjectCache.xml"));
1708 printf (" %s\n", _(" NSS6<stat> = Statistics from _Admin:Manage_NSS\\Thread.xml"));
1709 printf (" %s\n", _(" NSS7<stat> = Statistics from _Admin:Manage_NSS\\AuthorizationCache.xml"));
1710 printf (" %s\n", _(" NLM:<nlm> = check if NLM is loaded and report version"));
1711 printf (" %s\n", _(" (e.g. NLM:TSANDS.NLM)"));
1712 printf ("\n");
1713 printf (" %s\n", "-w, --warning=INTEGER");
1714 printf (" %s\n", _("Threshold which will result in a warning status"));
1715 printf (" %s\n", "-c, --critical=INTEGER");
1716 printf (" %s\n", _("Threshold which will result in a critical status"));
1717 printf (" %s\n", "-o, --osversion");
1718 printf (" %s\n", _("Include server version string in results"));
1719
1720 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1721
1722 printf ("\n");
1723 printf ("%s\n", _("Notes:"));
1724 printf (" %s\n", _("- This plugin requires that the MRTGEXT.NLM file from James Drews' MRTG"));
1725 printf (" %s\n", _(" extension for NetWare be loaded on the Novell servers you wish to check."));
1726 printf (" %s\n", _(" (available from http://www.engr.wisc.edu/~drews/mrtg/)"));
1727 printf (" %s\n", _("- Values for critical thresholds should be lower than warning thresholds"));
1728 printf (" %s\n", _(" when the following variables are checked: VPF, VKF, LTCH, CBUFF, DCB, "));
1729 printf (" %s\n", _(" TCB, LRUS and LRUM."));
1730
1731 printf (UT_SUPPORT);
1732}
1733
1734
1735
1736void print_usage(void)
1737{
1738 printf ("%s\n", _("Usage:"));
1739 printf ("%s -H host [-p port] [-v variable] [-w warning] [-c critical] [-t timeout]\n",progname);
1740}
diff --git a/plugins/check_overcr.c b/plugins/check_overcr.c
deleted file mode 100644
index 5165c828..00000000
--- a/plugins/check_overcr.c
+++ /dev/null
@@ -1,469 +0,0 @@
1/*****************************************************************************
2*
3* Monitoring check_overcr plugin
4*
5* License: GPL
6* Copyright (c) 2000-2007 Monitoring Plugins Development Team
7*
8* Description:
9*
10* This file contains the check_overcr plugin
11*
12* This plugin attempts to contact the Over-CR collector daemon running on the
13* remote UNIX server in order 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_overcr";
33const char *copyright = "2000-2007";
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,
43 LOAD5,
44 LOAD15,
45 DPU,
46 PROCS,
47 NETSTAT,
48 UPTIME
49};
50
51enum {
52 PORT = 2000
53};
54
55char *server_address = NULL;
56int server_port = PORT;
57double warning_value = 0L;
58double critical_value = 0L;
59bool check_warning_value = false;
60bool check_critical_value = false;
61enum checkvar vars_to_check = NONE;
62int cmd_timeout = 1;
63
64int netstat_port = 0;
65char *disk_name = NULL;
66char *process_name = NULL;
67char send_buffer[MAX_INPUT_BUFFER];
68
69int process_arguments (int, char **);
70void print_usage (void);
71void print_help (void);
72
73int
74main (int argc, char **argv)
75{
76 int result = STATE_UNKNOWN;
77 char recv_buffer[MAX_INPUT_BUFFER];
78 char temp_buffer[MAX_INPUT_BUFFER];
79 char *temp_ptr = NULL;
80 bool found_disk = false;
81 unsigned long percent_used_disk_space = 100;
82 double load;
83 double load_1min;
84 double load_5min;
85 double load_15min;
86 int port_connections = 0;
87 int processes = 0;
88 double uptime_raw_hours;
89 int uptime_raw_minutes = 0;
90 int uptime_days = 0;
91 int uptime_hours = 0;
92 int uptime_minutes = 0;
93
94 setlocale (LC_ALL, "");
95 bindtextdomain (PACKAGE, LOCALEDIR);
96 textdomain (PACKAGE);
97
98 /* Parse extra opts if any */
99 argv=np_extra_opts (&argc, argv, progname);
100
101 if (process_arguments (argc, argv) == ERROR)
102 usage4 (_("Could not parse arguments"));
103
104 /* initialize alarm signal handling */
105 signal (SIGALRM, socket_timeout_alarm_handler);
106
107 /* set socket timeout */
108 alarm (socket_timeout);
109
110 result = process_tcp_request2 (server_address,
111 server_port,
112 send_buffer,
113 recv_buffer,
114 sizeof (recv_buffer));
115
116 switch (vars_to_check) {
117
118 case LOAD1:
119 case LOAD5:
120 case LOAD15:
121
122 if (result != STATE_OK)
123 die (result, _("Unknown error fetching load data\n"));
124
125 temp_ptr = (char *) strtok (recv_buffer, "\r\n");
126 if (temp_ptr == NULL)
127 die (STATE_CRITICAL, _("Invalid response from server - no load information\n"));
128 else
129 load_1min = strtod (temp_ptr, NULL);
130
131 temp_ptr = (char *) strtok (NULL, "\r\n");
132 if (temp_ptr == NULL)
133 die (STATE_CRITICAL, _("Invalid response from server after load 1\n"));
134 else
135 load_5min = strtod (temp_ptr, NULL);
136
137 temp_ptr = (char *) strtok (NULL, "\r\n");
138 if (temp_ptr == NULL)
139 die (STATE_CRITICAL, _("Invalid response from server after load 5\n"));
140 else
141 load_15min = strtod (temp_ptr, NULL);
142
143 switch (vars_to_check) {
144 case LOAD1:
145 strcpy (temp_buffer, "1");
146 load = load_1min;
147 break;
148 case LOAD5:
149 strcpy (temp_buffer, "5");
150 load = load_5min;
151 break;
152 default:
153 strcpy (temp_buffer, "15");
154 load = load_15min;
155 break;
156 }
157
158 if (check_critical_value && (load >= critical_value))
159 result = STATE_CRITICAL;
160 else if (check_warning_value && (load >= warning_value))
161 result = STATE_WARNING;
162
163 die (result,
164 _("Load %s - %s-min load average = %0.2f"),
165 state_text(result),
166 temp_buffer,
167 load);
168
169 break;
170
171 case DPU:
172
173 if (result != STATE_OK)
174 die (result, _("Unknown error fetching disk data\n"));
175
176 for (temp_ptr = (char *) strtok (recv_buffer, " ");
177 temp_ptr != NULL;
178 temp_ptr = (char *) strtok (NULL, " ")) {
179
180 if (!strcmp (temp_ptr, disk_name)) {
181 found_disk = true;
182 temp_ptr = (char *) strtok (NULL, "%");
183 if (temp_ptr == NULL)
184 die (STATE_CRITICAL, _("Invalid response from server\n"));
185 else
186 percent_used_disk_space = strtoul (temp_ptr, NULL, 10);
187 break;
188 }
189
190 temp_ptr = (char *) strtok (NULL, "\r\n");
191 }
192
193 /* error if we couldn't find the info for the disk */
194 if (!found_disk)
195 die (STATE_CRITICAL,
196 "CRITICAL - Disk '%s' non-existent or not mounted",
197 disk_name);
198
199 if (check_critical_value && (percent_used_disk_space >= critical_value))
200 result = STATE_CRITICAL;
201 else if (check_warning_value && (percent_used_disk_space >= warning_value))
202 result = STATE_WARNING;
203
204 die (result, "Disk %s - %lu%% used on %s", state_text(result), percent_used_disk_space, disk_name);
205
206 break;
207
208 case NETSTAT:
209
210 if (result != STATE_OK)
211 die (result, _("Unknown error fetching network status\n"));
212 else
213 port_connections = strtod (recv_buffer, NULL);
214
215 if (check_critical_value && (port_connections >= critical_value))
216 result = STATE_CRITICAL;
217 else if (check_warning_value && (port_connections >= warning_value))
218 result = STATE_WARNING;
219
220 die (result,
221 _("Net %s - %d connection%s on port %d"),
222 state_text(result),
223 port_connections,
224 (port_connections == 1) ? "" : "s",
225 netstat_port);
226
227 break;
228
229 case PROCS:
230
231 if (result != STATE_OK)
232 die (result, _("Unknown error fetching process status\n"));
233
234 temp_ptr = (char *) strtok (recv_buffer, "(");
235 if (temp_ptr == NULL)
236 die (STATE_CRITICAL, _("Invalid response from server\n"));
237
238 temp_ptr = (char *) strtok (NULL, ")");
239 if (temp_ptr == NULL)
240 die (STATE_CRITICAL, _("Invalid response from server\n"));
241 else
242 processes = strtod (temp_ptr, NULL);
243
244 if (check_critical_value && (processes >= critical_value))
245 result = STATE_CRITICAL;
246 else if (check_warning_value && (processes >= warning_value))
247 result = STATE_WARNING;
248
249 die (result,
250 _("Process %s - %d instance%s of %s running"),
251 state_text(result),
252 processes,
253 (processes == 1) ? "" : "s",
254 process_name);
255 break;
256
257 case UPTIME:
258
259 if (result != STATE_OK)
260 return result;
261
262 uptime_raw_hours = strtod (recv_buffer, NULL);
263 uptime_raw_minutes = (unsigned long) (uptime_raw_hours * 60.0);
264
265 if (check_critical_value && (uptime_raw_minutes <= critical_value))
266 result = STATE_CRITICAL;
267 else if (check_warning_value && (uptime_raw_minutes <= warning_value))
268 result = STATE_WARNING;
269
270 uptime_days = uptime_raw_minutes / 1440;
271 uptime_raw_minutes %= 1440;
272 uptime_hours = uptime_raw_minutes / 60;
273 uptime_raw_minutes %= 60;
274 uptime_minutes = uptime_raw_minutes;
275
276 die (result,
277 _("Uptime %s - Up %d days %d hours %d minutes"),
278 state_text(result),
279 uptime_days,
280 uptime_hours,
281 uptime_minutes);
282 break;
283
284 default:
285 die (STATE_UNKNOWN, _("Nothing to check!\n"));
286 break;
287 }
288}
289
290
291/* process command-line arguments */
292int
293process_arguments (int argc, char **argv)
294{
295 int c;
296
297 int option = 0;
298 static struct option longopts[] = {
299 {"port", required_argument, 0, 'p'},
300 {"timeout", required_argument, 0, 't'},
301 {"critical", required_argument, 0, 'c'},
302 {"warning", required_argument, 0, 'w'},
303 {"variable", required_argument, 0, 'v'},
304 {"hostname", required_argument, 0, 'H'},
305 {"version", no_argument, 0, 'V'},
306 {"help", no_argument, 0, 'h'},
307 {0, 0, 0, 0}
308 };
309
310 /* no options were supplied */
311 if (argc < 2)
312 return ERROR;
313
314 /* backwards compatibility */
315 if (!is_option (argv[1])) {
316 server_address = argv[1];
317 argv[1] = argv[0];
318 argv = &argv[1];
319 argc--;
320 }
321
322 for (c = 1; c < argc; c++) {
323 if (strcmp ("-to", argv[c]) == 0)
324 strcpy (argv[c], "-t");
325 else if (strcmp ("-wv", argv[c]) == 0)
326 strcpy (argv[c], "-w");
327 else if (strcmp ("-cv", argv[c]) == 0)
328 strcpy (argv[c], "-c");
329 }
330
331 while (1) {
332 c = getopt_long (argc, argv, "+hVH:t:c:w:p:v:", longopts,
333 &option);
334
335 if (c == -1 || c == EOF || c == 1)
336 break;
337
338 switch (c) {
339 case '?': /* print short usage statement if args not parsable */
340 usage5 ();
341 case 'h': /* help */
342 print_help ();
343 exit (STATE_UNKNOWN);
344 case 'V': /* version */
345 print_revision (progname, NP_VERSION);
346 exit (STATE_UNKNOWN);
347 case 'H': /* hostname */
348 server_address = optarg;
349 break;
350 case 'p': /* port */
351 if (is_intnonneg (optarg))
352 server_port = atoi (optarg);
353 else
354 die (STATE_UNKNOWN,
355 _("Server port an integer\n"));
356 break;
357 case 'v': /* variable */
358 if (strcmp (optarg, "LOAD") == 0) {
359 strcpy (send_buffer, "LOAD\r\nQUIT\r\n");
360 if (strcmp (optarg, "LOAD1") == 0)
361 vars_to_check = LOAD1;
362 else if (strcmp (optarg, "LOAD5") == 0)
363 vars_to_check = LOAD5;
364 else if (strcmp (optarg, "LOAD15") == 0)
365 vars_to_check = LOAD15;
366 }
367 else if (strcmp (optarg, "UPTIME") == 0) {
368 vars_to_check = UPTIME;
369 strcpy (send_buffer, "UPTIME\r\n");
370 }
371 else if (strstr (optarg, "PROC") == optarg) {
372 vars_to_check = PROCS;
373 process_name = strscpy (process_name, optarg + 4);
374 sprintf (send_buffer, "PROCESS %s\r\n", process_name);
375 }
376 else if (strstr (optarg, "NET") == optarg) {
377 vars_to_check = NETSTAT;
378 netstat_port = atoi (optarg + 3);
379 sprintf (send_buffer, "NETSTAT %d\r\n", netstat_port);
380 }
381 else if (strstr (optarg, "DPU") == optarg) {
382 vars_to_check = DPU;
383 strcpy (send_buffer, "DISKSPACE\r\n");
384 disk_name = strscpy (disk_name, optarg + 3);
385 }
386 else
387 return ERROR;
388 break;
389 case 'w': /* warning threshold */
390 warning_value = strtoul (optarg, NULL, 10);
391 check_warning_value = true;
392 break;
393 case 'c': /* critical threshold */
394 critical_value = strtoul (optarg, NULL, 10);
395 check_critical_value = true;
396 break;
397 case 't': /* timeout */
398 socket_timeout = atoi (optarg);
399 if (socket_timeout <= 0)
400 return ERROR;
401 }
402
403 }
404 return OK;
405}
406
407
408void
409print_help (void)
410{
411 char *myport;
412 xasprintf (&myport, "%d", PORT);
413
414 print_revision (progname, NP_VERSION);
415
416 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
417 printf (COPYRIGHT, copyright, email);
418
419 printf ("%s\n", _("This plugin attempts to contact the Over-CR collector daemon running on the"));
420 printf ("%s\n", _("remote UNIX server in order to gather the requested system information."));
421
422 printf ("\n\n");
423
424 print_usage ();
425
426 printf (UT_HELP_VRSN);
427 printf (UT_EXTRA_OPTS);
428
429 printf (UT_HOST_PORT, 'p', myport);
430
431 printf (" %s\n", "-w, --warning=INTEGER");
432 printf (" %s\n", _("Threshold which will result in a warning status"));
433 printf (" %s\n", "-c, --critical=INTEGER");
434 printf (" %s\n", _("Threshold which will result in a critical status"));
435 printf (" %s\n", "-v, --variable=STRING");
436 printf (" %s\n", _("Variable to check. Valid variables include:"));
437 printf (" %s\n", _("LOAD1 = 1 minute average CPU load"));
438 printf (" %s\n", _("LOAD5 = 5 minute average CPU load"));
439 printf (" %s\n", _("LOAD15 = 15 minute average CPU load"));
440 printf (" %s\n", _("DPU<filesys> = percent used disk space on filesystem <filesys>"));
441 printf (" %s\n", _("PROC<process> = number of running processes with name <process>"));
442 printf (" %s\n", _("NET<port> = number of active connections on TCP port <port>"));
443 printf (" %s\n", _("UPTIME = system uptime in seconds"));
444
445 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
446
447 printf (UT_VERBOSE);
448
449 printf ("\n");
450 printf ("%s\n", _("This plugin requires that Eric Molitors' Over-CR collector daemon be"));
451 printf ("%s\n", _("running on the remote server."));
452 printf ("%s\n", _("Over-CR can be downloaded from http://www.molitor.org/overcr"));
453 printf ("%s\n", _("This plugin was tested with version 0.99.53 of the Over-CR collector"));
454
455 printf ("\n");
456 printf ("%s\n", _("Notes:"));
457 printf (" %s\n", _("For the available options, the critical threshold value should always be"));
458 printf (" %s\n", _("higher than the warning threshold value, EXCEPT with the uptime variable"));
459
460 printf (UT_SUPPORT);
461}
462
463
464void
465print_usage (void)
466{
467 printf ("%s\n", _("Usage:"));
468 printf ("%s -H host [-p port] [-v variable] [-w warning] [-c critical] [-t timeout]\n", progname);
469}
diff --git a/plugins/check_pgsql.c b/plugins/check_pgsql.c
index 94d589e1..84305adb 100644
--- a/plugins/check_pgsql.c
+++ b/plugins/check_pgsql.c
@@ -1,95 +1,75 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_pgsql plugin 3 * Monitoring check_pgsql plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2011 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_pgsql plugin 10 * This file contains the check_pgsql plugin
11* 11 *
12* Test whether a PostgreSQL Database is accepting connections. 12 * Test whether a PostgreSQL Database 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
31#include "states.h"
31const char *progname = "check_pgsql"; 32const char *progname = "check_pgsql";
32const char *copyright = "1999-2011"; 33const char *copyright = "1999-2024";
33const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
34 35
35#include "common.h" 36#include "common.h"
36#include "utils.h" 37#include "utils.h"
37#include "utils_cmd.h" 38#include "utils_cmd.h"
39#include "check_pgsql.d/config.h"
40#include "thresholds.h"
38 41
39#include "netutils.h" 42#include "netutils.h"
40#include <libpq-fe.h> 43#include <libpq-fe.h>
41#include <pg_config_manual.h> 44#include <pg_config_manual.h>
42 45
43#define DEFAULT_DB "template1"
44#define DEFAULT_HOST "127.0.0.1" 46#define DEFAULT_HOST "127.0.0.1"
45 47
46/* return the PSQL server version as a 3-tuple */ 48/* return the PSQL server version as a 3-tuple */
47#define PSQL_SERVER_VERSION3(server_version) \ 49#define PSQL_SERVER_VERSION3(server_version) \
48 (server_version) / 10000, \ 50 (server_version) / 10000, (server_version) / 100 - (int)((server_version) / 10000) * 100, \
49 (server_version) / 100 - (int)((server_version) / 10000) * 100, \ 51 (server_version) - (int)((server_version) / 100) * 100
50 (server_version) - (int)((server_version) / 100) * 100
51/* return true if the given host is a UNIX domain socket */ 52/* return true if the given host is a UNIX domain socket */
52#define PSQL_IS_UNIX_DOMAIN_SOCKET(host) \ 53#define PSQL_IS_UNIX_DOMAIN_SOCKET(host) ((NULL == (host)) || ('\0' == *(host)) || ('/' == *(host)))
53 ((NULL == (host)) || ('\0' == *(host)) || ('/' == *(host)))
54/* return a 3-tuple identifying a host/port independent of the socket type */ 54/* return a 3-tuple identifying a host/port independent of the socket type */
55#define PSQL_SOCKET3(host, port) \ 55#define PSQL_SOCKET3(host, port) \
56 ((NULL == (host)) || ('\0' == *(host))) ? DEFAULT_PGSOCKET_DIR : host, \ 56 ((NULL == (host)) || ('\0' == *(host))) ? DEFAULT_PGSOCKET_DIR : host, PSQL_IS_UNIX_DOMAIN_SOCKET(host) ? "/.s.PGSQL." : ":", port
57 PSQL_IS_UNIX_DOMAIN_SOCKET (host) ? "/.s.PGSQL." : ":", \ 57
58 port 58typedef struct {
59 59 int errorcode;
60enum { 60 check_pgsql_config config;
61 DEFAULT_PORT = 5432, 61} check_pgsql_config_wrapper;
62 DEFAULT_WARN = 2, 62static check_pgsql_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
63 DEFAULT_CRIT = 8 63
64}; 64static void print_help(void);
65 65static bool is_pg_logname(char * /*username*/);
66 66static mp_state_enum do_query(PGconn * /*conn*/, char * /*query*/, const char /*pgqueryname*/[], thresholds * /*qthresholds*/,
67 67 char * /*query_warning*/, char * /*query_critical*/);
68int process_arguments (int, char **); 68void print_usage(void);
69int validate_arguments (void); 69
70void print_usage (void); 70static int verbose = 0;
71void print_help (void); 71
72bool is_pg_logname (char *);
73int do_query (PGconn *, char *);
74
75char *pghost = NULL; /* host name of the backend server */
76char *pgport = NULL; /* port of the backend server */
77int default_port = DEFAULT_PORT;
78char *pgoptions = NULL;
79char *pgtty = NULL;
80char dbName[NAMEDATALEN] = DEFAULT_DB;
81char *pguser = NULL;
82char *pgpasswd = NULL;
83char *pgparams = NULL;
84double twarn = (double)DEFAULT_WARN;
85double tcrit = (double)DEFAULT_CRIT;
86char *pgquery = NULL;
87#define OPTID_QUERYNAME -1000 72#define OPTID_QUERYNAME -1000
88char *pgqueryname = NULL;
89char *query_warning = NULL;
90char *query_critical = NULL;
91thresholds *qthresholds = NULL;
92int verbose = 0;
93 73
94/****************************************************************************** 74/******************************************************************************
95 75
@@ -141,237 +121,235 @@ Please note that all tags must be lowercase to use the DocBook XML DTD.
141-@@ 121-@@
142******************************************************************************/ 122******************************************************************************/
143 123
124int main(int argc, char **argv) {
125 setlocale(LC_ALL, "");
126 bindtextdomain(PACKAGE, LOCALEDIR);
127 textdomain(PACKAGE);
144 128
129 /* Parse extra opts if any */
130 argv = np_extra_opts(&argc, argv, progname);
145 131
146int 132 check_pgsql_config_wrapper tmp_config = process_arguments(argc, argv);
147main (int argc, char **argv) 133 if (tmp_config.errorcode == ERROR) {
148{ 134 usage4(_("Could not parse arguments"));
149 PGconn *conn; 135 }
150 char *conninfo = NULL;
151
152 struct timeval start_timeval;
153 struct timeval end_timeval;
154 double elapsed_time;
155 int status = STATE_UNKNOWN;
156 int query_status = STATE_UNKNOWN;
157
158 /* begin, by setting the parameters for a backend connection if the
159 * parameters are null, then the system will try to use reasonable
160 * defaults by looking up environment variables or, failing that,
161 * using hardwired constants */
162
163 pgoptions = NULL; /* special options to start up the backend server */
164 pgtty = NULL; /* debugging tty for the backend server */
165
166 setlocale (LC_ALL, "");
167 bindtextdomain (PACKAGE, LOCALEDIR);
168 textdomain (PACKAGE);
169 136
170 /* Parse extra opts if any */ 137 const check_pgsql_config config = tmp_config.config;
171 argv=np_extra_opts (&argc, argv, progname);
172 138
173 if (process_arguments (argc, argv) == ERROR) 139 if (verbose > 2) {
174 usage4 (_("Could not parse arguments"));
175 if (verbose > 2)
176 printf("Arguments initialized\n"); 140 printf("Arguments initialized\n");
141 }
177 142
178 /* Set signal handling and alarm */ 143 /* Set signal handling and alarm */
179 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 144 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
180 usage4 (_("Cannot catch SIGALRM")); 145 usage4(_("Cannot catch SIGALRM"));
146 }
147 alarm(timeout_interval);
148
149 char *conninfo = NULL;
150 if (config.pgparams) {
151 asprintf(&conninfo, "%s ", config.pgparams);
152 }
153
154 asprintf(&conninfo, "%sdbname = '%s'", conninfo ? conninfo : "", config.dbName);
155 if (config.pghost) {
156 asprintf(&conninfo, "%s host = '%s'", conninfo, config.pghost);
157 }
158 if (config.pgport) {
159 asprintf(&conninfo, "%s port = '%s'", conninfo, config.pgport);
160 }
161 if (config.pgoptions) {
162 asprintf(&conninfo, "%s options = '%s'", conninfo, config.pgoptions);
181 } 163 }
182 alarm (timeout_interval);
183
184 if (pgparams)
185 asprintf (&conninfo, "%s ", pgparams);
186
187 asprintf (&conninfo, "%sdbname = '%s'", conninfo ? conninfo : "", dbName);
188 if (pghost)
189 asprintf (&conninfo, "%s host = '%s'", conninfo, pghost);
190 if (pgport)
191 asprintf (&conninfo, "%s port = '%s'", conninfo, pgport);
192 if (pgoptions)
193 asprintf (&conninfo, "%s options = '%s'", conninfo, pgoptions);
194 /* if (pgtty) -- ignored by PQconnectdb */ 164 /* if (pgtty) -- ignored by PQconnectdb */
195 if (pguser) 165 if (config.pguser) {
196 asprintf (&conninfo, "%s user = '%s'", conninfo, pguser); 166 asprintf(&conninfo, "%s user = '%s'", conninfo, config.pguser);
167 }
197 168
198 if (verbose) /* do not include password (see right below) in output */ 169 if (verbose) { /* do not include password (see right below) in output */
199 printf ("Connecting to PostgreSQL using conninfo: %s%s\n", conninfo, 170 printf("Connecting to PostgreSQL using conninfo: %s%s\n", conninfo, config.pgpasswd ? " password = <hidden>" : "");
200 pgpasswd ? " password = <hidden>" : ""); 171 }
201 172
202 if (pgpasswd) 173 if (config.pgpasswd) {
203 asprintf (&conninfo, "%s password = '%s'", conninfo, pgpasswd); 174 asprintf(&conninfo, "%s password = '%s'", conninfo, config.pgpasswd);
175 }
204 176
205 /* make a connection to the database */ 177 /* make a connection to the database */
206 gettimeofday (&start_timeval, NULL); 178 struct timeval start_timeval;
207 conn = PQconnectdb (conninfo); 179 gettimeofday(&start_timeval, NULL);
208 gettimeofday (&end_timeval, NULL); 180 PGconn *conn = PQconnectdb(conninfo);
181 struct timeval end_timeval;
182 gettimeofday(&end_timeval, NULL);
209 183
210 while (start_timeval.tv_usec > end_timeval.tv_usec) { 184 while (start_timeval.tv_usec > end_timeval.tv_usec) {
211 --end_timeval.tv_sec; 185 --end_timeval.tv_sec;
212 end_timeval.tv_usec += 1000000; 186 end_timeval.tv_usec += 1000000;
213 } 187 }
214 elapsed_time = (double)(end_timeval.tv_sec - start_timeval.tv_sec) 188 double elapsed_time =
215 + (double)(end_timeval.tv_usec - start_timeval.tv_usec) / 1000000.0; 189 (double)(end_timeval.tv_sec - start_timeval.tv_sec) + ((double)(end_timeval.tv_usec - start_timeval.tv_usec) / 1000000.0);
216 190
217 if (verbose) 191 if (verbose) {
218 printf("Time elapsed: %f\n", elapsed_time); 192 printf("Time elapsed: %f\n", elapsed_time);
193 }
219 194
220 /* check to see that the backend connection was successfully made */ 195 /* check to see that the backend connection was successfully made */
221 if (verbose) 196 if (verbose) {
222 printf("Verifying connection\n"); 197 printf("Verifying connection\n");
223 if (PQstatus (conn) == CONNECTION_BAD) { 198 }
224 printf (_("CRITICAL - no connection to '%s' (%s).\n"), 199 if (PQstatus(conn) == CONNECTION_BAD) {
225 dbName, PQerrorMessage (conn)); 200 printf(_("CRITICAL - no connection to '%s' (%s).\n"), config.dbName, PQerrorMessage(conn));
226 PQfinish (conn); 201 PQfinish(conn);
227 return STATE_CRITICAL; 202 return STATE_CRITICAL;
228 } 203 }
229 else if (elapsed_time > tcrit) { 204
205 mp_state_enum status = STATE_UNKNOWN;
206 if (elapsed_time > config.tcrit) {
230 status = STATE_CRITICAL; 207 status = STATE_CRITICAL;
231 } 208 } else if (elapsed_time > config.twarn) {
232 else if (elapsed_time > twarn) {
233 status = STATE_WARNING; 209 status = STATE_WARNING;
234 } 210 } else {
235 else {
236 status = STATE_OK; 211 status = STATE_OK;
237 } 212 }
238 213
239 if (verbose) { 214 if (verbose) {
240 char *server_host = PQhost (conn); 215 char *server_host = PQhost(conn);
241 int server_version = PQserverVersion (conn); 216 int server_version = PQserverVersion(conn);
242 217
243 printf ("Successfully connected to database %s (user %s) " 218 printf("Successfully connected to database %s (user %s) "
244 "at server %s%s%s (server version: %d.%d.%d, " 219 "at server %s%s%s (server version: %d.%d.%d, "
245 "protocol version: %d, pid: %d)\n", 220 "protocol version: %d, pid: %d)\n",
246 PQdb (conn), PQuser (conn), 221 PQdb(conn), PQuser(conn), PSQL_SOCKET3(server_host, PQport(conn)), PSQL_SERVER_VERSION3(server_version),
247 PSQL_SOCKET3 (server_host, PQport (conn)), 222 PQprotocolVersion(conn), PQbackendPID(conn));
248 PSQL_SERVER_VERSION3 (server_version),
249 PQprotocolVersion (conn), PQbackendPID (conn));
250 } 223 }
251 224
252 printf (_(" %s - database %s (%f sec.)|%s\n"), 225 printf(_(" %s - database %s (%f sec.)|%s\n"), state_text(status), config.dbName, elapsed_time,
253 state_text(status), 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));
254 fperfdata("time", elapsed_time, "s",
255 !!(twarn > 0.0), twarn, !!(tcrit > 0.0), tcrit, true, 0, false,0));
256 227
257 if (pgquery) 228 mp_state_enum query_status = STATE_UNKNOWN;
258 query_status = do_query (conn, pgquery); 229 if (config.pgquery) {
230 query_status = do_query(conn, config.pgquery, config.pgqueryname, config.qthresholds, config.query_warning, config.query_critical);
231 }
259 232
260 if (verbose) 233 if (verbose) {
261 printf("Closing connection\n"); 234 printf("Closing connection\n");
262 PQfinish (conn); 235 }
263 return (pgquery && query_status > status) ? query_status : status; 236 PQfinish(conn);
237 return (config.pgquery && query_status > status) ? query_status : status;
264} 238}
265 239
266
267
268/* process command-line arguments */ 240/* process command-line arguments */
269int 241check_pgsql_config_wrapper process_arguments(int argc, char **argv) {
270process_arguments (int argc, char **argv) 242 static struct option longopts[] = {{"help", no_argument, 0, 'h'},
271{ 243 {"version", no_argument, 0, 'V'},
272 int c; 244 {"timeout", required_argument, 0, 't'},
273 245 {"critical", required_argument, 0, 'c'},
274 int option = 0; 246 {"warning", required_argument, 0, 'w'},
275 static struct option longopts[] = { 247 {"hostname", required_argument, 0, 'H'},
276 {"help", no_argument, 0, 'h'}, 248 {"logname", required_argument, 0, 'l'},
277 {"version", no_argument, 0, 'V'}, 249 {"password", required_argument, 0, 'p'},
278 {"timeout", required_argument, 0, 't'}, 250 {"authorization", required_argument, 0, 'a'},
279 {"critical", required_argument, 0, 'c'}, 251 {"port", required_argument, 0, 'P'},
280 {"warning", required_argument, 0, 'w'}, 252 {"database", required_argument, 0, 'd'},
281 {"hostname", required_argument, 0, 'H'}, 253 {"option", required_argument, 0, 'o'},
282 {"logname", required_argument, 0, 'l'}, 254 {"query", required_argument, 0, 'q'},
283 {"password", required_argument, 0, 'p'}, 255 {"queryname", required_argument, 0, OPTID_QUERYNAME},
284 {"authorization", required_argument, 0, 'a'}, 256 {"query_critical", required_argument, 0, 'C'},
285 {"port", required_argument, 0, 'P'}, 257 {"query_warning", required_argument, 0, 'W'},
286 {"database", required_argument, 0, 'd'}, 258 {"verbose", no_argument, 0, 'v'},
287 {"option", required_argument, 0, 'o'}, 259 {0, 0, 0, 0}};
288 {"query", required_argument, 0, 'q'}, 260
289 {"queryname", required_argument, 0, OPTID_QUERYNAME}, 261 check_pgsql_config_wrapper result = {
290 {"query_critical", required_argument, 0, 'C'}, 262 .errorcode = OK,
291 {"query_warning", required_argument, 0, 'W'}, 263 .config = check_pgsql_config_init(),
292 {"verbose", no_argument, 0, 'v'},
293 {0, 0, 0, 0}
294 }; 264 };
295 265
296 while (1) { 266 while (true) {
297 c = getopt_long (argc, argv, "hVt:c:w:H:P:d:l:p:a:o:q:C:W:v", 267 int option = 0;
298 longopts, &option); 268 int option_char = getopt_long(argc, argv, "hVt:c:w:H:P:d:l:p:a:o:q:C:W:v", longopts, &option);
299 269
300 if (c == EOF) 270 if (option_char == EOF) {
301 break; 271 break;
272 }
302 273
303 switch (c) { 274 switch (option_char) {
304 case '?': /* usage */ 275 case '?': /* usage */
305 usage5 (); 276 usage5();
306 case 'h': /* help */ 277 case 'h': /* help */
307 print_help (); 278 print_help();
308 exit (STATE_UNKNOWN); 279 exit(STATE_UNKNOWN);
309 case 'V': /* version */ 280 case 'V': /* version */
310 print_revision (progname, NP_VERSION); 281 print_revision(progname, NP_VERSION);
311 exit (STATE_UNKNOWN); 282 exit(STATE_UNKNOWN);
312 case 't': /* timeout period */ 283 case 't': /* timeout period */
313 if (!is_integer (optarg)) 284 if (!is_integer(optarg)) {
314 usage2 (_("Timeout interval must be a positive integer"), optarg); 285 usage2(_("Timeout interval must be a positive integer"), optarg);
315 else 286 } else {
316 timeout_interval = atoi (optarg); 287 timeout_interval = atoi(optarg);
288 }
317 break; 289 break;
318 case 'c': /* critical time threshold */ 290 case 'c': /* critical time threshold */
319 if (!is_nonnegative (optarg)) 291 if (!is_nonnegative(optarg)) {
320 usage2 (_("Critical threshold must be a positive integer"), optarg); 292 usage2(_("Critical threshold must be a positive integer"), optarg);
321 else 293 } else {
322 tcrit = strtod (optarg, NULL); 294 result.config.tcrit = strtod(optarg, NULL);
295 }
323 break; 296 break;
324 case 'w': /* warning time threshold */ 297 case 'w': /* warning time threshold */
325 if (!is_nonnegative (optarg)) 298 if (!is_nonnegative(optarg)) {
326 usage2 (_("Warning threshold must be a positive integer"), optarg); 299 usage2(_("Warning threshold must be a positive integer"), optarg);
327 else 300 } else {
328 twarn = strtod (optarg, NULL); 301 result.config.twarn = strtod(optarg, NULL);
302 }
329 break; 303 break;
330 case 'C': /* critical query threshold */ 304 case 'C': /* critical query threshold */
331 query_critical = optarg; 305 result.config.query_critical = optarg;
332 break; 306 break;
333 case 'W': /* warning query threshold */ 307 case 'W': /* warning query threshold */
334 query_warning = optarg; 308 result.config.query_warning = optarg;
335 break; 309 break;
336 case 'H': /* host */ 310 case 'H': /* host */
337 if ((*optarg != '/') && (!is_host (optarg))) 311 if ((*optarg != '/') && (!is_host(optarg))) {
338 usage2 (_("Invalid hostname/address"), optarg); 312 usage2(_("Invalid hostname/address"), optarg);
339 else 313 } else {
340 pghost = optarg; 314 result.config.pghost = optarg;
315 }
341 break; 316 break;
342 case 'P': /* port */ 317 case 'P': /* port */
343 if (!is_integer (optarg)) 318 if (!is_integer(optarg)) {
344 usage2 (_("Port must be a positive integer"), optarg); 319 usage2(_("Port must be a positive integer"), optarg);
345 else 320 } else {
346 pgport = optarg; 321 result.config.pgport = optarg;
322 }
347 break; 323 break;
348 case 'd': /* database name */ 324 case 'd': /* database name */
349 if (strlen(optarg) >= NAMEDATALEN) { 325 if (strlen(optarg) >= NAMEDATALEN) {
350 usage2 (_("Database name exceeds the maximum length"), optarg); 326 usage2(_("Database name exceeds the maximum length"), optarg);
351 } 327 }
352 snprintf(dbName, NAMEDATALEN, "%s", optarg); 328 snprintf(result.config.dbName, NAMEDATALEN, "%s", optarg);
353 break; 329 break;
354 case 'l': /* login name */ 330 case 'l': /* login name */
355 if (!is_pg_logname (optarg)) 331 if (!is_pg_logname(optarg)) {
356 usage2 (_("User name is not valid"), optarg); 332 usage2(_("User name is not valid"), optarg);
357 else 333 } else {
358 pguser = optarg; 334 result.config.pguser = optarg;
335 }
359 break; 336 break;
360 case 'p': /* authentication password */ 337 case 'p': /* authentication password */
361 case 'a': 338 case 'a':
362 pgpasswd = optarg; 339 result.config.pgpasswd = optarg;
363 break; 340 break;
364 case 'o': 341 case 'o':
365 if (pgparams) 342 if (result.config.pgparams) {
366 asprintf (&pgparams, "%s %s", pgparams, optarg); 343 asprintf(&result.config.pgparams, "%s %s", result.config.pgparams, optarg);
367 else 344 } else {
368 asprintf (&pgparams, "%s", optarg); 345 asprintf(&result.config.pgparams, "%s", optarg);
346 }
369 break; 347 break;
370 case 'q': 348 case 'q':
371 pgquery = optarg; 349 result.config.pgquery = optarg;
372 break; 350 break;
373 case OPTID_QUERYNAME: 351 case OPTID_QUERYNAME:
374 pgqueryname = optarg; 352 result.config.pgqueryname = optarg;
375 break; 353 break;
376 case 'v': 354 case 'v':
377 verbose++; 355 verbose++;
@@ -379,38 +357,9 @@ process_arguments (int argc, char **argv)
379 } 357 }
380 } 358 }
381 359
382 set_thresholds (&qthresholds, query_warning, query_critical); 360 set_thresholds(&result.config.qthresholds, result.config.query_warning, result.config.query_critical);
383
384 return validate_arguments ();
385}
386
387
388/******************************************************************************
389
390@@-
391<sect3>
392<title>validate_arguments</title>
393
394<para>&PROTO_validate_arguments;</para>
395
396<para>Given a database name, this function returns true if the string
397is a valid PostgreSQL database name, and returns false if it is
398not.</para>
399
400<para>Valid PostgreSQL database names are less than &NAMEDATALEN;
401characters long and consist of letters, numbers, and underscores. The
402first character cannot be a number, however.</para>
403
404</sect3>
405-@@
406******************************************************************************/
407
408
409 361
410int 362 return result;
411validate_arguments ()
412{
413 return OK;
414} 363}
415 364
416/** 365/**
@@ -437,11 +386,10 @@ should be added.</para>
437-@@ 386-@@
438******************************************************************************/ 387******************************************************************************/
439 388
440 389bool is_pg_logname(char *username) {
441 390 if (strlen(username) > NAMEDATALEN - 1) {
442bool is_pg_logname (char *username) {
443 if (strlen (username) > NAMEDATALEN - 1)
444 return (false); 391 return (false);
392 }
445 return (true); 393 return (true);
446} 394}
447 395
@@ -453,182 +401,159 @@ bool is_pg_logname (char *username) {
453-@@ 401-@@
454******************************************************************************/ 402******************************************************************************/
455 403
456 404void print_help(void) {
457
458void
459print_help (void)
460{
461 char *myport; 405 char *myport;
462 406
463 xasprintf (&myport, "%d", DEFAULT_PORT); 407 xasprintf(&myport, "%d", 5432);
464 408
465 print_revision (progname, NP_VERSION); 409 print_revision(progname, NP_VERSION);
466 410
467 printf (COPYRIGHT, copyright, email); 411 printf(COPYRIGHT, copyright, email);
468 412
469 printf (_("Test whether a PostgreSQL Database is accepting connections.")); 413 printf(_("Test whether a PostgreSQL Database is accepting connections."));
470 414
471 printf ("\n\n"); 415 printf("\n\n");
472 416
473 print_usage (); 417 print_usage();
474 418
475 printf (UT_HELP_VRSN); 419 printf(UT_HELP_VRSN);
476 printf (UT_EXTRA_OPTS); 420 printf(UT_EXTRA_OPTS);
477 421
478 printf (UT_HOST_PORT, 'P', myport); 422 printf(UT_HOST_PORT, 'P', myport);
479 423
480 printf (" %s\n", "-d, --database=STRING"); 424 printf(" %s\n", "-d, --database=STRING");
481 printf (" %s", _("Database to check ")); 425 printf(" %s", _("Database to check "));
482 printf (_("(default: %s)\n"), DEFAULT_DB); 426 printf(_("(default: %s)\n"), DEFAULT_DB);
483 printf (" %s\n", "-l, --logname = STRING"); 427 printf(" %s\n", "-l, --logname = STRING");
484 printf (" %s\n", _("Login name of user")); 428 printf(" %s\n", _("Login name of user"));
485 printf (" %s\n", "-p, --password = STRING"); 429 printf(" %s\n", "-p, --password = STRING");
486 printf (" %s\n", _("Password (BIG SECURITY ISSUE)")); 430 printf(" %s\n", _("Password (BIG SECURITY ISSUE)"));
487 printf (" %s\n", "-o, --option = STRING"); 431 printf(" %s\n", "-o, --option = STRING");
488 printf (" %s\n", _("Connection parameters (keyword = value), see below")); 432 printf(" %s\n", _("Connection parameters (keyword = value), see below"));
489 433
490 printf (UT_WARN_CRIT); 434 printf(UT_WARN_CRIT);
491 435
492 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 436 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
493 437
494 printf (" %s\n", "-q, --query=STRING"); 438 printf(" %s\n", "-q, --query=STRING");
495 printf (" %s\n", _("SQL query to run. Only first column in first row will be read")); 439 printf(" %s\n", _("SQL query to run. Only first column in first row will be read"));
496 printf (" %s\n", "--queryname=STRING"); 440 printf(" %s\n", "--queryname=STRING");
497 printf (" %s\n", _("A name for the query, this string is used instead of the query")); 441 printf(" %s\n", _("A name for the query, this string is used instead of the query"));
498 printf (" %s\n", _("in the long output of the plugin")); 442 printf(" %s\n", _("in the long output of the plugin"));
499 printf (" %s\n", "-W, --query-warning=RANGE"); 443 printf(" %s\n", "-W, --query-warning=RANGE");
500 printf (" %s\n", _("SQL query value to result in warning status (double)")); 444 printf(" %s\n", _("SQL query value to result in warning status (double)"));
501 printf (" %s\n", "-C, --query-critical=RANGE"); 445 printf(" %s\n", "-C, --query-critical=RANGE");
502 printf (" %s\n", _("SQL query value to result in critical status (double)")); 446 printf(" %s\n", _("SQL query value to result in critical status (double)"));
503 447
504 printf (UT_VERBOSE); 448 printf(UT_VERBOSE);
505 449
506 printf ("\n"); 450 printf("\n");
507 printf (" %s\n", _("All parameters are optional.")); 451 printf(" %s\n", _("All parameters are optional."));
508 printf (" %s\n", _("This plugin tests a PostgreSQL DBMS to determine whether it is active and")); 452 printf(" %s\n", _("This plugin tests a PostgreSQL DBMS to determine whether it is active and"));
509 printf (" %s\n", _("accepting queries. In its current operation, it simply connects to the")); 453 printf(" %s\n", _("accepting queries. In its current operation, it simply connects to the"));
510 printf (" %s\n", _("specified database, and then disconnects. If no database is specified, it")); 454 printf(" %s\n", _("specified database, and then disconnects. If no database is specified, it"));
511 printf (" %s\n", _("connects to the template1 database, which is present in every functioning")); 455 printf(" %s\n", _("connects to the template1 database, which is present in every functioning"));
512 printf (" %s\n\n", _("PostgreSQL DBMS.")); 456 printf(" %s\n\n", _("PostgreSQL DBMS."));
513 457
514 printf (" %s\n", _("If a query is specified using the -q option, it will be executed after")); 458 printf(" %s\n", _("If a query is specified using the -q option, it will be executed after"));
515 printf (" %s\n", _("connecting to the server. The result from the query has to be numeric.")); 459 printf(" %s\n", _("connecting to the server. The result from the query has to be numeric."));
516 printf (" %s\n", _("Multiple SQL commands, separated by semicolon, are allowed but the result ")); 460 printf(" %s\n", _("Multiple SQL commands, separated by semicolon, are allowed but the result "));
517 printf (" %s\n", _("of the last command is taken into account only. The value of the first")); 461 printf(" %s\n", _("of the last command is taken into account only. The value of the first"));
518 printf (" %s\n", _("column in the first row is used as the check result. If a second column is")); 462 printf(" %s\n", _("column in the first row is used as the check result. If a second column is"));
519 printf (" %s\n", _("present in the result set, this is added to the plugin output with a")); 463 printf(" %s\n", _("present in the result set, this is added to the plugin output with a"));
520 printf (" %s\n", _("prefix of \"Extra Info:\". This information can be displayed in the system")); 464 printf(" %s\n", _("prefix of \"Extra Info:\". This information can be displayed in the system"));
521 printf (" %s\n\n", _("executing the plugin.")); 465 printf(" %s\n\n", _("executing the plugin."));
522 466
523 printf (" %s\n", _("See the chapter \"Monitoring Database Activity\" of the PostgreSQL manual")); 467 printf(" %s\n", _("See the chapter \"Monitoring Database Activity\" of the PostgreSQL manual"));
524 printf (" %s\n\n", _("for details about how to access internal statistics of the database server.")); 468 printf(" %s\n\n", _("for details about how to access internal statistics of the database server."));
525 469
526 printf (" %s\n", _("For a list of available connection parameters which may be used with the -o")); 470 printf(" %s\n", _("For a list of available connection parameters which may be used with the -o"));
527 printf (" %s\n", _("command line option, see the documentation for PQconnectdb() in the chapter")); 471 printf(" %s\n", _("command line option, see the documentation for PQconnectdb() in the chapter"));
528 printf (" %s\n", _("\"libpq - C Library\" of the PostgreSQL manual. For example, this may be")); 472 printf(" %s\n", _("\"libpq - C Library\" of the PostgreSQL manual. For example, this may be"));
529 printf (" %s\n", _("used to specify a service name in pg_service.conf to be used for additional")); 473 printf(" %s\n", _("used to specify a service name in pg_service.conf to be used for additional"));
530 printf (" %s\n", _("connection parameters: -o 'service=<name>' or to specify the SSL mode:")); 474 printf(" %s\n", _("connection parameters: -o 'service=<name>' or to specify the SSL mode:"));
531 printf (" %s\n\n", _("-o 'sslmode=require'.")); 475 printf(" %s\n\n", _("-o 'sslmode=require'."));
532 476
533 printf (" %s\n", _("The plugin will connect to a local postmaster if no host is specified. To")); 477 printf(" %s\n", _("The plugin will connect to a local postmaster if no host is specified. To"));
534 printf (" %s\n", _("connect to a remote host, be sure that the remote postmaster accepts TCP/IP")); 478 printf(" %s\n", _("connect to a remote host, be sure that the remote postmaster accepts TCP/IP"));
535 printf (" %s\n\n", _("connections (start the postmaster with the -i option).")); 479 printf(" %s\n\n", _("connections (start the postmaster with the -i option)."));
536 480
537 printf (" %s\n", _("Typically, the monitoring user (unless the --logname option is used) should be")); 481 printf(" %s\n", _("Typically, the monitoring user (unless the --logname option is used) should be"));
538 printf (" %s\n", _("able to connect to the database without a password. The plugin can also send")); 482 printf(" %s\n", _("able to connect to the database without a password. The plugin can also send"));
539 printf (" %s\n", _("a password, but no effort is made to obscure or encrypt the password.")); 483 printf(" %s\n", _("a password, but no effort is made to obscure or encrypt the password."));
540 484
541 printf (UT_SUPPORT); 485 printf(UT_SUPPORT);
542} 486}
543 487
544 488void print_usage(void) {
545 489 printf("%s\n", _("Usage:"));
546void 490 printf("%s [-H <host>] [-P <port>] [-c <critical time>] [-w <warning time>]\n", progname);
547print_usage (void) 491 printf(" [-t <timeout>] [-d <database>] [-l <logname>] [-p <password>]\n"
548{ 492 "[-q <query>] [-C <critical query range>] [-W <warning query range>]\n");
549 printf ("%s\n", _("Usage:"));
550 printf ("%s [-H <host>] [-P <port>] [-c <critical time>] [-w <warning time>]\n", progname);
551 printf (" [-t <timeout>] [-d <database>] [-l <logname>] [-p <password>]\n"
552 "[-q <query>] [-C <critical query range>] [-W <warning query range>]\n");
553} 493}
554 494
555int 495mp_state_enum do_query(PGconn *conn, char *query, const char pgqueryname[], thresholds *qthresholds, char *query_warning,
556do_query (PGconn *conn, char *query) 496 char *query_critical) {
557{ 497 if (verbose) {
558 PGresult *res; 498 printf("Executing SQL query \"%s\".\n", query);
559 499 }
560 char *val_str; 500 PGresult *res = PQexec(conn, query);
561 char *extra_info;
562 double value;
563
564 char *endptr = NULL;
565
566 int my_status = STATE_UNKNOWN;
567
568 if (verbose)
569 printf ("Executing SQL query \"%s\".\n", query);
570 res = PQexec (conn, query);
571 501
572 if (PGRES_TUPLES_OK != PQresultStatus (res)) { 502 if (PGRES_TUPLES_OK != PQresultStatus(res)) {
573 printf (_("QUERY %s - %s: %s.\n"), _("CRITICAL"), _("Error with query"), 503 printf(_("QUERY %s - %s: %s.\n"), _("CRITICAL"), _("Error with query"), PQerrorMessage(conn));
574 PQerrorMessage (conn));
575 return STATE_CRITICAL; 504 return STATE_CRITICAL;
576 } 505 }
577 506
578 if (PQntuples (res) < 1) { 507 if (PQntuples(res) < 1) {
579 printf ("QUERY %s - %s.\n", _("WARNING"), _("No rows returned")); 508 printf("QUERY %s - %s.\n", _("WARNING"), _("No rows returned"));
580 return STATE_WARNING; 509 return STATE_WARNING;
581 } 510 }
582 511
583 if (PQnfields (res) < 1) { 512 if (PQnfields(res) < 1) {
584 printf ("QUERY %s - %s.\n", _("WARNING"), _("No columns returned")); 513 printf("QUERY %s - %s.\n", _("WARNING"), _("No columns returned"));
585 return STATE_WARNING; 514 return STATE_WARNING;
586 } 515 }
587 516
588 val_str = PQgetvalue (res, 0, 0); 517 char *val_str = PQgetvalue(res, 0, 0);
589 if (! val_str) { 518 if (!val_str) {
590 printf ("QUERY %s - %s.\n", _("CRITICAL"), _("No data returned")); 519 printf("QUERY %s - %s.\n", _("CRITICAL"), _("No data returned"));
591 return STATE_CRITICAL; 520 return STATE_CRITICAL;
592 } 521 }
593 522
594 value = strtod (val_str, &endptr); 523 char *endptr = NULL;
595 if (verbose) 524 double value = strtod(val_str, &endptr);
596 printf ("Query result: %f\n", value); 525 if (verbose) {
526 printf("Query result: %f\n", value);
527 }
597 528
598 if (endptr == val_str) { 529 if (endptr == val_str) {
599 printf ("QUERY %s - %s: %s\n", _("CRITICAL"), _("Is not a numeric"), val_str); 530 printf("QUERY %s - %s: %s\n", _("CRITICAL"), _("Is not a numeric"), val_str);
600 return STATE_CRITICAL; 531 return STATE_CRITICAL;
601 } 532 }
602 else if ((endptr != NULL) && (*endptr != '\0')) {
603 if (verbose)
604 printf ("Garbage after value: %s.\n", endptr);
605 }
606 533
607 my_status = get_status (value, qthresholds); 534 if ((endptr != NULL) && (*endptr != '\0')) {
608 printf ("QUERY %s - ", 535 if (verbose) {
609 (my_status == STATE_OK) 536 printf("Garbage after value: %s.\n", endptr);
610 ? _("OK") 537 }
611 : (my_status == STATE_WARNING)
612 ? _("WARNING")
613 : (my_status == STATE_CRITICAL)
614 ? _("CRITICAL")
615 : _("UNKNOWN"));
616 if(pgqueryname) {
617 printf (_("%s returned %f"), pgqueryname, value);
618 } 538 }
619 else { 539
620 printf (_("'%s' returned %f"), query, value); 540 mp_state_enum my_status = get_status(value, qthresholds);
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);
621 } 549 }
622 550
623 printf ("|query=%f;%s;%s;;\n", value, 551 printf("|query=%f;%s;%s;;\n", value, query_warning ? query_warning : "", query_critical ? query_critical : "");
624 query_warning ? query_warning : "", 552 if (PQnfields(res) > 1) {
625 query_critical ? query_critical : ""); 553 char *extra_info = PQgetvalue(res, 0, 1);
626 if (PQnfields (res) > 1) {
627 extra_info = PQgetvalue (res, 0, 1);
628 if (extra_info != NULL) { 554 if (extra_info != NULL) {
629 printf ("Extra Info: %s\n", extra_info); 555 printf("Extra Info: %s\n", extra_info);
630 } 556 }
631 } 557 }
632 return my_status; 558 return my_status;
633} 559}
634
diff --git a/plugins/check_pgsql.d/config.h b/plugins/check_pgsql.d/config.h
new file mode 100644
index 00000000..2d4b8b89
--- /dev/null
+++ b/plugins/check_pgsql.d/config.h
@@ -0,0 +1,61 @@
1#pragma once
2
3#include "../../config.h"
4#include "thresholds.h"
5#include <stddef.h>
6#include <pg_config_manual.h>
7
8#define DEFAULT_DB "template1"
9
10enum {
11 DEFAULT_WARN = 2,
12 DEFAULT_CRIT = 8,
13};
14
15typedef struct {
16 char *pghost; /* host name of the backend server */
17 char *pgport; /* port of the backend server */
18 char *pgoptions; /* special options to start up the backend server */
19 char *pgtty; /* debugging tty for the backend server */
20 char dbName[NAMEDATALEN];
21 char *pguser;
22 char *pgpasswd;
23 char *pgparams;
24 char *pgquery;
25 char *pgqueryname;
26
27 double twarn;
28 double tcrit;
29 thresholds *qthresholds;
30 char *query_warning;
31 char *query_critical;
32} check_pgsql_config;
33
34/* begin, by setting the parameters for a backend connection if the
35 * parameters are null, then the system will try to use reasonable
36 * defaults by looking up environment variables or, failing that,
37 * using hardwired constants
38 * this targets .pgoptions and .pgtty
39 */
40
41check_pgsql_config check_pgsql_config_init() {
42 check_pgsql_config tmp = {
43 .pghost = NULL,
44 .pgport = NULL,
45 .pgoptions = NULL,
46 .pgtty = NULL,
47 .dbName = DEFAULT_DB,
48 .pguser = NULL,
49 .pgpasswd = NULL,
50 .pgparams = NULL,
51 .pgquery = NULL,
52 .pgqueryname = NULL,
53
54 .twarn = (double)DEFAULT_WARN,
55 .tcrit = (double)DEFAULT_CRIT,
56 .qthresholds = NULL,
57 .query_warning = NULL,
58 .query_critical = NULL,
59 };
60 return tmp;
61}
diff --git a/plugins/check_ping.c b/plugins/check_ping.c
index 6e162e6a..6bcdeaad 100644
--- a/plugins/check_ping.c
+++ b/plugins/check_ping.c
@@ -1,506 +1,526 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_ping plugin 3 * Monitoring check_ping plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2007 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_ping plugin 10 * This file contains the check_ping plugin
11* 11 *
12* Use the ping program to check connection statistics for a remote host. 12 * Use the ping program to check connection statistics for a remote host.
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_ping"; 31const char *progname = "check_ping";
32const char *copyright = "2000-2007"; 32const char *copyright = "2000-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 "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
45enum {
46 UNKNOWN_PACKET_LOSS = 200, /* 200% */
47 DEFAULT_MAX_PACKETS = 5 /* default no. of ICMP ECHO packets */
48};
49
50int process_arguments (int, char **);
51int get_threshold (char *, float *, int *);
52int validate_arguments (void);
53int run_ping (const char *cmd, const char *addr);
54int error_scan (char buf[MAX_INPUT_BUFFER], const char *addr);
55void print_usage (void);
56void print_help (void);
57
58bool display_html = false;
59int wpl = UNKNOWN_PACKET_LOSS;
60int cpl = UNKNOWN_PACKET_LOSS;
61float wrta = UNKNOWN_TRIP_TIME;
62float crta = UNKNOWN_TRIP_TIME;
63char **addresses = NULL;
64int n_addresses = 0;
65int max_addr = 1;
66int max_packets = -1;
67int verbose = 0;
68
69float rta = UNKNOWN_TRIP_TIME;
70int pl = UNKNOWN_PACKET_LOSS;
71
72char *warn_text;
73
74
75
76int
77main (int argc, char **argv)
78{
79 char *cmd = NULL;
80 char *rawcmd = NULL;
81 int result = STATE_UNKNOWN;
82 int this_result = STATE_UNKNOWN;
83 int i;
84 45
85 setlocale (LC_ALL, ""); 46typedef struct {
86 setlocale (LC_NUMERIC, "C"); 47 int errorcode;
87 bindtextdomain (PACKAGE, LOCALEDIR); 48 check_ping_config config;
88 textdomain (PACKAGE); 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*/);
52
53static int get_threshold(char * /*arg*/, double * /*trta*/, int * /*tpl*/);
54
55typedef struct {
56 mp_state_enum state;
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);
63static void print_help(void);
64void print_usage(void);
65
66static int verbose = 0;
89 67
90 addresses = malloc (sizeof(char*) * max_addr); 68static char *warn_text;
91 addresses[0] = NULL; 69
70int main(int argc, char **argv) {
71 setlocale(LC_ALL, "");
72 setlocale(LC_NUMERIC, "C");
73 bindtextdomain(PACKAGE, LOCALEDIR);
74 textdomain(PACKAGE);
92 75
93 /* Parse extra opts if any */ 76 /* Parse extra opts if any */
94 argv=np_extra_opts (&argc, argv, progname); 77 argv = np_extra_opts(&argc, argv, progname);
78
79 check_ping_config_wrapper tmp_config = process_arguments(argc, argv);
80 if (tmp_config.errorcode == ERROR) {
81 usage4(_("Could not parse arguments"));
82 }
95 83
96 if (process_arguments (argc, argv) == ERROR) 84 const check_ping_config config = tmp_config.config;
97 usage4 (_("Could not parse arguments"));
98 85
99 /* Set signal handling and alarm */ 86 /* Set signal handling and alarm */
100 if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) { 87 if (signal(SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
101 usage4 (_("Cannot catch SIGALRM")); 88 usage4(_("Cannot catch SIGALRM"));
102 } 89 }
103 90
104 /* If ./configure finds ping has timeout values, set plugin alarm slightly 91 /* If ./configure finds ping has timeout values, set plugin alarm slightly
105 * higher so that we can use response from command line ping */ 92 * higher so that we can use response from command line ping */
106#if defined(PING_PACKETS_FIRST) && defined(PING_HAS_TIMEOUT) 93#if defined(PING_PACKETS_FIRST) && defined(PING_HAS_TIMEOUT)
107 alarm (timeout_interval + 1); 94 alarm(timeout_interval + 1);
108#else 95#else
109 alarm (timeout_interval); 96 alarm(timeout_interval);
110#endif 97#endif
111 98
112 for (i = 0 ; i < n_addresses ; i++) { 99 int result = STATE_UNKNOWN;
113 100 char *rawcmd = NULL;
101 for (size_t i = 0; i < config.n_addresses; i++) {
114#ifdef PING6_COMMAND 102#ifdef PING6_COMMAND
115 if (address_family != AF_INET && is_inet6_addr(addresses[i])) 103 if (address_family != AF_INET && is_inet6_addr(config.addresses[i])) {
116 rawcmd = strdup(PING6_COMMAND); 104 rawcmd = strdup(PING6_COMMAND);
117 else 105 } else {
118 rawcmd = strdup(PING_COMMAND); 106 rawcmd = strdup(PING_COMMAND);
107 }
119#else 108#else
120 rawcmd = strdup(PING_COMMAND); 109 rawcmd = strdup(PING_COMMAND);
121#endif 110#endif
122 111
112 char *cmd = NULL;
113
123 /* does the host address of number of packets argument come first? */ 114 /* does the host address of number of packets argument come first? */
124#ifdef PING_PACKETS_FIRST 115#ifdef PING_PACKETS_FIRST
125# ifdef PING_HAS_TIMEOUT 116# ifdef PING_HAS_TIMEOUT
126 xasprintf (&cmd, rawcmd, timeout_interval, max_packets, addresses[i]); 117 xasprintf(&cmd, rawcmd, timeout_interval, config.max_packets, config.addresses[i]);
127# else 118# else
128 xasprintf (&cmd, rawcmd, max_packets, addresses[i]); 119 xasprintf(&cmd, rawcmd, config.max_packets, config.addresses[i]);
129# endif 120# endif
130#else 121#else
131 xasprintf (&cmd, rawcmd, addresses[i], max_packets); 122 xasprintf(&cmd, rawcmd, config.addresses[i], config.max_packets);
132#endif 123#endif
133 124
134 if (verbose >= 2) 125 if (verbose >= 2) {
135 printf ("CMD: %s\n", cmd); 126 printf("CMD: %s\n", cmd);
127 }
136 128
137 /* run the command */ 129 /* run the command */
138 this_result = run_ping (cmd, addresses[i]);
139 130
140 if (pl == UNKNOWN_PACKET_LOSS || rta < 0.0) { 131 ping_result pinged = run_ping(cmd, config.addresses[i], config.crta);
141 printf ("%s\n", cmd); 132
142 die (STATE_UNKNOWN, 133 if (pinged.packet_loss == UNKNOWN_PACKET_LOSS || pinged.round_trip_average < 0.0) {
143 _("CRITICAL - Could not interpret output from ping command\n")); 134 printf("%s\n", cmd);
135 die(STATE_UNKNOWN, _("CRITICAL - Could not interpret output from ping command\n"));
136 }
137
138 if (pinged.packet_loss >= config.cpl || pinged.round_trip_average >= config.crta || pinged.round_trip_average < 0) {
139 pinged.state = STATE_CRITICAL;
140 } else if (pinged.packet_loss >= config.wpl || pinged.round_trip_average >= config.wrta) {
141 pinged.state = STATE_WARNING;
142 } else if (pinged.packet_loss >= 0 && pinged.round_trip_average >= 0) {
143 pinged.state = max_state(STATE_OK, pinged.state);
144 }
145
146 if (config.n_addresses > 1 && pinged.state != STATE_UNKNOWN) {
147 die(STATE_OK, "%s is alive\n", config.addresses[i]);
144 } 148 }
145 149
146 if (pl >= cpl || rta >= crta || rta < 0) 150 if (config.display_html) {
147 this_result = STATE_CRITICAL; 151 printf("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, config.addresses[i]);
148 else if (pl >= wpl || rta >= wrta) 152 }
149 this_result = STATE_WARNING; 153 if (pinged.packet_loss == 100) {
150 else if (pl >= 0 && rta >= 0) 154 printf(_("PING %s - %sPacket loss = %d%%"), state_text(pinged.state), warn_text, pinged.packet_loss);
151 this_result = max_state (STATE_OK, this_result); 155 } else {
152 156 printf(_("PING %s - %sPacket loss = %d%%, RTA = %2.2f ms"), state_text(pinged.state), warn_text, pinged.packet_loss,
153 if (n_addresses > 1 && this_result != STATE_UNKNOWN) 157 pinged.round_trip_average);
154 die (STATE_OK, "%s is alive\n", addresses[i]); 158 }
155 159 if (config.display_html) {
156 if (display_html == true) 160 printf("</A>");
157 printf ("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, addresses[i]); 161 }
158 if (pl == 100)
159 printf (_("PING %s - %sPacket loss = %d%%"), state_text (this_result), warn_text,
160 pl);
161 else
162 printf (_("PING %s - %sPacket loss = %d%%, RTA = %2.2f ms"),
163 state_text (this_result), warn_text, pl, rta);
164 if (display_html == true)
165 printf ("</A>");
166 162
167 /* Print performance data */ 163 /* Print performance data */
168 if (pl != 100) { 164 if (pinged.packet_loss != 100) {
169 printf("|%s", fperfdata ("rta", (double) rta, "ms", 165 printf("|%s", fperfdata("rta", pinged.round_trip_average, "ms", (bool)(config.wrta > 0), config.wrta, (bool)(config.crta > 0),
170 wrta>0?true:false, wrta, 166 config.crta, true, 0, false, 0));
171 crta>0?true:false, crta,
172 true, 0, false, 0));
173 } else { 167 } else {
174 printf("| rta=U;%f;%f;;", wrta, crta); 168 printf("| rta=U;%f;%f;;", config.wrta, config.crta);
175 } 169 }
176 printf(" %s\n", perfdata ("pl", (long) pl, "%",
177 wpl>0?true:false, wpl,
178 cpl>0?true:false, cpl,
179 true, 0, false, 0));
180 170
181 if (verbose >= 2) 171 printf(" %s\n", perfdata("pl", (long)pinged.packet_loss, "%", (bool)(config.wpl > 0), config.wpl, (bool)(config.cpl > 0),
182 printf ("%f:%d%% %f:%d%%\n", wrta, wpl, crta, cpl); 172 config.cpl, true, 0, false, 0));
173
174 if (verbose >= 2) {
175 printf("%f:%d%% %f:%d%%\n", config.wrta, config.wpl, config.crta, config.cpl);
176 }
183 177
184 result = max_state (result, this_result); 178 result = max_state(result, pinged.state);
185 free (rawcmd); 179 free(rawcmd);
186 free (cmd); 180 free(cmd);
187 } 181 }
188 182
189 return result; 183 return result;
190} 184}
191 185
192
193
194/* process command-line arguments */ 186/* process command-line arguments */
195int 187check_ping_config_wrapper process_arguments(int argc, char **argv) {
196process_arguments (int argc, char **argv) 188 static struct option longopts[] = {STD_LONG_OPTS,
197{ 189 {"packets", required_argument, 0, 'p'},
198 int c = 1; 190 {"nohtml", no_argument, 0, 'n'},
199 char *ptr; 191 {"link", no_argument, 0, 'L'},
200 192 {"use-ipv4", no_argument, 0, '4'},
201 int option = 0; 193 {"use-ipv6", no_argument, 0, '6'},
202 static struct option longopts[] = { 194 {0, 0, 0, 0}};
203 STD_LONG_OPTS, 195
204 {"packets", required_argument, 0, 'p'}, 196 check_ping_config_wrapper result = {
205 {"nohtml", no_argument, 0, 'n'}, 197 .errorcode = OK,
206 {"link", no_argument, 0, 'L'}, 198 .config = check_ping_config_init(),
207 {"use-ipv4", no_argument, 0, '4'},
208 {"use-ipv6", no_argument, 0, '6'},
209 {0, 0, 0, 0}
210 }; 199 };
211 200
212 if (argc < 2) 201 if (argc < 2) {
213 return ERROR; 202 result.errorcode = ERROR;
203 return result;
204 }
214 205
215 for (c = 1; c < argc; c++) { 206 for (int index = 1; index < argc; index++) {
216 if (strcmp ("-to", argv[c]) == 0) 207 if (strcmp("-to", argv[index]) == 0) {
217 strcpy (argv[c], "-t"); 208 strcpy(argv[index], "-t");
218 if (strcmp ("-nohtml", argv[c]) == 0) 209 }
219 strcpy (argv[c], "-n"); 210 if (strcmp("-nohtml", argv[index]) == 0) {
211 strcpy(argv[index], "-n");
212 }
220 } 213 }
221 214
222 while (1) { 215 int option = 0;
223 c = getopt_long (argc, argv, "VvhnL46t:c:w:H:p:", longopts, &option); 216 size_t max_addr = MAX_ADDR_START;
217 while (true) {
218 int option_index = getopt_long(argc, argv, "VvhnL46t:c:w:H:p:", longopts, &option);
224 219
225 if (c == -1 || c == EOF) 220 if (option_index == -1 || option_index == EOF) {
226 break; 221 break;
222 }
227 223
228 switch (c) { 224 switch (option_index) {
229 case '?': /* usage */ 225 case '?': /* usage */
230 usage5 (); 226 usage5();
231 case 'h': /* help */ 227 case 'h': /* help */
232 print_help (); 228 print_help();
233 exit (STATE_UNKNOWN); 229 exit(STATE_UNKNOWN);
234 break; 230 break;
235 case 'V': /* version */ 231 case 'V': /* version */
236 print_revision (progname, NP_VERSION); 232 print_revision(progname, NP_VERSION);
237 exit (STATE_UNKNOWN); 233 exit(STATE_UNKNOWN);
238 break; 234 break;
239 case 't': /* timeout period */ 235 case 't': /* timeout period */
240 timeout_interval = atoi (optarg); 236 timeout_interval = atoi(optarg);
241 break; 237 break;
242 case 'v': /* verbose mode */ 238 case 'v': /* verbose mode */
243 verbose++; 239 verbose++;
244 break; 240 break;
245 case '4': /* IPv4 only */ 241 case '4': /* IPv4 only */
246 address_family = AF_INET; 242 address_family = AF_INET;
247 break; 243 break;
248 case '6': /* IPv6 only */ 244 case '6': /* IPv6 only */
249#ifdef USE_IPV6 245#ifdef USE_IPV6
250 address_family = AF_INET6; 246 address_family = AF_INET6;
251#else 247#else
252 usage (_("IPv6 support not available\n")); 248 usage(_("IPv6 support not available\n"));
253#endif 249#endif
254 break; 250 break;
255 case 'H': /* hostname */ 251 case 'H': /* hostname */ {
256 ptr=optarg; 252 char *ptr = optarg;
257 while (1) { 253 while (true) {
258 n_addresses++; 254 result.config.n_addresses++;
259 if (n_addresses > max_addr) { 255 if (result.config.n_addresses > max_addr) {
260 max_addr *= 2; 256 max_addr *= 2;
261 addresses = realloc (addresses, sizeof(char*) * max_addr); 257 result.config.addresses = realloc(result.config.addresses, sizeof(char *) * max_addr);
262 if (addresses == NULL) 258 if (result.config.addresses == NULL) {
263 die (STATE_UNKNOWN, _("Could not realloc() addresses\n")); 259 die(STATE_UNKNOWN, _("Could not realloc() addresses\n"));
260 }
264 } 261 }
265 addresses[n_addresses-1] = ptr; 262 result.config.addresses[result.config.n_addresses - 1] = ptr;
266 if ((ptr = index (ptr, ','))) { 263 if ((ptr = index(ptr, ','))) {
267 strcpy (ptr, ""); 264 strcpy(ptr, "");
268 ptr += sizeof(char); 265 ptr += sizeof(char);
269 } else { 266 } else {
270 break; 267 break;
271 } 268 }
272 } 269 }
270 } break;
271 case 'p': /* number of packets to send */
272 if (is_intnonneg(optarg)) {
273 result.config.max_packets = atoi(optarg);
274 } else {
275 usage2(_("<max_packets> (%s) must be a non-negative number\n"), optarg);
276 }
273 break; 277 break;
274 case 'p': /* number of packets to send */ 278 case 'n': /* no HTML */
275 if (is_intnonneg (optarg)) 279 result.config.display_html = false;
276 max_packets = atoi (optarg);
277 else
278 usage2 (_("<max_packets> (%s) must be a non-negative number\n"), optarg);
279 break;
280 case 'n': /* no HTML */
281 display_html = false;
282 break; 280 break;
283 case 'L': /* show HTML */ 281 case 'L': /* show HTML */
284 display_html = true; 282 result.config.display_html = true;
285 break; 283 break;
286 case 'c': 284 case 'c':
287 get_threshold (optarg, &crta, &cpl); 285 get_threshold(optarg, &result.config.crta, &result.config.cpl);
288 break; 286 break;
289 case 'w': 287 case 'w':
290 get_threshold (optarg, &wrta, &wpl); 288 get_threshold(optarg, &result.config.wrta, &result.config.wpl);
291 break; 289 break;
292 } 290 }
293 } 291 }
294 292
295 c = optind; 293 int arg_counter = optind;
296 if (c == argc) 294 if (arg_counter == argc) {
297 return validate_arguments (); 295 return validate_arguments(result);
296 }
298 297
299 if (addresses[0] == NULL) { 298 if (result.config.addresses[0] == NULL) {
300 if (!is_host (argv[c])) { 299 if (!is_host(argv[arg_counter])) {
301 usage2 (_("Invalid hostname/address"), argv[c]); 300 usage2(_("Invalid hostname/address"), argv[arg_counter]);
302 } else { 301 } else {
303 addresses[0] = argv[c++]; 302 result.config.addresses[0] = argv[arg_counter++];
304 n_addresses++; 303 result.config.n_addresses++;
305 if (c == argc) 304 if (arg_counter == argc) {
306 return validate_arguments (); 305 return validate_arguments(result);
306 }
307 } 307 }
308 } 308 }
309 309
310 if (wpl == UNKNOWN_PACKET_LOSS) { 310 if (result.config.wpl == UNKNOWN_PACKET_LOSS) {
311 if (!is_intpercent (argv[c])) { 311 if (!is_intpercent(argv[arg_counter])) {
312 printf (_("<wpl> (%s) must be an integer percentage\n"), argv[c]); 312 printf(_("<wpl> (%s) must be an integer percentage\n"), argv[arg_counter]);
313 return ERROR; 313 result.errorcode = ERROR;
314 } else { 314 return result;
315 wpl = atoi (argv[c++]); 315 }
316 if (c == argc) 316 result.config.wpl = atoi(argv[arg_counter++]);
317 return validate_arguments (); 317 if (arg_counter == argc) {
318 return validate_arguments(result);
318 } 319 }
319 } 320 }
320 321
321 if (cpl == UNKNOWN_PACKET_LOSS) { 322 if (result.config.cpl == UNKNOWN_PACKET_LOSS) {
322 if (!is_intpercent (argv[c])) { 323 if (!is_intpercent(argv[arg_counter])) {
323 printf (_("<cpl> (%s) must be an integer percentage\n"), argv[c]); 324 printf(_("<cpl> (%s) must be an integer percentage\n"), argv[arg_counter]);
324 return ERROR; 325 result.errorcode = ERROR;
325 } else { 326 return result;
326 cpl = atoi (argv[c++]); 327 }
327 if (c == argc) 328 result.config.cpl = atoi(argv[arg_counter++]);
328 return validate_arguments (); 329 if (arg_counter == argc) {
330 return validate_arguments(result);
329 } 331 }
330 } 332 }
331 333
332 if (wrta < 0.0) { 334 if (result.config.wrta < 0.0) {
333 if (is_negative (argv[c])) { 335 if (is_negative(argv[arg_counter])) {
334 printf (_("<wrta> (%s) must be a non-negative number\n"), argv[c]); 336 printf(_("<wrta> (%s) must be a non-negative number\n"), argv[arg_counter]);
335 return ERROR; 337 result.errorcode = ERROR;
336 } else { 338 return result;
337 wrta = atof (argv[c++]); 339 }
338 if (c == argc) 340 result.config.wrta = atof(argv[arg_counter++]);
339 return validate_arguments (); 341 if (arg_counter == argc) {
342 return validate_arguments(result);
340 } 343 }
341 } 344 }
342 345
343 if (crta < 0.0) { 346 if (result.config.crta < 0.0) {
344 if (is_negative (argv[c])) { 347 if (is_negative(argv[arg_counter])) {
345 printf (_("<crta> (%s) must be a non-negative number\n"), argv[c]); 348 printf(_("<crta> (%s) must be a non-negative number\n"), argv[arg_counter]);
346 return ERROR; 349 result.errorcode = ERROR;
347 } else { 350 return result;
348 crta = atof (argv[c++]); 351 }
349 if (c == argc) 352 result.config.crta = atof(argv[arg_counter++]);
350 return validate_arguments (); 353 if (arg_counter == argc) {
354 return validate_arguments(result);
351 } 355 }
352 } 356 }
353 357
354 if (max_packets == -1) { 358 if (result.config.max_packets == -1) {
355 if (is_intnonneg (argv[c])) { 359 if (is_intnonneg(argv[arg_counter])) {
356 max_packets = atoi (argv[c++]); 360 result.config.max_packets = atoi(argv[arg_counter++]);
357 } else { 361 } else {
358 printf (_("<max_packets> (%s) must be a non-negative number\n"), argv[c]); 362 printf(_("<max_packets> (%s) must be a non-negative number\n"), argv[arg_counter]);
359 return ERROR; 363 result.errorcode = ERROR;
364 return result;
360 } 365 }
361 } 366 }
362 367
363 return validate_arguments (); 368 return validate_arguments(result);
364} 369}
365 370
366 371int get_threshold(char *arg, double *trta, int *tpl) {
367 372 if (is_intnonneg(arg) && sscanf(arg, "%lf", trta) == 1) {
368int
369get_threshold (char *arg, float *trta, int *tpl)
370{
371 if (is_intnonneg (arg) && sscanf (arg, "%f", trta) == 1)
372 return OK; 373 return OK;
373 else if (strpbrk (arg, ",:") && strstr (arg, "%") && sscanf (arg, "%f%*[:,]%d%%", trta, tpl) == 2) 374 }
375
376 if (strpbrk(arg, ",:") && strstr(arg, "%") && sscanf(arg, "%lf%*[:,]%d%%", trta, tpl) == 2) {
374 return OK; 377 return OK;
375 else if (strstr (arg, "%") && sscanf (arg, "%d%%", tpl) == 1) 378 }
379
380 if (strstr(arg, "%") && sscanf(arg, "%d%%", tpl) == 1) {
376 return OK; 381 return OK;
382 }
377 383
378 usage2 (_("%s: Warning threshold must be integer or percentage!\n\n"), arg); 384 usage2(_("%s: Warning threshold must be integer or percentage!\n\n"), arg);
379 return STATE_UNKNOWN; 385 return STATE_UNKNOWN;
380} 386}
381 387
382 388check_ping_config_wrapper validate_arguments(check_ping_config_wrapper config_wrapper) {
383 389 if (config_wrapper.config.wrta < 0.0) {
384int 390 printf(_("<wrta> was not set\n"));
385validate_arguments () 391 config_wrapper.errorcode = ERROR;
386{ 392 return config_wrapper;
387 float max_seconds;
388 int i;
389
390 if (wrta < 0.0) {
391 printf (_("<wrta> was not set\n"));
392 return ERROR;
393 } 393 }
394 else if (crta < 0.0) { 394
395 printf (_("<crta> was not set\n")); 395 if (config_wrapper.config.crta < 0.0) {
396 return ERROR; 396 printf(_("<crta> was not set\n"));
397 config_wrapper.errorcode = ERROR;
398 return config_wrapper;
397 } 399 }
398 else if (wpl == UNKNOWN_PACKET_LOSS) { 400
399 printf (_("<wpl> was not set\n")); 401 if (config_wrapper.config.wpl == UNKNOWN_PACKET_LOSS) {
400 return ERROR; 402 printf(_("<wpl> was not set\n"));
403 config_wrapper.errorcode = ERROR;
404 return config_wrapper;
401 } 405 }
402 else if (cpl == UNKNOWN_PACKET_LOSS) { 406
403 printf (_("<cpl> was not set\n")); 407 if (config_wrapper.config.cpl == UNKNOWN_PACKET_LOSS) {
404 return ERROR; 408 printf(_("<cpl> was not set\n"));
409 config_wrapper.errorcode = ERROR;
410 return config_wrapper;
405 } 411 }
406 else if (wrta > crta) { 412
407 printf (_("<wrta> (%f) cannot be larger than <crta> (%f)\n"), wrta, crta); 413 if (config_wrapper.config.wrta > config_wrapper.config.crta) {
408 return ERROR; 414 printf(_("<wrta> (%f) cannot be larger than <crta> (%f)\n"), config_wrapper.config.wrta, config_wrapper.config.crta);
415 config_wrapper.errorcode = ERROR;
416 return config_wrapper;
409 } 417 }
410 else if (wpl > cpl) { 418
411 printf (_("<wpl> (%d) cannot be larger than <cpl> (%d)\n"), wpl, cpl); 419 if (config_wrapper.config.wpl > config_wrapper.config.cpl) {
412 return ERROR; 420 printf(_("<wpl> (%d) cannot be larger than <cpl> (%d)\n"), config_wrapper.config.wpl, config_wrapper.config.cpl);
421 config_wrapper.errorcode = ERROR;
422 return config_wrapper;
413 } 423 }
414 424
415 if (max_packets == -1) 425 if (config_wrapper.config.max_packets == -1) {
416 max_packets = DEFAULT_MAX_PACKETS; 426 config_wrapper.config.max_packets = DEFAULT_MAX_PACKETS;
427 }
417 428
418 max_seconds = crta / 1000.0 * max_packets + max_packets; 429 double max_seconds = (config_wrapper.config.crta / 1000.0 * config_wrapper.config.max_packets) + config_wrapper.config.max_packets;
419 if (max_seconds > timeout_interval) 430 if (max_seconds > timeout_interval) {
420 timeout_interval = (int)max_seconds; 431 timeout_interval = (unsigned int)max_seconds;
432 }
421 433
422 for (i=0; i<n_addresses; i++) { 434 for (size_t i = 0; i < config_wrapper.config.n_addresses; i++) {
423 if (!is_host(addresses[i])) 435 if (!is_host(config_wrapper.config.addresses[i])) {
424 usage2 (_("Invalid hostname/address"), addresses[i]); 436 usage2(_("Invalid hostname/address"), config_wrapper.config.addresses[i]);
437 }
425 } 438 }
426 439
427 if (n_addresses == 0) { 440 if (config_wrapper.config.n_addresses == 0) {
428 usage (_("You must specify a server address or host name")); 441 usage(_("You must specify a server address or host name"));
429 } 442 }
430 443
431 return OK; 444 return config_wrapper;
432} 445}
433 446
447ping_result run_ping(const char *cmd, const char *addr, double crta) {
448 if ((child_process = spopen(cmd)) == NULL) {
449 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd);
450 }
434 451
452 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
453 if (child_stderr == NULL) {
454 printf(_("Cannot open stderr for %s\n"), cmd);
455 }
435 456
436int
437run_ping (const char *cmd, const char *addr)
438{
439 char buf[MAX_INPUT_BUFFER]; 457 char buf[MAX_INPUT_BUFFER];
440 int result = STATE_UNKNOWN; 458 ping_result result = {
441 int match; 459 .state = STATE_UNKNOWN,
442 460 .packet_loss = UNKNOWN_PACKET_LOSS,
443 if ((child_process = spopen (cmd)) == NULL) 461 .round_trip_average = UNKNOWN_TRIP_TIME,
444 die (STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd); 462 };
445
446 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
447 if (child_stderr == NULL)
448 printf (_("Cannot open stderr for %s\n"), cmd);
449
450 while (fgets (buf, MAX_INPUT_BUFFER - 1, child_process)) {
451 463
452 if (verbose >= 3) 464 while (fgets(buf, MAX_INPUT_BUFFER - 1, child_process)) {
465 if (verbose >= 3) {
453 printf("Output: %s", buf); 466 printf("Output: %s", buf);
467 }
454 468
455 result = max_state (result, error_scan (buf, addr)); 469 result.state = max_state(result.state, error_scan(buf, addr));
456 470
457 /* get the percent loss statistics */ 471 /* get the percent loss statistics */
458 match = 0; 472 int match = 0;
459 if((sscanf(buf,"%*d packets transmitted, %*d packets received, +%*d errors, %d%% packet loss%n",&pl,&match) && match) || 473 if ((sscanf(buf, "%*d packets transmitted, %*d packets received, +%*d errors, %d%% packet loss%n", &result.packet_loss, &match) ==
460 (sscanf(buf,"%*d packets transmitted, %*d packets received, +%*d duplicates, %d%% packet loss%n",&pl,&match) && match) || 474 1 &&
461 (sscanf(buf,"%*d packets transmitted, %*d received, +%*d duplicates, %d%% packet loss%n",&pl,&match) && match) || 475 match) ||
462 (sscanf(buf,"%*d packets transmitted, %*d packets received, %d%% packet loss%n",&pl,&match) && match) || 476 (sscanf(buf, "%*d packets transmitted, %*d packets received, +%*d duplicates, %d%% packet loss%n", &result.packet_loss,
463 (sscanf(buf,"%*d packets transmitted, %*d packets received, %d%% loss, time%n",&pl,&match) && match) || 477 &match) == 1 &&
464 (sscanf(buf,"%*d packets transmitted, %*d received, %d%% loss, time%n",&pl,&match) && match) || 478 match) ||
465 (sscanf(buf,"%*d packets transmitted, %*d received, %d%% packet loss, time%n",&pl,&match) && match) || 479 (sscanf(buf, "%*d packets transmitted, %*d received, +%*d duplicates, %d%% packet loss%n", &result.packet_loss, &match) == 1 &&
466 (sscanf(buf,"%*d packets transmitted, %*d received, +%*d errors, %d%% packet loss%n",&pl,&match) && match) || 480 match) ||
467 (sscanf(buf,"%*d packets transmitted %*d received, +%*d errors, %d%% packet loss%n",&pl,&match) && match) || 481 (sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% packet loss%n", &result.packet_loss, &match) == 1 && match) ||
468 (sscanf(buf,"%*[^(](%d%% %*[^)])%n",&pl,&match) && match) 482 (sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% loss, time%n", &result.packet_loss, &match) == 1 && match) ||
469 ) 483 (sscanf(buf, "%*d packets transmitted, %*d received, %d%% loss, time%n", &result.packet_loss, &match) == 1 && match) ||
484 (sscanf(buf, "%*d packets transmitted, %*d received, %d%% packet loss, time%n", &result.packet_loss, &match) == 1 && match) ==
485 1 ||
486 (sscanf(buf, "%*d packets transmitted, %*d received, +%*d errors, %d%% packet loss%n", &result.packet_loss, &match) == 1 &&
487 match) ||
488 (sscanf(buf, "%*d packets transmitted %*d received, +%*d errors, %d%% packet loss%n", &result.packet_loss, &match) == 1 &&
489 match) ||
490 (sscanf(buf, "%*[^(](%d%% %*[^)])%n", &result.packet_loss, &match) == 1 && match)) {
470 continue; 491 continue;
492 }
471 493
472 /* get the round trip average */ 494 /* get the round trip average */
473 else 495 if ((sscanf(buf, "round-trip min/avg/max = %*f/%lf/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
474 if((sscanf(buf,"round-trip min/avg/max = %*f/%f/%*f%n",&rta,&match) && match) || 496 (sscanf(buf, "round-trip min/avg/max/mdev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
475 (sscanf(buf,"round-trip min/avg/max/mdev = %*f/%f/%*f/%*f%n",&rta,&match) && match) || 497 (sscanf(buf, "round-trip min/avg/max/sdev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
476 (sscanf(buf,"round-trip min/avg/max/sdev = %*f/%f/%*f/%*f%n",&rta,&match) && match) || 498 (sscanf(buf, "round-trip min/avg/max/stddev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
477 (sscanf(buf,"round-trip min/avg/max/stddev = %*f/%f/%*f/%*f%n",&rta,&match) && match) || 499 (sscanf(buf, "round-trip min/avg/max/std-dev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
478 (sscanf(buf,"round-trip min/avg/max/std-dev = %*f/%f/%*f/%*f%n",&rta,&match) && match) || 500 (sscanf(buf, "round-trip (ms) min/avg/max = %*f/%lf/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
479 (sscanf(buf,"round-trip (ms) min/avg/max = %*f/%f/%*f%n",&rta,&match) && match) || 501 (sscanf(buf, "round-trip (ms) min/avg/max/stddev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
480 (sscanf(buf,"round-trip (ms) min/avg/max/stddev = %*f/%f/%*f/%*f%n",&rta,&match) && match) || 502 (sscanf(buf, "rtt min/avg/max/mdev = %*f/%lf/%*f/%*f ms%n", &result.round_trip_average, &match) == 1 && match) ||
481 (sscanf(buf,"rtt min/avg/max/mdev = %*f/%f/%*f/%*f ms%n",&rta,&match) && match) || 503 (sscanf(buf, "%*[^=] = %*fms, %*[^=] = %*fms, %*[^=] = %lfms%n", &result.round_trip_average, &match) == 1 && match)) {
482 (sscanf(buf, "%*[^=] = %*fms, %*[^=] = %*fms, %*[^=] = %fms%n", &rta, &match) && match)
483 )
484 continue; 504 continue;
505 }
485 } 506 }
486 507
487 /* this is needed because there is no rta if all packets are lost */ 508 /* this is needed because there is no rta if all packets are lost */
488 if (pl == 100) 509 if (result.packet_loss == 100) {
489 rta = crta; 510 result.round_trip_average = crta;
511 }
490 512
491 /* check stderr, setting at least WARNING if there is output here */ 513 /* check stderr, setting at least WARNING if there is output here */
492 /* Add warning into warn_text */ 514 /* Add warning into warn_text */
493 while (fgets (buf, MAX_INPUT_BUFFER - 1, child_stderr)) { 515 while (fgets(buf, MAX_INPUT_BUFFER - 1, child_stderr)) {
494 if ( 516 if (!strstr(buf, "WARNING - no SO_TIMESTAMP support, falling back to SIOCGSTAMP") && !strstr(buf, "Warning: time of day goes back")
495 ! strstr(buf,"WARNING - no SO_TIMESTAMP support, falling back to SIOCGSTAMP")
496 && ! strstr(buf,"Warning: time of day goes back")
497 517
498 ) { 518 ) {
499 if (verbose >= 3) { 519 if (verbose >= 3) {
500 printf("Got stderr: %s", buf); 520 printf("Got stderr: %s", buf);
501 } 521 }
502 if ((result=error_scan(buf, addr)) == STATE_OK) { 522 if ((result.state = error_scan(buf, addr)) == STATE_OK) {
503 result = STATE_WARNING; 523 result.state = STATE_WARNING;
504 if (warn_text == NULL) { 524 if (warn_text == NULL) {
505 warn_text = strdup(_("System call sent warnings to stderr ")); 525 warn_text = strdup(_("System call sent warnings to stderr "));
506 } else { 526 } else {
@@ -510,111 +530,97 @@ run_ping (const char *cmd, const char *addr)
510 } 530 }
511 } 531 }
512 532
513 (void) fclose (child_stderr); 533 (void)fclose(child_stderr);
514 534
535 spclose(child_process);
515 536
516 spclose (child_process); 537 if (warn_text == NULL) {
517
518 if (warn_text == NULL)
519 warn_text = strdup(""); 538 warn_text = strdup("");
539 }
520 540
521 return result; 541 return result;
522} 542}
523 543
544mp_state_enum error_scan(char buf[MAX_INPUT_BUFFER], const char *addr) {
545 if (strstr(buf, "Network is unreachable") || strstr(buf, "Destination Net Unreachable") || strstr(buf, "No route")) {
546 die(STATE_CRITICAL, _("CRITICAL - Network Unreachable (%s)\n"), addr);
547 } else if (strstr(buf, "Destination Host Unreachable") || strstr(buf, "Address unreachable")) {
548 die(STATE_CRITICAL, _("CRITICAL - Host Unreachable (%s)\n"), addr);
549 } else if (strstr(buf, "Destination Port Unreachable") || strstr(buf, "Port unreachable")) {
550 die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Port Unreachable (%s)\n"), addr);
551 } else if (strstr(buf, "Destination Protocol Unreachable")) {
552 die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Protocol Unreachable (%s)\n"), addr);
553 } else if (strstr(buf, "Destination Net Prohibited")) {
554 die(STATE_CRITICAL, _("CRITICAL - Network Prohibited (%s)\n"), addr);
555 } else if (strstr(buf, "Destination Host Prohibited")) {
556 die(STATE_CRITICAL, _("CRITICAL - Host Prohibited (%s)\n"), addr);
557 } else if (strstr(buf, "Packet filtered") || strstr(buf, "Administratively prohibited")) {
558 die(STATE_CRITICAL, _("CRITICAL - Packet Filtered (%s)\n"), addr);
559 } else if (strstr(buf, "unknown host")) {
560 die(STATE_CRITICAL, _("CRITICAL - Host not found (%s)\n"), addr);
561 } else if (strstr(buf, "Time to live exceeded") || strstr(buf, "Time exceeded")) {
562 die(STATE_CRITICAL, _("CRITICAL - Time to live exceeded (%s)\n"), addr);
563 } else if (strstr(buf, "Destination unreachable: ")) {
564 die(STATE_CRITICAL, _("CRITICAL - Destination Unreachable (%s)\n"), addr);
565 }
524 566
567 if (strstr(buf, "(DUP!)") || strstr(buf, "DUPLICATES FOUND")) {
568 if (warn_text == NULL) {
569 warn_text = strdup(_(WARN_DUPLICATES));
570 } else if (!strstr(warn_text, _(WARN_DUPLICATES)) && xasprintf(&warn_text, "%s %s", warn_text, _(WARN_DUPLICATES)) == -1) {
571 die(STATE_UNKNOWN, _("Unable to realloc warn_text\n"));
572 }
573 return STATE_WARNING;
574 }
525 575
526int 576 return STATE_OK;
527error_scan (char buf[MAX_INPUT_BUFFER], const char *addr)
528{
529 if (strstr (buf, "Network is unreachable") ||
530 strstr (buf, "Destination Net Unreachable") ||
531 strstr (buf, "No route")
532 )
533 die (STATE_CRITICAL, _("CRITICAL - Network Unreachable (%s)\n"), addr);
534 else if (strstr (buf, "Destination Host Unreachable") || strstr(buf, "Address unreachable"))
535 die (STATE_CRITICAL, _("CRITICAL - Host Unreachable (%s)\n"), addr);
536 else if (strstr (buf, "Destination Port Unreachable") || strstr(buf, "Port unreachable"))
537 die (STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Port Unreachable (%s)\n"), addr);
538 else if (strstr (buf, "Destination Protocol Unreachable"))
539 die (STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Protocol Unreachable (%s)\n"), addr);
540 else if (strstr (buf, "Destination Net Prohibited"))
541 die (STATE_CRITICAL, _("CRITICAL - Network Prohibited (%s)\n"), addr);
542 else if (strstr (buf, "Destination Host Prohibited"))
543 die (STATE_CRITICAL, _("CRITICAL - Host Prohibited (%s)\n"), addr);
544 else if (strstr (buf, "Packet filtered") || strstr(buf, "Administratively prohibited"))
545 die (STATE_CRITICAL, _("CRITICAL - Packet Filtered (%s)\n"), addr);
546 else if (strstr (buf, "unknown host" ))
547 die (STATE_CRITICAL, _("CRITICAL - Host not found (%s)\n"), addr);
548 else if (strstr (buf, "Time to live exceeded") || strstr(buf, "Time exceeded"))
549 die (STATE_CRITICAL, _("CRITICAL - Time to live exceeded (%s)\n"), addr);
550 else if (strstr (buf, "Destination unreachable: "))
551 die (STATE_CRITICAL, _("CRITICAL - Destination Unreachable (%s)\n"), addr);
552
553 if (strstr (buf, "(DUP!)") || strstr (buf, "DUPLICATES FOUND")) {
554 if (warn_text == NULL)
555 warn_text = strdup (_(WARN_DUPLICATES));
556 else if (! strstr (warn_text, _(WARN_DUPLICATES)) &&
557 xasprintf (&warn_text, "%s %s", warn_text, _(WARN_DUPLICATES)) == -1)
558 die (STATE_UNKNOWN, _("Unable to realloc warn_text\n"));
559 return (STATE_WARNING);
560 }
561
562 return (STATE_OK);
563} 577}
564 578
579void print_help(void) {
580 print_revision(progname, NP_VERSION);
565 581
582 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
583 printf(COPYRIGHT, copyright, email);
566 584
567void 585 printf(_("Use ping to check connection statistics for a remote host."));
568print_help (void)
569{
570 print_revision (progname, NP_VERSION);
571
572 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
573 printf (COPYRIGHT, copyright, email);
574
575 printf (_("Use ping to check connection statistics for a remote host."));
576 586
577 printf ("\n\n"); 587 printf("\n\n");
578 588
579 print_usage (); 589 print_usage();
580 590
581 printf (UT_HELP_VRSN); 591 printf(UT_HELP_VRSN);
582 printf (UT_EXTRA_OPTS); 592 printf(UT_EXTRA_OPTS);
583 593
584 printf (UT_IPv46); 594 printf(UT_IPv46);
585 595
586 printf (" %s\n", "-H, --hostname=HOST"); 596 printf(" %s\n", "-H, --hostname=HOST");
587 printf (" %s\n", _("host to ping")); 597 printf(" %s\n", _("host to ping"));
588 printf (" %s\n", "-w, --warning=THRESHOLD"); 598 printf(" %s\n", "-w, --warning=THRESHOLD");
589 printf (" %s\n", _("warning threshold pair")); 599 printf(" %s\n", _("warning threshold pair"));
590 printf (" %s\n", "-c, --critical=THRESHOLD"); 600 printf(" %s\n", "-c, --critical=THRESHOLD");
591 printf (" %s\n", _("critical threshold pair")); 601 printf(" %s\n", _("critical threshold pair"));
592 printf (" %s\n", "-p, --packets=INTEGER"); 602 printf(" %s\n", "-p, --packets=INTEGER");
593 printf (" %s ", _("number of ICMP ECHO packets to send")); 603 printf(" %s ", _("number of ICMP ECHO packets to send"));
594 printf (_("(Default: %d)\n"), DEFAULT_MAX_PACKETS); 604 printf(_("(Default: %d)\n"), DEFAULT_MAX_PACKETS);
595 printf (" %s\n", "-L, --link"); 605 printf(" %s\n", "-L, --link");
596 printf (" %s\n", _("show HTML in the plugin output (obsoleted by urlize)")); 606 printf(" %s\n", _("show HTML in the plugin output (obsoleted by urlize)"));
597 607
598 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 608 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
599 609
600 printf ("\n"); 610 printf("\n");
601 printf ("%s\n", _("THRESHOLD is <rta>,<pl>% where <rta> is the round trip average travel")); 611 printf("%s\n", _("THRESHOLD is <rta>,<pl>% where <rta> is the round trip average travel"));
602 printf ("%s\n", _("time (ms) which triggers a WARNING or CRITICAL state, and <pl> is the")); 612 printf("%s\n", _("time (ms) which triggers a WARNING or CRITICAL state, and <pl> is the"));
603 printf ("%s\n", _("percentage of packet loss to trigger an alarm state.")); 613 printf("%s\n", _("percentage of packet loss to trigger an alarm state."));
604 614
605 printf ("\n"); 615 printf("\n");
606 printf ("%s\n", _("This plugin uses the ping command to probe the specified host for packet loss")); 616 printf("%s\n", _("This plugin uses the ping command to probe the specified host for packet loss"));
607 printf ("%s\n", _("(percentage) and round trip average (milliseconds). It can produce HTML output")); 617 printf("%s\n", _("(percentage) and round trip average (milliseconds). It can produce HTML output."));
608 printf ("%s\n", _("linking to a traceroute CGI contributed by Ian Cass. The CGI can be found in"));
609 printf ("%s\n", _("the contrib area of the downloads section at http://www.nagios.org/"));
610 618
611 printf (UT_SUPPORT); 619 printf(UT_SUPPORT);
612} 620}
613 621
614void 622void print_usage(void) {
615print_usage (void) 623 printf("%s\n", _("Usage:"));
616{ 624 printf("%s -H <host_address> -w <wrta>,<wpl>%% -c <crta>,<cpl>%%\n", progname);
617 printf ("%s\n", _("Usage:")); 625 printf(" [-p packets] [-t timeout] [-4|-6]\n");
618 printf ("%s -H <host_address> -w <wrta>,<wpl>%% -c <crta>,<cpl>%%\n", progname);
619 printf (" [-p packets] [-t timeout] [-4|-6]\n");
620} 626}
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 1fcbd981..83e6864e 100644
--- a/plugins/check_procs.c
+++ b/plugins/check_procs.c
@@ -1,357 +1,330 @@
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-2008 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-2008"; 39const char *copyright = "2000-2024";
40const char *email = "devel@monitoring-plugins.org"; 40const char *email = "devel@monitoring-plugins.org";
41 41
42#include "common.h" 42#include "common.h"
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
54int process_arguments (int, char **); 56typedef struct {
55int validate_arguments (void); 57 int errorcode;
56int convert_to_seconds (char *); 58 check_procs_config config;
57void 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*/);
60char *warning_range = NULL; 62
61char *critical_range = NULL; 63static int convert_to_seconds(char * /*etime*/, enum metric /*metric*/);
62thresholds *procs_thresholds = NULL; 64static void print_help(void);
63 65void print_usage(void);
64int 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 */ 83
82char *metric_name; 84static int verbose = 0;
83enum metric { 85
84 METRIC_PROCS, 86static int stat_exe(const pid_t pid, struct stat *buf) {
85 METRIC_VSZ,
86 METRIC_RSS,
87 METRIC_CPU,
88 METRIC_ELAPSED
89};
90enum metric metric = METRIC_PROCS;
91
92int verbose = 0;
93int uid;
94pid_t ppid;
95int vsz;
96int rss;
97float pcpu;
98char *statopts;
99char *prog;
100char *exclude_progs;
101char **exclude_progs_arr = NULL;
102char exclude_progs_counter = 0;
103char *args;
104char *input_filename = NULL;
105regex_t re_args;
106char *fmt;
107char *fails;
108char tmp[MAX_INPUT_BUFFER];
109int kthread_filter = 0;
110int usepid = 0; /* whether to test for pid or /proc/pid/exe */
111
112FILE *ps_input = NULL;
113
114static int
115stat_exe (const pid_t pid, struct stat *buf) {
116 char *path; 87 char *path;
117 int ret;
118 xasprintf(&path, "/proc/%d/exe", pid); 88 xasprintf(&path, "/proc/%d/exe", pid);
119 ret = stat(path, buf); 89 int ret = stat(path, buf);
120 free(path); 90 free(path);
121 return ret; 91 return ret;
122} 92}
123 93
124 94int main(int argc, char **argv) {
125int 95 setlocale(LC_ALL, "");
126main (int argc, char **argv)
127{
128 char *input_buffer;
129 char *input_line;
130 char *procprog;
131
132 pid_t mypid = 0;
133 pid_t myppid = 0;
134 struct stat statbuf;
135 dev_t mydev = 0;
136 ino_t myino = 0;
137 int procuid = 0;
138 pid_t procpid = 0;
139 pid_t procppid = 0;
140 pid_t kthread_ppid = 0;
141 int procvsz = 0;
142 int procrss = 0;
143 int procseconds = 0;
144 float procpcpu = 0;
145 char procstat[8];
146 char procetime[MAX_INPUT_BUFFER] = { '\0' };
147 char *procargs;
148
149 const char *zombie = "Z";
150
151 int resultsum = 0; /* bitmask of the filter criteria met by a process */
152 int found = 0; /* counter for number of lines returned in `ps` output */
153 int procs = 0; /* counter for number of processes meeting filter criteria */
154 int pos; /* number of spaces before 'args' in `ps` output */
155 int cols; /* number of columns in ps output */
156 int expected_cols = PS_COLS - 1;
157 int warn = 0; /* number of processes in warn state */
158 int crit = 0; /* number of processes in crit state */
159 int i = 0;
160 int result = STATE_UNKNOWN;
161 int ret = 0;
162 output chld_out, chld_err;
163
164 setlocale (LC_ALL, "");
165 bindtextdomain (PACKAGE, LOCALEDIR);
166 textdomain (PACKAGE);
167 setlocale(LC_NUMERIC, "POSIX"); 96 setlocale(LC_NUMERIC, "POSIX");
168 97 bindtextdomain(PACKAGE, LOCALEDIR);
169 input_buffer = malloc (MAX_INPUT_BUFFER); 98 textdomain(PACKAGE);
170 procprog = malloc (MAX_INPUT_BUFFER);
171
172 xasprintf (&metric_name, "PROCS");
173 metric = METRIC_PROCS;
174 99
175 /* Parse extra opts if any */ 100 /* Parse extra opts if any */
176 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 }
177 107
178 if (process_arguments (argc, argv) == ERROR) 108 check_procs_config config = tmp_config.config;
179 usage4 (_("Could not parse arguments"));
180 109
181 /* find ourself */ 110 /* find ourself */
182 mypid = getpid(); 111 pid_t mypid = getpid();
183 myppid = getppid(); 112 pid_t myppid = getppid();
184 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) {
185 /* usepid might have been set by -T */ 117 /* usepid might have been set by -T */
186 usepid = 1; 118 config.usepid = true;
187 } else { 119 } else {
188 usepid = 0; 120 config.usepid = false;
189 mydev = statbuf.st_dev; 121 mydev = statbuf.st_dev;
190 myino = statbuf.st_ino; 122 myino = statbuf.st_ino;
191 } 123 }
192 124
193 /* Set signal handling and alarm timeout */ 125 /* Set signal handling and alarm timeout */
194 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 126 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
195 die (STATE_UNKNOWN, _("Cannot catch SIGALRM")); 127 die(STATE_UNKNOWN, _("Cannot catch SIGALRM"));
196 } 128 }
197 (void) alarm ((unsigned) timeout_interval); 129 (void)alarm(timeout_interval);
198 130
199 if (verbose >= 2) 131 if (verbose >= 2) {
200 printf (_("CMD: %s\n"), PS_COMMAND); 132 printf(_("CMD: %s\n"), PS_COMMAND);
133 }
201 134
202 if (input_filename == NULL) { 135 output chld_out;
203 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);
204 if (chld_err.lines > 0) { 140 if (chld_err.lines > 0) {
205 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]);
206 exit(STATE_WARNING); 142 exit(STATE_WARNING);
207 } 143 }
208 } else { 144 } else {
209 result = cmd_file_read( input_filename, &chld_out, 0); 145 result = cmd_file_read(config.input_filename, &chld_out, 0);
210 } 146 }
211 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
212 /* flush first line: j starts at 1 */ 168 /* flush first line: j starts at 1 */
213 for (size_t j = 1; j < chld_out.lines; j++) { 169 for (size_t j = 1; j < chld_out.lines; j++) {
214 input_line = chld_out.line[j]; 170 char *input_line = chld_out.line[j];
215 171
216 if (verbose >= 3) 172 if (verbose >= 3) {
217 printf ("%s", input_line); 173 printf("%s", input_line);
174 }
218 175
219 strcpy (procprog, ""); 176 strcpy(procprog, "");
220 xasprintf (&procargs, "%s", ""); 177 char *procargs;
178 xasprintf(&procargs, "%s", "");
221 179
222 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);
223 182
224 /* Zombie processes do not give a procprog command */ 183 /* Zombie processes do not give a procprog command */
225 if ( cols < expected_cols && strstr(procstat, zombie) ) { 184 const char *zombie = "Z";
185 if (cols < expected_cols && strstr(procstat, zombie)) {
226 cols = expected_cols; 186 cols = expected_cols;
227 } 187 }
228 if ( cols >= expected_cols ) { 188 if (cols >= expected_cols) {
229 resultsum = 0; 189 resultsum = 0;
230 xasprintf (&procargs, "%s", input_line + pos); 190 xasprintf(&procargs, "%s", input_line + pos);
231 strip (procargs); 191 strip(procargs);
232 192
233 /* Some ps return full pathname for command. This removes path */ 193 /* Some ps return full pathname for command. This removes path */
234 strcpy(procprog, base_name(procprog)); 194 strcpy(procprog, base_name(procprog));
235 195
236 /* we need to convert the elapsed time to seconds */ 196 /* we need to convert the elapsed time to seconds */
237 procseconds = convert_to_seconds(procetime); 197 procseconds = convert_to_seconds(procetime, config.metric);
238 198
239 if (verbose >= 3) 199 if (verbose >= 3) {
240 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 prog=%s args=%s\n", procs, procuid, procvsz,
241 procs, procuid, procvsz, procrss, 201 procrss, procpid, procppid, procpcpu, procstat, procetime, procprog, procargs);
242 procpid, procppid, procpcpu, procstat, 202 }
243 procetime, procprog, procargs);
244 203
245 /* Ignore self */ 204 /* Ignore self */
246 if ((usepid && mypid == procpid) || 205 int ret = 0;
247 ( ((!usepid) && ((ret = stat_exe(procpid, &statbuf) != -1) && statbuf.st_dev == mydev && statbuf.st_ino == myino)) || 206 if ((config.usepid && mypid == procpid) ||
248 (ret == -1 && errno == ENOENT)) 207 (((!config.usepid) && ((ret = stat_exe(procpid, &statbuf) != -1) && statbuf.st_dev == mydev && statbuf.st_ino == myino)) ||
249 ) { 208 (ret == -1 && errno == ENOENT))) {
250 if (verbose >= 3) 209 if (verbose >= 3) {
251 printf("not considering - is myself or gone\n"); 210 printf("not considering - is myself or gone\n");
211 }
252 continue; 212 continue;
253 } 213 }
254 /* Ignore parent*/ 214 /* Ignore parent*/
255 else if (myppid == procpid) { 215 if (myppid == procpid) {
256 if (verbose >= 3) 216 if (verbose >= 3) {
257 printf("not considering - is parent\n"); 217 printf("not considering - is parent\n");
218 }
258 continue; 219 continue;
259 } 220 }
260 221
261 /* Ignore our own children */ 222 /* Ignore our own children */
262 if (procppid == mypid) { 223 if (procppid == mypid) {
263 if (verbose >= 3) 224 if (verbose >= 3) {
264 printf("not considering - is our child\n"); 225 printf("not considering - is our child\n");
226 }
265 continue; 227 continue;
266 } 228 }
267 229
268 /* Ignore excluded processes by name */ 230 /* Ignore excluded processes by name */
269 if(options & EXCLUDE_PROGS) { 231 if (config.options & EXCLUDE_PROGS) {
270 int found = 0; 232 bool found = false;
271 int i = 0; 233 for (int i = 0; i < (config.exclude_progs_counter); i++) {
272 234 if (!strcmp(procprog, config.exclude_progs_arr[i])) {
273 for(i=0; i < (exclude_progs_counter); i++) { 235 found = true;
274 if(!strcmp(procprog, exclude_progs_arr[i])) { 236 }
275 found = 1; 237 }
276 } 238 if (!found) {
277 } 239 resultsum |= EXCLUDE_PROGS;
278 if(found == 0) { 240 } else {
279 resultsum |= EXCLUDE_PROGS; 241 if (verbose >= 3) {
280 } else 242 printf("excluding - by ignorelist\n");
281 { 243 }
282 if(verbose >= 3) 244 }
283 printf("excluding - by ignorelist\n");
284 }
285 } 245 }
286 246
287 /* filter kernel threads (children of KTHREAD_PARENT)*/ 247 /* filter kernel threads (children of KTHREAD_PARENT)*/
288 /* TODO adapt for other OSes than GNU/Linux 248 /* TODO adapt for other OSes than GNU/Linux
289 sorry for not doing that, but I've no other OSes to test :-( */ 249 sorry for not doing that, but I've no other OSes to test :-( */
290 if (kthread_filter == 1) { 250 if (config.kthread_filter) {
291 /* get pid KTHREAD_PARENT */ 251 /* get pid KTHREAD_PARENT */
292 if (kthread_ppid == 0 && !strcmp(procprog, KTHREAD_PARENT) ) 252 if (kthread_ppid == 0 && !strcmp(procprog, KTHREAD_PARENT)) {
293 kthread_ppid = procpid; 253 kthread_ppid = procpid;
254 }
294 255
295 if (kthread_ppid == procppid) { 256 if (kthread_ppid == procppid) {
296 if (verbose >= 2) 257 if (verbose >= 2) {
297 printf ("Ignore kernel thread: pid=%d ppid=%d prog=%s args=%s\n", procpid, procppid, procprog, procargs); 258 printf("Ignore kernel thread: pid=%d ppid=%d prog=%s args=%s\n", procpid, procppid, procprog, procargs);
259 }
298 continue; 260 continue;
299 } 261 }
300 } 262 }
301 263
302 if ((options & STAT) && (strstr (procstat, statopts))) 264 if ((config.options & STAT) && (strstr(procstat, config.statopts))) {
303 resultsum |= STAT; 265 resultsum |= STAT;
304 if ((options & ARGS) && procargs && (strstr (procargs, args) != NULL)) 266 }
267 if ((config.options & ARGS) && procargs && (strstr(procargs, config.args) != NULL)) {
305 resultsum |= ARGS; 268 resultsum |= ARGS;
306 if ((options & EREG_ARGS) && procargs && (regexec(&re_args, procargs, (size_t) 0, NULL, 0) == 0)) 269 }
270 if ((config.options & EREG_ARGS) && procargs && (regexec(&config.re_args, procargs, (size_t)0, NULL, 0) == 0)) {
307 resultsum |= EREG_ARGS; 271 resultsum |= EREG_ARGS;
308 if ((options & PROG) && procprog && (strcmp (prog, procprog) == 0)) 272 }
273 if ((config.options & PROG) && procprog && (strcmp(config.prog, procprog) == 0)) {
309 resultsum |= PROG; 274 resultsum |= PROG;
310 if ((options & PPID) && (procppid == ppid)) 275 }
276 if ((config.options & PPID) && (procppid == config.ppid)) {
311 resultsum |= PPID; 277 resultsum |= PPID;
312 if ((options & USER) && (procuid == uid)) 278 }
279 if ((config.options & USER) && (procuid == config.uid)) {
313 resultsum |= USER; 280 resultsum |= USER;
314 if ((options & VSZ) && (procvsz >= vsz)) 281 }
282 if ((config.options & VSZ) && (procvsz >= config.vsz)) {
315 resultsum |= VSZ; 283 resultsum |= VSZ;
316 if ((options & RSS) && (procrss >= rss)) 284 }
285 if ((config.options & RSS) && (procrss >= config.rss)) {
317 resultsum |= RSS; 286 resultsum |= RSS;
318 if ((options & PCPU) && (procpcpu >= pcpu)) 287 }
288 if ((config.options & PCPU) && (procpcpu >= config.pcpu)) {
319 resultsum |= PCPU; 289 resultsum |= PCPU;
290 }
320 291
321 found++; 292 found++;
322 293
323 /* Next line if filters not matched */ 294 /* Next line if filters not matched */
324 if (!(options == resultsum || options == ALL)) 295 if (!(config.options == resultsum || config.options == ALL)) {
325 continue; 296 continue;
297 }
326 298
327 procs++; 299 procs++;
328 if (verbose >= 2) { 300 if (verbose >= 2) {
329 printf ("Matched: uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n", 301 printf("Matched: uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n", procuid, procvsz,
330 procuid, procvsz, procrss, 302 procrss, procpid, procppid, procpcpu, procstat, procetime, procprog, procargs);
331 procpid, procppid, procpcpu, procstat,
332 procetime, procprog, procargs);
333 } 303 }
334 304
335 if (metric == METRIC_VSZ) 305 mp_state_enum temporary_result = STATE_OK;
336 i = get_status ((double)procvsz, procs_thresholds); 306 if (config.metric == METRIC_VSZ) {
337 else if (metric == METRIC_RSS) 307 temporary_result = get_status((double)procvsz, config.procs_thresholds);
338 i = get_status ((double)procrss, procs_thresholds); 308 } else if (config.metric == METRIC_RSS) {
309 temporary_result = get_status((double)procrss, config.procs_thresholds);
310 }
339 /* TODO? float thresholds for --metric=CPU */ 311 /* TODO? float thresholds for --metric=CPU */
340 else if (metric == METRIC_CPU) 312 else if (config.metric == METRIC_CPU) {
341 i = get_status (procpcpu, procs_thresholds); 313 temporary_result = get_status(procpcpu, config.procs_thresholds);
342 else if (metric == METRIC_ELAPSED) 314 } else if (config.metric == METRIC_ELAPSED) {
343 i = get_status ((double)procseconds, procs_thresholds); 315 temporary_result = get_status((double)procseconds, config.procs_thresholds);
316 }
344 317
345 if (metric != METRIC_PROCS) { 318 if (config.metric != METRIC_PROCS) {
346 if (i == STATE_WARNING) { 319 if (temporary_result == STATE_WARNING) {
347 warn++; 320 warn++;
348 xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog); 321 xasprintf(&config.fails, "%s%s%s", config.fails, (strcmp(config.fails, "") ? ", " : ""), procprog);
349 result = max_state (result, i); 322 result = max_state(result, temporary_result);
350 } 323 }
351 if (i == STATE_CRITICAL) { 324 if (temporary_result == STATE_CRITICAL) {
352 crit++; 325 crit++;
353 xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog); 326 xasprintf(&config.fails, "%s%s%s", config.fails, (strcmp(config.fails, "") ? ", " : ""), procprog);
354 result = max_state (result, i); 327 result = max_state(result, temporary_result);
355 } 328 }
356 } 329 }
357 } 330 }
@@ -361,339 +334,350 @@ main (int argc, char **argv)
361 } 334 }
362 } 335 }
363 336
364 if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */ 337 if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */
365 printf (_("Unable to read output\n")); 338 printf(_("Unable to read output\n"));
366 return STATE_UNKNOWN; 339 return STATE_UNKNOWN;
367 } 340 }
368 341
369 if ( result == STATE_UNKNOWN ) 342 if (result == STATE_UNKNOWN) {
370 result = STATE_OK; 343 result = STATE_OK;
344 }
371 345
372 /* Needed if procs found, but none match filter */ 346 /* Needed if procs found, but none match filter */
373 if ( metric == METRIC_PROCS ) { 347 if (config.metric == METRIC_PROCS) {
374 result = max_state (result, get_status ((double)procs, procs_thresholds) ); 348 result = max_state(result, get_status((double)procs, config.procs_thresholds));
375 } 349 }
376 350
377 if ( result == STATE_OK ) { 351 if (result == STATE_OK) {
378 printf ("%s %s: ", metric_name, _("OK")); 352 printf("%s %s: ", config.metric_name, _("OK"));
379 } else if (result == STATE_WARNING) { 353 } else if (result == STATE_WARNING) {
380 printf ("%s %s: ", metric_name, _("WARNING")); 354 printf("%s %s: ", config.metric_name, _("WARNING"));
381 if ( metric != METRIC_PROCS ) { 355 if (config.metric != METRIC_PROCS) {
382 printf (_("%d warn out of "), warn); 356 printf(_("%d warn out of "), warn);
383 } 357 }
384 } else if (result == STATE_CRITICAL) { 358 } else if (result == STATE_CRITICAL) {
385 printf ("%s %s: ", metric_name, _("CRITICAL")); 359 printf("%s %s: ", config.metric_name, _("CRITICAL"));
386 if (metric != METRIC_PROCS) { 360 if (config.metric != METRIC_PROCS) {
387 printf (_("%d crit, %d warn out of "), crit, warn); 361 printf(_("%d crit, %d warn out of "), crit, warn);
388 } 362 }
389 } 363 }
390 printf (ngettext ("%d process", "%d processes", (unsigned long) procs), procs); 364 printf(ngettext("%d process", "%d processes", (unsigned long)procs), procs);
391 365
392 if (strcmp(fmt,"") != 0) { 366 if (strcmp(config.fmt, "") != 0) {
393 printf (_(" with %s"), fmt); 367 printf(_(" with %s"), config.fmt);
394 } 368 }
395 369
396 if ( verbose >= 1 && strcmp(fails,"") ) 370 if (verbose >= 1 && strcmp(config.fails, "")) {
397 printf (" [%s]", fails); 371 printf(" [%s]", config.fails);
372 }
398 373
399 if (metric == METRIC_PROCS) 374 if (config.metric == METRIC_PROCS) {
400 printf (" | procs=%d;%s;%s;0;", procs, 375 printf(" | procs=%d;%s;%s;0;", procs, config.warning_range ? config.warning_range : "",
401 warning_range ? warning_range : "", 376 config.critical_range ? config.critical_range : "");
402 critical_range ? critical_range : ""); 377 } else {
403 else 378 printf(" | procs=%d;;;0; procs_warn=%d;;;0; procs_crit=%d;;;0;", procs, warn, crit);
404 printf (" | procs=%d;;;0; procs_warn=%d;;;0; procs_crit=%d;;;0;", procs, warn, crit); 379 }
405 380
406 printf ("\n"); 381 printf("\n");
407 return result; 382 exit(result);
408} 383}
409 384
410
411
412/* process command-line arguments */ 385/* process command-line arguments */
413int 386check_procs_config_wrapper process_arguments(int argc, char **argv) {
414process_arguments (int argc, char **argv) 387 static struct option longopts[] = {{"warning", required_argument, 0, 'w'},
415{ 388 {"critical", required_argument, 0, 'c'},
416 int c = 1; 389 {"metric", required_argument, 0, 'm'},
417 char *user; 390 {"timeout", required_argument, 0, 't'},
418 struct passwd *pw; 391 {"status", required_argument, 0, 's'},
419 int option = 0; 392 {"ppid", required_argument, 0, 'p'},
420 int err; 393 {"user", required_argument, 0, 'u'},
421 int cflags = REG_NOSUB | REG_EXTENDED; 394 {"command", required_argument, 0, 'C'},
422 char errbuf[MAX_INPUT_BUFFER]; 395 {"vsz", required_argument, 0, 'z'},
423 char *temp_string; 396 {"rss", required_argument, 0, 'r'},
424 int i=0; 397 {"pcpu", required_argument, 0, 'P'},
425 static struct option longopts[] = { 398 {"elapsed", required_argument, 0, 'e'},
426 {"warning", required_argument, 0, 'w'}, 399 {"argument-array", required_argument, 0, 'a'},
427 {"critical", required_argument, 0, 'c'}, 400 {"help", no_argument, 0, 'h'},
428 {"metric", required_argument, 0, 'm'}, 401 {"version", no_argument, 0, 'V'},
429 {"timeout", required_argument, 0, 't'}, 402 {"verbose", no_argument, 0, 'v'},
430 {"status", required_argument, 0, 's'}, 403 {"ereg-argument-array", required_argument, 0, CHAR_MAX + 1},
431 {"ppid", required_argument, 0, 'p'}, 404 {"input-file", required_argument, 0, CHAR_MAX + 2},
432 {"user", required_argument, 0, 'u'}, 405 {"no-kthreads", required_argument, 0, 'k'},
433 {"command", required_argument, 0, 'C'}, 406 {"traditional-filter", no_argument, 0, 'T'},
434 {"vsz", required_argument, 0, 'z'}, 407 {"exclude-process", required_argument, 0, 'X'},
435 {"rss", required_argument, 0, 'r'}, 408 {0, 0, 0, 0}};
436 {"pcpu", required_argument, 0, 'P'}, 409
437 {"elapsed", required_argument, 0, 'e'}, 410 for (int index = 1; index < argc; index++) {
438 {"argument-array", required_argument, 0, 'a'}, 411 if (strcmp("-to", argv[index]) == 0) {
439 {"help", no_argument, 0, 'h'}, 412 strcpy(argv[index], "-t");
440 {"version", no_argument, 0, 'V'}, 413 }
441 {"verbose", no_argument, 0, 'v'}, 414 }
442 {"ereg-argument-array", required_argument, 0, CHAR_MAX+1},
443 {"input-file", required_argument, 0, CHAR_MAX+2},
444 {"no-kthreads", required_argument, 0, 'k'},
445 {"traditional-filter", no_argument, 0, 'T'},
446 {"exclude-process", required_argument, 0, 'X'},
447 {0, 0, 0, 0}
448 };
449 415
450 for (c = 1; c < argc; c++) 416 check_procs_config_wrapper result = {
451 if (strcmp ("-to", argv[c]) == 0) 417 .errorcode = OK,
452 strcpy (argv[c], "-t"); 418 .config = check_procs_config_init(),
419 };
453 420
454 while (1) { 421 while (true) {
455 c = getopt_long (argc, argv, "Vvhkt:c:w:p:s:u:C:a:z:r:m:P:T:X:", 422 int option = 0;
456 longopts, &option); 423 int option_index = getopt_long(argc, argv, "Vvhkt:c:w:p:s:u:C:a:z:r:m:P:T:X:", longopts, &option);
457 424
458 if (c == -1 || c == EOF) 425 if (option_index == -1 || option_index == EOF) {
459 break; 426 break;
427 }
460 428
461 switch (c) { 429 switch (option_index) {
462 case '?': /* help */ 430 case '?': /* help */
463 usage5 (); 431 usage5();
464 case 'h': /* help */ 432 case 'h': /* help */
465 print_help (); 433 print_help();
466 exit (STATE_UNKNOWN); 434 exit(STATE_UNKNOWN);
467 case 'V': /* version */ 435 case 'V': /* version */
468 print_revision (progname, NP_VERSION); 436 print_revision(progname, NP_VERSION);
469 exit (STATE_UNKNOWN); 437 exit(STATE_UNKNOWN);
470 case 't': /* timeout period */ 438 case 't': /* timeout period */
471 if (!is_integer (optarg)) 439 if (!is_integer(optarg)) {
472 usage2 (_("Timeout interval must be a positive integer"), optarg); 440 usage2(_("Timeout interval must be a positive integer"), optarg);
473 else 441 } else {
474 timeout_interval = atoi (optarg); 442 timeout_interval = atoi(optarg);
443 }
475 break; 444 break;
476 case 'c': /* critical threshold */ 445 case 'c': /* critical threshold */
477 critical_range = optarg; 446 result.config.critical_range = optarg;
478 break; 447 break;
479 case 'w': /* warning threshold */ 448 case 'w': /* warning threshold */
480 warning_range = optarg; 449 result.config.warning_range = optarg;
481 break; 450 break;
482 case 'p': /* process id */ 451 case 'p': { /* process id */
483 if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) { 452 static char tmp[MAX_INPUT_BUFFER];
484 xasprintf (&fmt, "%s%sPPID = %d", (fmt ? fmt : "") , (options ? ", " : ""), ppid); 453 if (sscanf(optarg, "%d%[^0-9]", &result.config.ppid, tmp) == 1) {
485 options |= PPID; 454 xasprintf(&result.config.fmt, "%s%sPPID = %d", (result.config.fmt ? result.config.fmt : ""),
455 (result.config.options ? ", " : ""), result.config.ppid);
456 result.config.options |= PPID;
486 break; 457 break;
487 } 458 }
488 usage4 (_("Parent Process ID must be an integer!")); 459 usage4(_("Parent Process ID must be an integer!"));
489 case 's': /* status */ 460 }
490 if (statopts) 461 case 's': /* status */
462 if (result.config.statopts) {
491 break; 463 break;
492 else 464 } else {
493 statopts = optarg; 465 result.config.statopts = optarg;
494 xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts); 466 }
495 options |= STAT; 467 xasprintf(&result.config.fmt, _("%s%sSTATE = %s"), (result.config.fmt ? result.config.fmt : ""),
468 (result.config.options ? ", " : ""), result.config.statopts);
469 result.config.options |= STAT;
496 break; 470 break;
497 case 'u': /* user or user id */ 471 case 'u': /* user or user id */ {
498 if (is_integer (optarg)) { 472 struct passwd *pw;
499 uid = atoi (optarg); 473 if (is_integer(optarg)) {
500 pw = getpwuid ((uid_t) uid); 474 result.config.uid = atoi(optarg);
475 pw = getpwuid(result.config.uid);
501 /* check to be sure user exists */ 476 /* check to be sure user exists */
502 if (pw == NULL) 477 if (pw == NULL) {
503 usage2 (_("UID was not found"), optarg); 478 usage2(_("UID was not found"), optarg);
504 } 479 }
505 else { 480 } else {
506 pw = getpwnam (optarg); 481 pw = getpwnam(optarg);
507 /* check to be sure user exists */ 482 /* check to be sure user exists */
508 if (pw == NULL) 483 if (pw == NULL) {
509 usage2 (_("User name was not found"), optarg); 484 usage2(_("User name was not found"), optarg);
485 }
510 /* then get uid */ 486 /* then get uid */
511 uid = pw->pw_uid; 487 result.config.uid = pw->pw_uid;
512 } 488 }
513 user = pw->pw_name; 489
514 xasprintf (&fmt, "%s%sUID = %d (%s)", (fmt ? fmt : ""), (options ? ", " : ""), 490 char *user = pw->pw_name;
515 uid, user); 491 xasprintf(&result.config.fmt, "%s%sUID = %d (%s)", (result.config.fmt ? result.config.fmt : ""),
516 options |= USER; 492 (result.config.options ? ", " : ""), result.config.uid, user);
517 break; 493 result.config.options |= USER;
518 case 'C': /* command */ 494 } break;
495 case 'C': /* command */
519 /* TODO: allow this to be passed in with --metric */ 496 /* TODO: allow this to be passed in with --metric */
520 if (prog) 497 if (result.config.prog) {
521 break; 498 break;
522 else 499 } else {
523 prog = optarg; 500 result.config.prog = optarg;
524 xasprintf (&fmt, _("%s%scommand name '%s'"), (fmt ? fmt : ""), (options ? ", " : ""), 501 }
525 prog); 502 xasprintf(&result.config.fmt, _("%s%scommand name '%s'"), (result.config.fmt ? result.config.fmt : ""),
526 options |= PROG; 503 (result.config.options ? ", " : ""), result.config.prog);
504 result.config.options |= PROG;
527 break; 505 break;
528 case 'X': 506 case 'X':
529 if(exclude_progs) 507 if (result.config.exclude_progs) {
530 break; 508 break;
531 else 509 } else {
532 exclude_progs = optarg; 510 result.config.exclude_progs = optarg;
533 xasprintf (&fmt, _("%s%sexclude progs '%s'"), (fmt ? fmt : ""), (options ? ", " : ""), 511 }
534 exclude_progs); 512 xasprintf(&result.config.fmt, _("%s%sexclude progs '%s'"), (result.config.fmt ? result.config.fmt : ""),
535 char *p = strtok(exclude_progs, ","); 513 (result.config.options ? ", " : ""), result.config.exclude_progs);
536 514 char *tmp_pointer = strtok(result.config.exclude_progs, ",");
537 while(p){ 515
538 exclude_progs_arr = realloc(exclude_progs_arr, sizeof(char*) * ++exclude_progs_counter); 516 while (tmp_pointer) {
539 exclude_progs_arr[exclude_progs_counter-1] = p; 517 result.config.exclude_progs_arr =
540 p = strtok(NULL, ","); 518 realloc(result.config.exclude_progs_arr, sizeof(char *) * ++result.config.exclude_progs_counter);
519 result.config.exclude_progs_arr[result.config.exclude_progs_counter - 1] = tmp_pointer;
520 tmp_pointer = strtok(NULL, ",");
541 } 521 }
542 522
543 options |= EXCLUDE_PROGS; 523 result.config.options |= EXCLUDE_PROGS;
544 break; 524 break;
545 case 'a': /* args (full path name with args) */ 525 case 'a': /* args (full path name with args) */
546 /* TODO: allow this to be passed in with --metric */ 526 /* TODO: allow this to be passed in with --metric */
547 if (args) 527 if (result.config.args) {
548 break; 528 break;
549 else 529 } else {
550 args = optarg; 530 result.config.args = optarg;
551 xasprintf (&fmt, "%s%sargs '%s'", (fmt ? fmt : ""), (options ? ", " : ""), args); 531 }
552 options |= ARGS; 532 xasprintf(&result.config.fmt, "%s%sargs '%s'", (result.config.fmt ? result.config.fmt : ""),
533 (result.config.options ? ", " : ""), result.config.args);
534 result.config.options |= ARGS;
553 break; 535 break;
554 case CHAR_MAX+1: 536 case CHAR_MAX + 1: {
555 err = regcomp(&re_args, optarg, cflags); 537 int cflags = REG_NOSUB | REG_EXTENDED;
538 int err = regcomp(&result.config.re_args, optarg, cflags);
556 if (err != 0) { 539 if (err != 0) {
557 regerror (err, &re_args, errbuf, MAX_INPUT_BUFFER); 540 char errbuf[MAX_INPUT_BUFFER];
558 die (STATE_UNKNOWN, "PROCS %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf); 541 regerror(err, &result.config.re_args, errbuf, MAX_INPUT_BUFFER);
542 die(STATE_UNKNOWN, "PROCS %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
559 } 543 }
560 /* Strip off any | within the regex optarg */ 544 /* Strip off any | within the regex optarg */
561 temp_string = strdup(optarg); 545 char *temp_string = strdup(optarg);
562 while(temp_string[i]!='\0'){ 546 int index = 0;
563 if(temp_string[i]=='|') 547 while (temp_string[index] != '\0') {
564 temp_string[i]=','; 548 if (temp_string[index] == '|') {
565 i++; 549 temp_string[index] = ',';
566 } 550 }
567 xasprintf (&fmt, "%s%sregex args '%s'", (fmt ? fmt : ""), (options ? ", " : ""), temp_string); 551 index++;
568 options |= EREG_ARGS; 552 }
569 break; 553 xasprintf(&result.config.fmt, "%s%sregex args '%s'", (result.config.fmt ? result.config.fmt : ""),
570 case 'r': /* RSS */ 554 (result.config.options ? ", " : ""), temp_string);
571 if (sscanf (optarg, "%d%[^0-9]", &rss, tmp) == 1) { 555 result.config.options |= EREG_ARGS;
572 xasprintf (&fmt, "%s%sRSS >= %d", (fmt ? fmt : ""), (options ? ", " : ""), rss); 556 } break;
573 options |= RSS; 557 case 'r': { /* RSS */
558 static char tmp[MAX_INPUT_BUFFER];
559 if (sscanf(optarg, "%d%[^0-9]", &result.config.rss, tmp) == 1) {
560 xasprintf(&result.config.fmt, "%s%sRSS >= %d", (result.config.fmt ? result.config.fmt : ""),
561 (result.config.options ? ", " : ""), result.config.rss);
562 result.config.options |= RSS;
574 break; 563 break;
575 } 564 }
576 usage4 (_("RSS must be an integer!")); 565 usage4(_("RSS must be an integer!"));
577 case 'z': /* VSZ */ 566 }
578 if (sscanf (optarg, "%d%[^0-9]", &vsz, tmp) == 1) { 567 case 'z': { /* VSZ */
579 xasprintf (&fmt, "%s%sVSZ >= %d", (fmt ? fmt : ""), (options ? ", " : ""), vsz); 568 static char tmp[MAX_INPUT_BUFFER];
580 options |= VSZ; 569 if (sscanf(optarg, "%d%[^0-9]", &result.config.vsz, tmp) == 1) {
570 xasprintf(&result.config.fmt, "%s%sVSZ >= %d", (result.config.fmt ? result.config.fmt : ""),
571 (result.config.options ? ", " : ""), result.config.vsz);
572 result.config.options |= VSZ;
581 break; 573 break;
582 } 574 }
583 usage4 (_("VSZ must be an integer!")); 575 usage4(_("VSZ must be an integer!"));
584 case 'P': /* PCPU */ 576 }
577 case 'P': { /* PCPU */
585 /* TODO: -P 1.5.5 is accepted */ 578 /* TODO: -P 1.5.5 is accepted */
586 if (sscanf (optarg, "%f%[^0-9.]", &pcpu, tmp) == 1) { 579 static char tmp[MAX_INPUT_BUFFER];
587 xasprintf (&fmt, "%s%sPCPU >= %.2f", (fmt ? fmt : ""), (options ? ", " : ""), pcpu); 580 if (sscanf(optarg, "%f%[^0-9.]", &result.config.pcpu, tmp) == 1) {
588 options |= PCPU; 581 xasprintf(&result.config.fmt, "%s%sPCPU >= %.2f", (result.config.fmt ? result.config.fmt : ""),
582 (result.config.options ? ", " : ""), result.config.pcpu);
583 result.config.options |= PCPU;
589 break; 584 break;
590 } 585 }
591 usage4 (_("PCPU must be a float!")); 586 usage4(_("PCPU must be a float!"));
587 }
592 case 'm': 588 case 'm':
593 xasprintf (&metric_name, "%s", optarg); 589 xasprintf(&result.config.metric_name, "%s", optarg);
594 if ( strcmp(optarg, "PROCS") == 0) { 590 if (strcmp(optarg, "PROCS") == 0) {
595 metric = METRIC_PROCS; 591 result.config.metric = METRIC_PROCS;
596 break; 592 break;
597 } 593 }
598 else if ( strcmp(optarg, "VSZ") == 0) { 594 if (strcmp(optarg, "VSZ") == 0) {
599 metric = METRIC_VSZ; 595 result.config.metric = METRIC_VSZ;
600 break; 596 break;
601 } 597 }
602 else if ( strcmp(optarg, "RSS") == 0 ) { 598 if (strcmp(optarg, "RSS") == 0) {
603 metric = METRIC_RSS; 599 result.config.metric = METRIC_RSS;
604 break; 600 break;
605 } 601 }
606 else if ( strcmp(optarg, "CPU") == 0 ) { 602 if (strcmp(optarg, "CPU") == 0) {
607 metric = METRIC_CPU; 603 result.config.metric = METRIC_CPU;
608 break; 604 break;
609 } 605 }
610 else if ( strcmp(optarg, "ELAPSED") == 0) { 606 if (strcmp(optarg, "ELAPSED") == 0) {
611 metric = METRIC_ELAPSED; 607 result.config.metric = METRIC_ELAPSED;
612 break; 608 break;
613 } 609 }
614 610
615 usage4 (_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!")); 611 usage4(_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!"));
616 case 'k': /* linux kernel thread filter */ 612 case 'k': /* linux kernel thread filter */
617 kthread_filter = 1; 613 result.config.kthread_filter = true;
618 break; 614 break;
619 case 'v': /* command */ 615 case 'v': /* command */
620 verbose++; 616 verbose++;
621 break; 617 break;
622 case 'T': 618 case 'T':
623 usepid = 1; 619 result.config.usepid = true;
624 break; 620 break;
625 case CHAR_MAX+2: 621 case CHAR_MAX + 2:
626 input_filename = optarg; 622 result.config.input_filename = optarg;
627 break; 623 break;
628 } 624 }
629 } 625 }
630 626
631 c = optind; 627 int index = optind;
632 if ((! warning_range) && argv[c]) 628 if ((!result.config.warning_range) && argv[index]) {
633 warning_range = argv[c++]; 629 result.config.warning_range = argv[index++];
634 if ((! critical_range) && argv[c]) 630 }
635 critical_range = argv[c++]; 631 if ((!result.config.critical_range) && argv[index]) {
636 if (statopts == NULL && argv[c]) { 632 result.config.critical_range = argv[index++];
637 xasprintf (&statopts, "%s", argv[c++]); 633 }
638 xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts); 634 if (result.config.statopts == NULL && argv[index]) {
639 options |= STAT; 635 xasprintf(&result.config.statopts, "%s", argv[index++]);
636 xasprintf(&result.config.fmt, _("%s%sSTATE = %s"), (result.config.fmt ? result.config.fmt : ""),
637 (result.config.options ? ", " : ""), result.config.statopts);
638 result.config.options |= STAT;
640 } 639 }
641 640
642 /* this will abort in case of invalid ranges */ 641 /* this will abort in case of invalid ranges */
643 set_thresholds (&procs_thresholds, warning_range, critical_range); 642 set_thresholds(&result.config.procs_thresholds, result.config.warning_range, result.config.critical_range);
644 643
645 return validate_arguments (); 644 return validate_arguments(result);
646} 645}
647 646
647check_procs_config_wrapper validate_arguments(check_procs_config_wrapper config_wrapper) {
648 if (config_wrapper.config.options == 0) {
649 config_wrapper.config.options = ALL;
650 }
648 651
652 if (config_wrapper.config.statopts == NULL) {
653 config_wrapper.config.statopts = strdup("");
654 }
649 655
650int 656 if (config_wrapper.config.prog == NULL) {
651validate_arguments () 657 config_wrapper.config.prog = strdup("");
652{ 658 }
653 if (options == 0)
654 options = ALL;
655
656 if (statopts==NULL)
657 statopts = strdup("");
658
659 if (prog==NULL)
660 prog = strdup("");
661 659
662 if (args==NULL) 660 if (config_wrapper.config.args == NULL) {
663 args = strdup(""); 661 config_wrapper.config.args = strdup("");
662 }
664 663
665 if (fmt==NULL) 664 if (config_wrapper.config.fmt == NULL) {
666 fmt = strdup(""); 665 config_wrapper.config.fmt = strdup("");
666 }
667 667
668 if (fails==NULL) 668 if (config_wrapper.config.fails == NULL) {
669 fails = strdup(""); 669 config_wrapper.config.fails = strdup("");
670 }
670 671
671 return options; 672 // return options;
673 return config_wrapper;
672} 674}
673 675
674
675/* convert the elapsed time to seconds */ 676/* convert the elapsed time to seconds */
676int 677int convert_to_seconds(char *etime, enum metric metric) {
677convert_to_seconds(char *etime) { 678 int hyphcnt = 0;
678 679 int coloncnt = 0;
679 char *ptr; 680 for (char *ptr = etime; *ptr != '\0'; ptr++) {
680 int total;
681
682 int hyphcnt;
683 int coloncnt;
684 int days;
685 int hours;
686 int minutes;
687 int seconds;
688
689 hyphcnt = 0;
690 coloncnt = 0;
691 days = 0;
692 hours = 0;
693 minutes = 0;
694 seconds = 0;
695
696 for (ptr = etime; *ptr != '\0'; ptr++) {
697 681
698 if (*ptr == '-') { 682 if (*ptr == '-') {
699 hyphcnt++; 683 hyphcnt++;
@@ -705,9 +689,12 @@ convert_to_seconds(char *etime) {
705 } 689 }
706 } 690 }
707 691
692 int days = 0;
693 int hours = 0;
694 int minutes = 0;
695 int seconds = 0;
708 if (hyphcnt > 0) { 696 if (hyphcnt > 0) {
709 sscanf(etime, "%d-%d:%d:%d", 697 sscanf(etime, "%d-%d:%d:%d", &days, &hours, &minutes, &seconds);
710 &days, &hours, &minutes, &seconds);
711 /* linux 2.6.5/2.6.6 reporting some processes with infinite 698 /* linux 2.6.5/2.6.6 reporting some processes with infinite
712 * elapsed times for some reason */ 699 * elapsed times for some reason */
713 if (days == 49710) { 700 if (days == 49710) {
@@ -715,135 +702,125 @@ convert_to_seconds(char *etime) {
715 } 702 }
716 } else { 703 } else {
717 if (coloncnt == 2) { 704 if (coloncnt == 2) {
718 sscanf(etime, "%d:%d:%d", 705 sscanf(etime, "%d:%d:%d", &hours, &minutes, &seconds);
719 &hours, &minutes, &seconds);
720 } else if (coloncnt == 1) { 706 } else if (coloncnt == 1) {
721 sscanf(etime, "%d:%d", 707 sscanf(etime, "%d:%d", &minutes, &seconds);
722 &minutes, &seconds);
723 } 708 }
724 } 709 }
725 710
726 total = (days * 86400) + 711 int total = (days * 86400) + (hours * 3600) + (minutes * 60) + seconds;
727 (hours * 3600) +
728 (minutes * 60) +
729 seconds;
730 712
731 if (verbose >= 3 && metric == METRIC_ELAPSED) { 713 if (verbose >= 3 && metric == METRIC_ELAPSED) {
732 printf("seconds: %d\n", total); 714 printf("seconds: %d\n", total);
733 } 715 }
734 return total; 716 return total;
735} 717}
736 718
719void print_help(void) {
720 print_revision(progname, NP_VERSION);
737 721
738void 722 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
739print_help (void) 723 printf(COPYRIGHT, copyright, email);
740{
741 print_revision (progname, NP_VERSION);
742
743 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
744 printf (COPYRIGHT, copyright, email);
745 724
746 printf ("%s\n", _("Checks all processes and generates WARNING or CRITICAL states if the specified")); 725 printf("%s\n", _("Checks all processes and generates WARNING or CRITICAL states if the specified"));
747 printf ("%s\n", _("metric is outside the required threshold ranges. The metric defaults to number")); 726 printf("%s\n", _("metric is outside the required threshold ranges. The metric defaults to number"));
748 printf ("%s\n", _("of processes. Search filters can be applied to limit the processes to check.")); 727 printf("%s\n", _("of processes. Search filters can be applied to limit the processes to check."));
749 728
750 printf ("\n\n"); 729 printf("\n\n");
751 730
752 printf ("%s\n", _("The parent process, check_procs itself and any child process of check_procs (ps)")); 731 printf("%s\n", _("The parent process, check_procs itself and any child process of check_procs (ps)"));
753 printf ("%s\n", _("are excluded from any checks to prevent false positives.")); 732 printf("%s\n", _("are excluded from any checks to prevent false positives."));
754 733
755 printf ("\n\n"); 734 printf("\n\n");
756 735
757 print_usage (); 736 print_usage();
758 737
759 printf (UT_HELP_VRSN); 738 printf(UT_HELP_VRSN);
760 printf (UT_EXTRA_OPTS); 739 printf(UT_EXTRA_OPTS);
761 printf (" %s\n", "-w, --warning=RANGE"); 740 printf(" %s\n", "-w, --warning=RANGE");
762 printf (" %s\n", _("Generate warning state if metric is outside this range")); 741 printf(" %s\n", _("Generate warning state if metric is outside this range"));
763 printf (" %s\n", "-c, --critical=RANGE"); 742 printf(" %s\n", "-c, --critical=RANGE");
764 printf (" %s\n", _("Generate critical state if metric is outside this range")); 743 printf(" %s\n", _("Generate critical state if metric is outside this range"));
765 printf (" %s\n", "-m, --metric=TYPE"); 744 printf(" %s\n", "-m, --metric=TYPE");
766 printf (" %s\n", _("Check thresholds against metric. Valid types:")); 745 printf(" %s\n", _("Check thresholds against metric. Valid types:"));
767 printf (" %s\n", _("PROCS - number of processes (default)")); 746 printf(" %s\n", _("PROCS - number of processes (default)"));
768 printf (" %s\n", _("VSZ - virtual memory size")); 747 printf(" %s\n", _("VSZ - virtual memory size"));
769 printf (" %s\n", _("RSS - resident set memory size")); 748 printf(" %s\n", _("RSS - resident set memory size"));
770 printf (" %s\n", _("CPU - percentage CPU")); 749 printf(" %s\n", _("CPU - percentage CPU"));
771/* only linux etime is support currently */ 750/* only linux etime is support currently */
772#if defined( __linux__ ) 751#if defined(__linux__)
773 printf (" %s\n", _("ELAPSED - time elapsed in seconds")); 752 printf(" %s\n", _("ELAPSED - time elapsed in seconds"));
774#endif /* defined(__linux__) */ 753#endif /* defined(__linux__) */
775 printf (UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 754 printf(UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
776 755
777 printf (" %s\n", "-v, --verbose"); 756 printf(" %s\n", "-v, --verbose");
778 printf (" %s\n", _("Extra information. Up to 3 verbosity levels")); 757 printf(" %s\n", _("Extra information. Up to 3 verbosity levels"));
779 758
780 printf (" %s\n", "-T, --traditional"); 759 printf(" %s\n", "-T, --traditional");
781 printf (" %s\n", _("Filter own process the traditional way by PID instead of /proc/pid/exe")); 760 printf(" %s\n", _("Filter own process the traditional way by PID instead of /proc/pid/exe"));
782 761
783 printf ("\n"); 762 printf("\n");
784 printf ("%s\n", "Filters:"); 763 printf("%s\n", "Filters:");
785 printf (" %s\n", "-s, --state=STATUSFLAGS"); 764 printf(" %s\n", "-s, --state=STATUSFLAGS");
786 printf (" %s\n", _("Only scan for processes that have, in the output of `ps`, one or")); 765 printf(" %s\n", _("Only scan for processes that have, in the output of `ps`, one or"));
787 printf (" %s\n", _("more of the status flags you specify (for example R, Z, S, RS,")); 766 printf(" %s\n", _("more of the status flags you specify (for example R, Z, S, RS,"));
788 printf (" %s\n", _("RSZDT, plus others based on the output of your 'ps' command).")); 767 printf(" %s\n", _("RSZDT, plus others based on the output of your 'ps' command)."));
789 printf (" %s\n", "-p, --ppid=PPID"); 768 printf(" %s\n", "-p, --ppid=PPID");
790 printf (" %s\n", _("Only scan for children of the parent process ID indicated.")); 769 printf(" %s\n", _("Only scan for children of the parent process ID indicated."));
791 printf (" %s\n", "-z, --vsz=VSZ"); 770 printf(" %s\n", "-z, --vsz=VSZ");
792 printf (" %s\n", _("Only scan for processes with VSZ higher than indicated.")); 771 printf(" %s\n", _("Only scan for processes with VSZ higher than indicated."));
793 printf (" %s\n", "-r, --rss=RSS"); 772 printf(" %s\n", "-r, --rss=RSS");
794 printf (" %s\n", _("Only scan for processes with RSS higher than indicated.")); 773 printf(" %s\n", _("Only scan for processes with RSS higher than indicated."));
795 printf (" %s\n", "-P, --pcpu=PCPU"); 774 printf(" %s\n", "-P, --pcpu=PCPU");
796 printf (" %s\n", _("Only scan for processes with PCPU higher than indicated.")); 775 printf(" %s\n", _("Only scan for processes with PCPU higher than indicated."));
797 printf (" %s\n", "-u, --user=USER"); 776 printf(" %s\n", "-u, --user=USER");
798 printf (" %s\n", _("Only scan for processes with user name or ID indicated.")); 777 printf(" %s\n", _("Only scan for processes with user name or ID indicated."));
799 printf (" %s\n", "-a, --argument-array=STRING"); 778 printf(" %s\n", "-a, --argument-array=STRING");
800 printf (" %s\n", _("Only scan for processes with args that contain STRING.")); 779 printf(" %s\n", _("Only scan for processes with args that contain STRING."));
801 printf (" %s\n", "--ereg-argument-array=STRING"); 780 printf(" %s\n", "--ereg-argument-array=STRING");
802 printf (" %s\n", _("Only scan for processes with args that contain the regex STRING.")); 781 printf(" %s\n", _("Only scan for processes with args that contain the regex STRING."));
803 printf (" %s\n", "-C, --command=COMMAND"); 782 printf(" %s\n", "-C, --command=COMMAND");
804 printf (" %s\n", _("Only scan for exact matches of COMMAND (without path).")); 783 printf(" %s\n", _("Only scan for exact matches of COMMAND (without path)."));
805 printf (" %s\n", "-X, --exclude-process"); 784 printf(" %s\n", "-X, --exclude-process");
806 printf (" %s\n", _("Exclude processes which match this comma separated list")); 785 printf(" %s\n", _("Exclude processes which match this comma separated list"));
807 printf (" %s\n", "-k, --no-kthreads"); 786 printf(" %s\n", "-k, --no-kthreads");
808 printf (" %s\n", _("Only scan for non kernel threads (works on Linux only).")); 787 printf(" %s\n", _("Only scan for non kernel threads (works on Linux only)."));
809 788
810 printf(_("\n\ 789 printf(_("\n\
811RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n\ 790RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n\
812specified 'max:min', a warning status will be generated if the\n\ 791specified 'max:min', a warning status will be generated if the\n\
813count is inside the specified range\n\n")); 792count is inside the specified range\n\n"));
814 793
815 printf(_("\ 794 printf(_("\
816This plugin checks the number of currently running processes and\n\ 795This plugin checks the number of currently running processes and\n\
817generates WARNING or CRITICAL states if the process count is outside\n\ 796generates WARNING or CRITICAL states if the process count is outside\n\
818the specified threshold ranges. The process count can be filtered by\n\ 797the specified threshold ranges. The process count can be filtered by\n\
819process owner, parent process PID, current state (e.g., 'Z'), or may\n\ 798process owner, parent process PID, current state (e.g., 'Z'), or may\n\
820be the total number of running processes\n\n")); 799be the total number of running processes\n\n"));
821 800
822 printf ("%s\n", _("Examples:")); 801 printf("%s\n", _("Examples:"));
823 printf (" %s\n", "check_procs -w 2:2 -c 2:1024 -C portsentry"); 802 printf(" %s\n", "check_procs -w 2:2 -c 2:1024 -C portsentry");
824 printf (" %s\n", _("Warning if not two processes with command name portsentry.")); 803 printf(" %s\n", _("Warning if not two processes with command name portsentry."));
825 printf (" %s\n\n", _("Critical if < 2 or > 1024 processes")); 804 printf(" %s\n\n", _("Critical if < 2 or > 1024 processes"));
826 printf (" %s\n", "check_procs -c 1: -C sshd"); 805 printf(" %s\n", "check_procs -c 1: -C sshd");
827 printf (" %s\n", _("Critical if not at least 1 process with command sshd")); 806 printf(" %s\n", _("Critical if not at least 1 process with command sshd"));
828 printf (" %s\n", "check_procs -w 1024 -c 1: -C sshd"); 807 printf(" %s\n", "check_procs -w 1024 -c 1: -C sshd");
829 printf (" %s\n", _("Warning if > 1024 processes with command name sshd.")); 808 printf(" %s\n", _("Warning if > 1024 processes with command name sshd."));
830 printf (" %s\n\n", _("Critical if < 1 processes with command name sshd.")); 809 printf(" %s\n\n", _("Critical if < 1 processes with command name sshd."));
831 printf (" %s\n", "check_procs -w 10 -a '/usr/local/bin/perl' -u root"); 810 printf(" %s\n", "check_procs -w 10 -a '/usr/local/bin/perl' -u root");
832 printf (" %s\n", _("Warning alert if > 10 processes with command arguments containing")); 811 printf(" %s\n", _("Warning alert if > 10 processes with command arguments containing"));
833 printf (" %s\n\n", _("'/usr/local/bin/perl' and owned by root")); 812 printf(" %s\n\n", _("'/usr/local/bin/perl' and owned by root"));
834 printf (" %s\n", "check_procs -w 50000 -c 100000 --metric=VSZ"); 813 printf(" %s\n", "check_procs -w 50000 -c 100000 --metric=VSZ");
835 printf (" %s\n\n", _("Alert if VSZ of any processes over 50K or 100K")); 814 printf(" %s\n\n", _("Alert if VSZ of any processes over 50K or 100K"));
836 printf (" %s\n", "check_procs -w 10 -c 20 --metric=CPU"); 815 printf(" %s\n", "check_procs -w 10 -c 20 --metric=CPU");
837 printf (" %s\n", _("Alert if CPU of any processes over 10\% or 20\%")); 816 printf(" %s\n", _("Alert if CPU of any processes over 10%% or 20%%"));
838 817
839 printf (UT_SUPPORT); 818 printf(UT_SUPPORT);
840} 819}
841 820
842void 821void print_usage(void) {
843print_usage (void) 822 printf("%s\n", _("Usage:"));
844{ 823 printf("%s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n", progname);
845 printf ("%s\n", _("Usage:")); 824 printf(" [-u user] [-r rss] [-z vsz] [-P %%cpu] [-a argument-array]\n");
846 printf ("%s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n", progname); 825 printf(" [-C command] [-X process_to_exclude] [-k] [-t timeout] [-v]\n");
847 printf (" [-u user] [-r rss] [-z vsz] [-P %%cpu] [-a argument-array]\n");
848 printf (" [-C command] [-X process_to_exclude] [-k] [-t timeout] [-v]\n");
849} 826}
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 6b32710a..cc846709 100644
--- a/plugins/check_radius.c
+++ b/plugins/check_radius.c
@@ -1,99 +1,92 @@
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-2008 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-2008"; 32const char *copyright = "2000-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 "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
49int process_arguments (int, char **); 51typedef struct {
50void print_help (void); 52 int errorcode;
51void print_usage (void); 53 check_radius_config config;
54} check_radius_config_wrapper;
55static check_radius_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
56static void print_help(void);
57void print_usage(void);
52 58
53#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI) 59#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
54#define my_rc_conf_str(a) rc_conf_str(rch,a) 60# define my_rc_conf_str(a) rc_conf_str(rch, a)
55#if defined(HAVE_LIBRADCLI) 61# if defined(HAVE_LIBRADCLI)
56#define my_rc_send_server(a,b) rc_send_server(rch,a,b,AUTH) 62# define my_rc_send_server(a, b) rc_send_server(rch, a, b, AUTH)
57#else 63# else
58#define my_rc_send_server(a,b) rc_send_server(rch,a,b) 64# define my_rc_send_server(a, b) rc_send_server(rch, a, b)
59#endif 65# endif
60#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADCLI) 66# if defined(HAVE_LIBFREERADIUS_CLIENT) || 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) 67# define my_rc_buildreq(a, b, c, d, e, f) rc_buildreq(rch, a, b, c, d, (a)->secret, e, f)
62#else 68# else
63#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(rch,a,b,c,d,e,f) 69# define my_rc_buildreq(a, b, c, d, e, f) rc_buildreq(rch, a, b, c, d, e, f)
64#endif 70# endif
65#define my_rc_avpair_add(a,b,c,d) rc_avpair_add(rch,a,b,c,-1,d) 71# define my_rc_avpair_add(a, b, c, d) rc_avpair_add(rch, a, b, c, -1, d)
66#define my_rc_read_dictionary(a) rc_read_dictionary(rch, a) 72# define my_rc_read_dictionary(a) rc_read_dictionary(rch, a)
67#else 73#else
68#define my_rc_conf_str(a) rc_conf_str(a) 74# define my_rc_conf_str(a) rc_conf_str(a)
69#define my_rc_send_server(a,b) rc_send_server(a, b) 75# 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) 76# 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) 77# 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) 78# define my_rc_read_dictionary(a) rc_read_dictionary(a)
73#endif 79#endif
74 80
75/* REJECT_RC is only defined in some version of radiusclient. It has 81/* 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 */ 82 * been reported from radiusclient-ng 0.5.6 on FreeBSD 7.2-RELEASE */
77#ifndef REJECT_RC 83#ifndef REJECT_RC
78#define REJECT_RC BADRESP_RC 84# define REJECT_RC BADRESP_RC
79#endif 85#endif
80 86
81int my_rc_read_config(char *); 87static int my_rc_read_config(char * /*a*/, rc_handle ** /*rch*/);
82
83#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
84rc_handle *rch = NULL;
85#endif
86 88
87char *server = NULL; 89static bool verbose = false;
88char *username = NULL;
89char *password = NULL;
90char *nasid = NULL;
91char *nasipaddress = NULL;
92char *expect = NULL;
93char *config_file = NULL;
94unsigned short port = PW_AUTH_UDP_PORT;
95int retries = 1;
96bool verbose = false;
97 90
98/****************************************************************************** 91/******************************************************************************
99 92
@@ -148,149 +141,167 @@ Please note that all tags must be lowercase to use the DocBook XML DTD.
148-@@ 141-@@
149******************************************************************************/ 142******************************************************************************/
150 143
144int main(int argc, char **argv) {
145 setlocale(LC_ALL, "");
146 bindtextdomain(PACKAGE, LOCALEDIR);
147 textdomain(PACKAGE);
151 148
149 /* Parse extra opts if any */
150 argv = np_extra_opts(&argc, argv, progname);
151
152 check_radius_config_wrapper tmp_config = process_arguments(argc, argv);
153
154 if (tmp_config.errorcode == ERROR) {
155 usage4(_("Could not parse arguments"));
156 }
157
158 check_radius_config config = tmp_config.config;
159
160#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
161 rc_handle *rch = NULL;
162#endif
163
164 char *str = strdup("dictionary");
165 if ((config.config_file && my_rc_read_config(config.config_file, &rch)) || my_rc_read_dictionary(my_rc_conf_str(str))) {
166 die(STATE_UNKNOWN, _("Config file error\n"));
167 }
168
169 uint32_t service = PW_AUTHENTICATE_ONLY;
170
171 SEND_DATA data;
172 memset(&data, 0, sizeof(data));
173 if (!(my_rc_avpair_add(&data.send_pairs, PW_SERVICE_TYPE, &service, 0) &&
174 my_rc_avpair_add(&data.send_pairs, PW_USER_NAME, config.username, 0) &&
175 my_rc_avpair_add(&data.send_pairs, PW_USER_PASSWORD, config.password, 0))) {
176 die(STATE_UNKNOWN, _("Out of Memory?\n"));
177 }
178
179 if (config.nas_id != NULL) {
180 if (!(my_rc_avpair_add(&data.send_pairs, PW_NAS_IDENTIFIER, config.nas_id, 0))) {
181 die(STATE_UNKNOWN, _("Invalid NAS-Identifier\n"));
182 }
183 }
152 184
153int
154main (int argc, char **argv)
155{
156 struct sockaddr_storage ss;
157 char name[HOST_NAME_MAX]; 185 char name[HOST_NAME_MAX];
186 if (config.nas_ip_address == NULL) {
187 if (gethostname(name, sizeof(name)) != 0) {
188 die(STATE_UNKNOWN, _("gethostname() failed!\n"));
189 }
190 config.nas_ip_address = name;
191 }
192
193 struct sockaddr_storage radius_server_socket;
194 if (!dns_lookup(config.nas_ip_address, &radius_server_socket, AF_UNSPEC)) {
195 die(STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
196 }
197
198 uint32_t client_id = ntohl(((struct sockaddr_in *)&radius_server_socket)->sin_addr.s_addr);
199 if (my_rc_avpair_add(&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0) == NULL) {
200 die(STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
201 }
202
203 my_rc_buildreq(&data, PW_ACCESS_REQUEST, config.server, config.port, (int)timeout_interval, config.retries);
204
158#ifdef RC_BUFFER_LEN 205#ifdef RC_BUFFER_LEN
159 char msg[RC_BUFFER_LEN]; 206 char msg[RC_BUFFER_LEN];
160#else 207#else
161 char msg[BUFFER_LEN]; 208 char msg[BUFFER_LEN];
162#endif 209#endif
163 SEND_DATA data;
164 int result = STATE_UNKNOWN;
165 uint32_t client_id, service;
166 char *str;
167
168 setlocale (LC_ALL, "");
169 bindtextdomain (PACKAGE, LOCALEDIR);
170 textdomain (PACKAGE);
171 210
172 /* Parse extra opts if any */ 211 int result = my_rc_send_server(&data, msg);
173 argv=np_extra_opts (&argc, argv, progname); 212 rc_avpair_free(data.send_pairs);
213 if (data.receive_pairs) {
214 rc_avpair_free(data.receive_pairs);
215 }
174 216
175 if (process_arguments (argc, argv) == ERROR) 217 if (result == TIMEOUT_RC) {
176 usage4 (_("Could not parse arguments")); 218 printf("Timeout\n");
219 exit(STATE_CRITICAL);
220 }
177 221
178 str = strdup ("dictionary"); 222 if (result == ERROR_RC) {
179 if ((config_file && my_rc_read_config (config_file)) || 223 printf(_("Auth Error\n"));
180 my_rc_read_dictionary (my_rc_conf_str (str))) 224 exit(STATE_CRITICAL);
181 die (STATE_UNKNOWN, _("Config file error\n")); 225 }
182 226
183 service = PW_AUTHENTICATE_ONLY; 227 if (result == REJECT_RC) {
228 printf(_("Auth Failed\n"));
229 exit(STATE_WARNING);
230 }
184 231
185 memset (&data, 0, sizeof(data)); 232 if (result == BADRESP_RC) {
186 if (!(my_rc_avpair_add (&data.send_pairs, PW_SERVICE_TYPE, &service, 0) && 233 printf(_("Bad Response\n"));
187 my_rc_avpair_add (&data.send_pairs, PW_USER_NAME, username, 0) && 234 exit(STATE_WARNING);
188 my_rc_avpair_add (&data.send_pairs, PW_USER_PASSWORD, password, 0) 235 }
189 ))
190 die (STATE_UNKNOWN, _("Out of Memory?\n"));
191 236
192 if (nasid != NULL) { 237 if (config.expect && !strstr(msg, config.expect)) {
193 if (!(my_rc_avpair_add (&data.send_pairs, PW_NAS_IDENTIFIER, nasid, 0))) 238 printf("%s\n", msg);
194 die (STATE_UNKNOWN, _("Invalid NAS-Identifier\n")); 239 exit(STATE_WARNING);
195 } 240 }
196 241
197 if (nasipaddress == NULL) { 242 if (result == OK_RC) {
198 if (gethostname (name, sizeof(name)) != 0) 243 printf(_("Auth OK\n"));
199 die (STATE_UNKNOWN, _("gethostname() failed!\n")); 244 exit(STATE_OK);
200 nasipaddress = name;
201 } 245 }
202 if (!dns_lookup (nasipaddress, &ss, AF_INET)) /* TODO: Support IPv6. */ 246
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); 247 (void)snprintf(msg, sizeof(msg), _("Unexpected result code %d"), result);
229 die (STATE_UNKNOWN, "%s\n", msg); 248 printf("%s\n", msg);
249 exit(STATE_UNKNOWN);
230} 250}
231 251
232
233
234/* process command-line arguments */ 252/* process command-line arguments */
235int 253check_radius_config_wrapper process_arguments(int argc, char **argv) {
236process_arguments (int argc, char **argv) 254 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, {"port", required_argument, 0, 'P'},
237{ 255 {"username", required_argument, 0, 'u'}, {"password", required_argument, 0, 'p'},
238 int c; 256 {"nas-id", required_argument, 0, 'n'}, {"nas-ip-address", required_argument, 0, 'N'},
239 257 {"filename", required_argument, 0, 'F'}, {"expect", required_argument, 0, 'e'},
240 int option = 0; 258 {"retries", required_argument, 0, 'r'}, {"timeout", required_argument, 0, 't'},
241 static struct option longopts[] = { 259 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
242 {"hostname", required_argument, 0, 'H'}, 260 {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
243 {"port", required_argument, 0, 'P'}, 261
244 {"username", required_argument, 0, 'u'}, 262 check_radius_config_wrapper result = {
245 {"password", required_argument, 0, 'p'}, 263 .errorcode = OK,
246 {"nas-id", required_argument, 0, 'n'}, 264 .config = check_radius_config_init(),
247 {"nas-ip-address", required_argument, 0, 'N'},
248 {"filename", required_argument, 0, 'F'},
249 {"expect", required_argument, 0, 'e'},
250 {"retries", required_argument, 0, 'r'},
251 {"timeout", required_argument, 0, 't'},
252 {"verbose", no_argument, 0, 'v'},
253 {"version", no_argument, 0, 'V'},
254 {"help", no_argument, 0, 'h'},
255 {0, 0, 0, 0}
256 }; 265 };
257 266
258 while (1) { 267 while (true) {
259 c = getopt_long (argc, argv, "+hVvH:P:F:u:p:n:N:t:r:e:", longopts, 268 int option = 0;
260 &option); 269 int option_index = getopt_long(argc, argv, "+hVvH:P:F:u:p:n:N:t:r:e:", longopts, &option);
261 270
262 if (c == -1 || c == EOF || c == 1) 271 if (option_index == -1 || option_index == EOF || option_index == 1) {
263 break; 272 break;
273 }
264 274
265 switch (c) { 275 switch (option_index) {
266 case '?': /* print short usage statement if args not parsable */ 276 case '?': /* print short usage statement if args not parsable */
267 usage5 (); 277 usage5();
268 case 'h': /* help */ 278 case 'h': /* help */
269 print_help (); 279 print_help();
270 exit (STATE_UNKNOWN); 280 exit(STATE_UNKNOWN);
271 case 'V': /* version */ 281 case 'V': /* version */
272 print_revision (progname, NP_VERSION); 282 print_revision(progname, NP_VERSION);
273 exit (STATE_UNKNOWN); 283 exit(STATE_UNKNOWN);
274 case 'v': /* verbose mode */ 284 case 'v': /* verbose mode */
275 verbose = true; 285 verbose = true;
276 break; 286 break;
277 case 'H': /* hostname */ 287 case 'H': /* hostname */
278 if (!is_host (optarg)) { 288 if (!is_host(optarg)) {
279 usage2 (_("Invalid hostname/address"), optarg); 289 usage2(_("Invalid hostname/address"), optarg);
280 } 290 }
281 server = optarg; 291 result.config.server = optarg;
282 break; 292 break;
283 case 'P': /* port */ 293 case 'P': /* port */
284 if (is_intnonneg (optarg)) 294 if (is_intnonneg(optarg)) {
285 port = (unsigned short)atoi (optarg); 295 result.config.port = (unsigned short)atoi(optarg);
286 else 296 } else {
287 usage4 (_("Port must be a positive integer")); 297 usage4(_("Port must be a positive integer"));
298 }
288 break; 299 break;
289 case 'u': /* username */ 300 case 'u': /* username */
290 username = optarg; 301 result.config.username = optarg;
291 break; 302 break;
292 case 'p': /* password */ 303 case 'p': /* password */
293 password = strdup(optarg); 304 result.config.password = strdup(optarg);
294 305
295 /* Delete the password from process list */ 306 /* Delete the password from process list */
296 while (*optarg != '\0') { 307 while (*optarg != '\0') {
@@ -298,119 +309,115 @@ process_arguments (int argc, char **argv)
298 optarg++; 309 optarg++;
299 } 310 }
300 break; 311 break;
301 case 'n': /* nas id */ 312 case 'n': /* nas id */
302 nasid = optarg; 313 result.config.nas_id = optarg;
303 break; 314 break;
304 case 'N': /* nas ip address */ 315 case 'N': /* nas ip address */
305 nasipaddress = optarg; 316 result.config.nas_ip_address = optarg;
306 break; 317 break;
307 case 'F': /* configuration file */ 318 case 'F': /* configuration file */
308 config_file = optarg; 319 result.config.config_file = optarg;
309 break; 320 break;
310 case 'e': /* expect */ 321 case 'e': /* expect */
311 expect = optarg; 322 result.config.expect = optarg;
312 break; 323 break;
313 case 'r': /* retries */ 324 case 'r': /* retries */
314 if (is_intpos (optarg)) 325 if (is_intpos(optarg)) {
315 retries = atoi (optarg); 326 result.config.retries = atoi(optarg);
316 else 327 } else {
317 usage4 (_("Number of retries must be a positive integer")); 328 usage4(_("Number of retries must be a positive integer"));
329 }
318 break; 330 break;
319 case 't': /* timeout */ 331 case 't': /* timeout */
320 if (is_intpos (optarg)) 332 if (is_intpos(optarg)) {
321 timeout_interval = (unsigned)atoi (optarg); 333 timeout_interval = (unsigned)atoi(optarg);
322 else 334 } else {
323 usage2 (_("Timeout interval must be a positive integer"), optarg); 335 usage2(_("Timeout interval must be a positive integer"), optarg);
336 }
324 break; 337 break;
325 } 338 }
326 } 339 }
327 340
328 if (server == NULL) 341 if (result.config.server == NULL) {
329 usage4 (_("Hostname was not supplied")); 342 usage4(_("Hostname was not supplied"));
330 if (username == NULL) 343 }
331 usage4 (_("User not specified")); 344 if (result.config.username == NULL) {
332 if (password == NULL) 345 usage4(_("User not specified"));
333 usage4 (_("Password not specified")); 346 }
334 if (config_file == NULL) 347 if (result.config.password == NULL) {
335 usage4 (_("Configuration file not specified")); 348 usage4(_("Password not specified"));
349 }
350 if (result.config.config_file == NULL) {
351 usage4(_("Configuration file not specified"));
352 }
336 353
337 return OK; 354 return result;
338} 355}
339 356
340 357void print_help(void) {
341
342void
343print_help (void)
344{
345 char *myport; 358 char *myport;
346 xasprintf (&myport, "%d", PW_AUTH_UDP_PORT); 359 xasprintf(&myport, "%d", PW_AUTH_UDP_PORT);
347 360
348 print_revision (progname, NP_VERSION); 361 print_revision(progname, NP_VERSION);
349 362
350 printf ("Copyright (c) 1999 Robert August Vincent II\n"); 363 printf("Copyright (c) 1999 Robert August Vincent II\n");
351 printf (COPYRIGHT, copyright, email); 364 printf(COPYRIGHT, copyright, email);
352 365
353 printf("%s\n", _("Tests to see if a RADIUS server is accepting connections.")); 366 printf("%s\n", _("Tests to see if a RADIUS server is accepting connections."));
354 367
355 printf ("\n\n"); 368 printf("\n\n");
356 369
357 print_usage (); 370 print_usage();
358 371
359 printf (UT_HELP_VRSN); 372 printf(UT_HELP_VRSN);
360 printf (UT_EXTRA_OPTS); 373 printf(UT_EXTRA_OPTS);
361 374
362 printf (UT_HOST_PORT, 'P', myport); 375 printf(UT_HOST_PORT, 'P', myport);
363 376
364 printf (" %s\n", "-u, --username=STRING"); 377 printf(" %s\n", "-u, --username=STRING");
365 printf (" %s\n", _("The user to authenticate")); 378 printf(" %s\n", _("The user to authenticate"));
366 printf (" %s\n", "-p, --password=STRING"); 379 printf(" %s\n", "-p, --password=STRING");
367 printf (" %s\n", _("Password for authentication (SECURITY RISK)")); 380 printf(" %s\n", _("Password for authentication (SECURITY RISK)"));
368 printf (" %s\n", "-n, --nas-id=STRING"); 381 printf(" %s\n", "-n, --nas-id=STRING");
369 printf (" %s\n", _("NAS identifier")); 382 printf(" %s\n", _("NAS identifier"));
370 printf (" %s\n", "-N, --nas-ip-address=STRING"); 383 printf(" %s\n", "-N, --nas-ip-address=STRING");
371 printf (" %s\n", _("NAS IP Address")); 384 printf(" %s\n", _("NAS IP Address"));
372 printf (" %s\n", "-F, --filename=STRING"); 385 printf(" %s\n", "-F, --filename=STRING");
373 printf (" %s\n", _("Configuration file")); 386 printf(" %s\n", _("Configuration file"));
374 printf (" %s\n", "-e, --expect=STRING"); 387 printf(" %s\n", "-e, --expect=STRING");
375 printf (" %s\n", _("Response string to expect from the server")); 388 printf(" %s\n", _("Response string to expect from the server"));
376 printf (" %s\n", "-r, --retries=INTEGER"); 389 printf(" %s\n", "-r, --retries=INTEGER");
377 printf (" %s\n", _("Number of times to retry a failed connection")); 390 printf(" %s\n", _("Number of times to retry a failed connection"));
378 391
379 printf (UT_CONN_TIMEOUT, timeout_interval); 392 printf(UT_CONN_TIMEOUT, timeout_interval);
380 393
381 printf ("\n"); 394 printf("\n");
382 printf ("%s\n", _("This plugin tests a RADIUS server to see if it is accepting connections.")); 395 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")); 396 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")); 397 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.")); 398 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")); 399 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")); 400 printf("%s\n", _("password can possibly be determined by careful watching of the command line"));
388 printf ("%s\n", _("in a process listing. This risk is exacerbated because the plugin will")); 401 printf("%s\n", _("in a process listing. This risk is exacerbated because the plugin will"));
389 printf ("%s\n", _("typically be executed at regular predictable intervals. Please be sure that")); 402 printf("%s\n", _("typically be executed at regular predictable intervals. Please be sure that"));
390 printf ("%s\n", _("the password used does not allow access to sensitive system resources.")); 403 printf("%s\n", _("the password used does not allow access to sensitive system resources."));
391 404
392 printf (UT_SUPPORT); 405 printf(UT_SUPPORT);
393} 406}
394 407
395 408void print_usage(void) {
396 409 printf("%s\n", _("Usage:"));
397void 410 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\ 411 [-P port] [-t timeout] [-r retries] [-e expect]\n\
403 [-n nas-id] [-N nas-ip-addr]\n", progname); 412 [-n nas-id] [-N nas-ip-addr]\n",
413 progname);
404} 414}
405 415
406 416int my_rc_read_config(char *config_file_name, rc_handle **rch) {
407
408int my_rc_read_config(char * a)
409{
410#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI) 417#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
411 rch = rc_read_config(a); 418 *rch = rc_read_config(config_file_name);
412 return (rch == NULL) ? 1 : 0; 419 return (rch == NULL) ? 1 : 0;
413#else 420#else
414 return rc_read_config(a); 421 return rc_read_config(config_file_name);
415#endif 422#endif
416} 423}
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 15e035b6..ec0928ed 100644
--- a/plugins/check_real.c
+++ b/plugins/check_real.c
@@ -1,454 +1,439 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_real plugin 3 * Monitoring check_real plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2007 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_real plugin 10 * This file contains the check_real plugin
11* 11 *
12* This plugin tests the REAL service on the specified host. 12 * This plugin tests the REAL service on the specified host.
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#include "states.h"
32#include <stdio.h>
31const char *progname = "check_real"; 33const char *progname = "check_real";
32const char *copyright = "2000-2007"; 34const char *copyright = "2000-2024";
33const char *email = "devel@monitoring-plugins.org"; 35const char *email = "devel@monitoring-plugins.org";
34 36
35#include "common.h" 37#include "common.h"
36#include "netutils.h" 38#include "netutils.h"
37#include "utils.h" 39#include "utils.h"
40#include "check_real.d/config.h"
38 41
39enum { 42#define EXPECT "RTSP/1."
40 PORT = 554 43#define URL ""
41};
42
43#define EXPECT "RTSP/1."
44#define URL ""
45 44
46int process_arguments (int, char **); 45typedef struct {
47int validate_arguments (void); 46 int errorcode;
48void print_help (void); 47 check_real_config config;
49void print_usage (void); 48} check_real_config_wrapper;
49static check_real_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
50 50
51int server_port = PORT; 51static void print_help(void);
52char *server_address; 52void print_usage(void);
53char *host_name;
54char *server_url = NULL;
55char *server_expect;
56int warning_time = 0;
57bool check_warning_time = false;
58int critical_time = 0;
59bool check_critical_time = false;
60bool verbose = false;
61 53
54static bool verbose = false;
62 55
63 56int main(int argc, char **argv) {
64int 57 setlocale(LC_ALL, "");
65main (int argc, char **argv) 58 bindtextdomain(PACKAGE, LOCALEDIR);
66{ 59 textdomain(PACKAGE);
67 int sd;
68 int result = STATE_UNKNOWN;
69 char buffer[MAX_INPUT_BUFFER];
70 char *status_line = NULL;
71
72 setlocale (LC_ALL, "");
73 bindtextdomain (PACKAGE, LOCALEDIR);
74 textdomain (PACKAGE);
75 60
76 /* Parse extra opts if any */ 61 /* Parse extra opts if any */
77 argv=np_extra_opts (&argc, argv, progname); 62 argv = np_extra_opts(&argc, argv, progname);
63
64 check_real_config_wrapper tmp_config = process_arguments(argc, argv);
65 if (tmp_config.errorcode == ERROR) {
66 usage4(_("Could not parse arguments"));
67 }
78 68
79 if (process_arguments (argc, argv) == ERROR) 69 const check_real_config config = tmp_config.config;
80 usage4 (_("Could not parse arguments"));
81 70
82 /* initialize alarm signal handling */ 71 /* initialize alarm signal handling */
83 signal (SIGALRM, socket_timeout_alarm_handler); 72 signal(SIGALRM, socket_timeout_alarm_handler);
84 73
85 /* set socket timeout */ 74 /* set socket timeout */
86 alarm (socket_timeout); 75 alarm(socket_timeout);
87 time (&start_time); 76 time(&start_time);
88 77
89 /* try to connect to the host at the given port number */ 78 /* try to connect to the host at the given port number */
90 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK) 79 int socket;
91 die (STATE_CRITICAL, _("Unable to connect to %s on port %d\n"), 80 if (my_tcp_connect(config.server_address, config.server_port, &socket) != STATE_OK) {
92 server_address, server_port); 81 die(STATE_CRITICAL, _("Unable to connect to %s on port %d\n"), config.server_address, config.server_port);
82 }
93 83
94 /* Part I - Server Check */ 84 /* Part I - Server Check */
95 85
96 /* send the OPTIONS request */ 86 /* send the OPTIONS request */
97 sprintf (buffer, "OPTIONS rtsp://%s:%d RTSP/1.0\r\n", host_name, server_port); 87 char buffer[MAX_INPUT_BUFFER];
98 result = send (sd, buffer, strlen (buffer), 0); 88 sprintf(buffer, "OPTIONS rtsp://%s:%d RTSP/1.0\r\n", config.host_name, config.server_port);
89 ssize_t sent_bytes = send(socket, buffer, strlen(buffer), 0);
90 if (sent_bytes == -1) {
91 die(STATE_CRITICAL, _("Sending options to %s failed\n"), config.host_name);
92 }
99 93
100 /* send the header sync */ 94 /* send the header sync */
101 sprintf (buffer, "CSeq: 1\r\n"); 95 sprintf(buffer, "CSeq: 1\r\n");
102 result = send (sd, buffer, strlen (buffer), 0); 96 sent_bytes = send(socket, buffer, strlen(buffer), 0);
97 if (sent_bytes == -1) {
98 die(STATE_CRITICAL, _("Sending header sync to %s failed\n"), config.host_name);
99 }
103 100
104 /* send a newline so the server knows we're done with the request */ 101 /* send a newline so the server knows we're done with the request */
105 sprintf (buffer, "\r\n"); 102 sprintf(buffer, "\r\n");
106 result = send (sd, buffer, strlen (buffer), 0); 103 sent_bytes = send(socket, buffer, strlen(buffer), 0);
104 if (sent_bytes == -1) {
105 die(STATE_CRITICAL, _("Sending newline to %s failed\n"), config.host_name);
106 }
107 107
108 /* watch for the REAL connection string */ 108 /* watch for the REAL connection string */
109 result = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0); 109 ssize_t received_bytes = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0);
110 110
111 /* return a CRITICAL status if we couldn't read any data */ 111 /* return a CRITICAL status if we couldn't read any data */
112 if (result == -1) 112 if (received_bytes == -1) {
113 die (STATE_CRITICAL, _("No data received from %s\n"), host_name); 113 die(STATE_CRITICAL, _("No data received from %s\n"), config.host_name);
114 }
114 115
116 mp_state_enum result = STATE_OK;
117 char *status_line = NULL;
115 /* make sure we find the response we are looking for */ 118 /* make sure we find the response we are looking for */
116 if (!strstr (buffer, server_expect)) { 119 if (!strstr(buffer, config.server_expect)) {
117 if (server_port == PORT) 120 if (config.server_port == PORT) {
118 printf ("%s\n", _("Invalid REAL response received from host")); 121 printf("%s\n", _("Invalid REAL response received from host"));
119 else 122 } else {
120 printf (_("Invalid REAL response received from host on port %d\n"), 123 printf(_("Invalid REAL response received from host on port %d\n"), config.server_port);
121 server_port); 124 }
122 } 125 } else {
123 else {
124 /* else we got the REAL string, so check the return code */ 126 /* else we got the REAL string, so check the return code */
125 127
126 time (&end_time); 128 time(&end_time);
127 129
128 result = STATE_OK; 130 result = STATE_OK;
129 131
130 status_line = (char *) strtok (buffer, "\n"); 132 status_line = strtok(buffer, "\n");
131 133
132 if (strstr (status_line, "200")) 134 if (strstr(status_line, "200")) {
133 result = STATE_OK; 135 result = STATE_OK;
136 }
134 137
135 /* client errors result in a warning state */ 138 /* client errors result in a warning state */
136 else if (strstr (status_line, "400")) 139 else if (strstr(status_line, "400")) {
137 result = STATE_WARNING; 140 result = STATE_WARNING;
138 else if (strstr (status_line, "401")) 141 } else if (strstr(status_line, "401")) {
139 result = STATE_WARNING; 142 result = STATE_WARNING;
140 else if (strstr (status_line, "402")) 143 } else if (strstr(status_line, "402")) {
141 result = STATE_WARNING; 144 result = STATE_WARNING;
142 else if (strstr (status_line, "403")) 145 } else if (strstr(status_line, "403")) {
143 result = STATE_WARNING; 146 result = STATE_WARNING;
144 else if (strstr (status_line, "404")) 147 } else if (strstr(status_line, "404")) {
145 result = STATE_WARNING; 148 result = STATE_WARNING;
146 149 } else if (strstr(status_line, "500")) {
147 /* server errors result in a critical state */ 150 /* server errors result in a critical state */
148 else if (strstr (status_line, "500"))
149 result = STATE_CRITICAL; 151 result = STATE_CRITICAL;
150 else if (strstr (status_line, "501")) 152 } else if (strstr(status_line, "501")) {
151 result = STATE_CRITICAL; 153 result = STATE_CRITICAL;
152 else if (strstr (status_line, "502")) 154 } else if (strstr(status_line, "502")) {
153 result = STATE_CRITICAL; 155 result = STATE_CRITICAL;
154 else if (strstr (status_line, "503")) 156 } else if (strstr(status_line, "503")) {
155 result = STATE_CRITICAL; 157 result = STATE_CRITICAL;
156 158 } else {
157 else
158 result = STATE_UNKNOWN; 159 result = STATE_UNKNOWN;
160 }
159 } 161 }
160 162
161 /* Part II - Check stream exists and is ok */ 163 /* Part II - Check stream exists and is ok */
162 if ((result == STATE_OK )&& (server_url != NULL) ) { 164 if ((result == STATE_OK) && (config.server_url != NULL)) {
163 165
164 /* Part I - Server Check */ 166 /* Part I - Server Check */
165 167
166 /* send the DESCRIBE request */ 168 /* send the DESCRIBE request */
167 sprintf (buffer, "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n", host_name, 169 sprintf(buffer, "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n", config.host_name, config.server_port, config.server_url);
168 server_port, server_url); 170
169 result = send (sd, buffer, strlen (buffer), 0); 171 ssize_t sent_bytes = send(socket, buffer, strlen(buffer), 0);
172 if (sent_bytes == -1) {
173 die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name);
174 }
170 175
171 /* send the header sync */ 176 /* send the header sync */
172 sprintf (buffer, "CSeq: 2\r\n"); 177 sprintf(buffer, "CSeq: 2\r\n");
173 result = send (sd, buffer, strlen (buffer), 0); 178 sent_bytes = send(socket, buffer, strlen(buffer), 0);
179 if (sent_bytes == -1) {
180 die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name);
181 }
174 182
175 /* send a newline so the server knows we're done with the request */ 183 /* send a newline so the server knows we're done with the request */
176 sprintf (buffer, "\r\n"); 184 sprintf(buffer, "\r\n");
177 result = send (sd, buffer, strlen (buffer), 0); 185 sent_bytes = send(socket, buffer, strlen(buffer), 0);
186 if (sent_bytes == -1) {
187 die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name);
188 }
178 189
179 /* watch for the REAL connection string */ 190 /* watch for the REAL connection string */
180 result = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0); 191 ssize_t recv_bytes = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0);
181 buffer[result] = '\0'; /* null terminate received buffer */ 192 if (recv_bytes == -1) {
182 193 /* return a CRITICAL status if we couldn't read any data */
183 /* return a CRITICAL status if we couldn't read any data */ 194 printf(_("No data received from host\n"));
184 if (result == -1) {
185 printf (_("No data received from host\n"));
186 result = STATE_CRITICAL; 195 result = STATE_CRITICAL;
187 } 196 } else {
188 else { 197 buffer[result] = '\0'; /* null terminate received buffer */
189 /* make sure we find the response we are looking for */ 198 /* make sure we find the response we are looking for */
190 if (!strstr (buffer, server_expect)) { 199 if (!strstr(buffer, config.server_expect)) {
191 if (server_port == PORT) 200 if (config.server_port == PORT) {
192 printf ("%s\n", _("Invalid REAL response received from host")); 201 printf("%s\n", _("Invalid REAL response received from host"));
193 else 202 } else {
194 printf (_("Invalid REAL response received from host on port %d\n"), 203 printf(_("Invalid REAL response received from host on port %d\n"), config.server_port);
195 server_port); 204 }
196 } 205 } else {
197 else {
198 206
199 /* else we got the REAL string, so check the return code */ 207 /* else we got the REAL string, so check the return code */
200 208
201 time (&end_time); 209 time(&end_time);
202 210
203 result = STATE_OK; 211 result = STATE_OK;
204 212
205 status_line = (char *) strtok (buffer, "\n"); 213 status_line = strtok(buffer, "\n");
206 214
207 if (strstr (status_line, "200")) 215 if (strstr(status_line, "200")) {
208 result = STATE_OK; 216 result = STATE_OK;
217 }
209 218
210 /* client errors result in a warning state */ 219 /* client errors result in a warning state */
211 else if (strstr (status_line, "400")) 220 else if (strstr(status_line, "400")) {
212 result = STATE_WARNING; 221 result = STATE_WARNING;
213 else if (strstr (status_line, "401")) 222 } else if (strstr(status_line, "401")) {
214 result = STATE_WARNING; 223 result = STATE_WARNING;
215 else if (strstr (status_line, "402")) 224 } else if (strstr(status_line, "402")) {
216 result = STATE_WARNING; 225 result = STATE_WARNING;
217 else if (strstr (status_line, "403")) 226 } else if (strstr(status_line, "403")) {
218 result = STATE_WARNING; 227 result = STATE_WARNING;
219 else if (strstr (status_line, "404")) 228 } else if (strstr(status_line, "404")) {
220 result = STATE_WARNING; 229 result = STATE_WARNING;
230 }
221 231
222 /* server errors result in a critical state */ 232 /* server errors result in a critical state */
223 else if (strstr (status_line, "500")) 233 else if (strstr(status_line, "500")) {
224 result = STATE_CRITICAL; 234 result = STATE_CRITICAL;
225 else if (strstr (status_line, "501")) 235 } else if (strstr(status_line, "501")) {
226 result = STATE_CRITICAL; 236 result = STATE_CRITICAL;
227 else if (strstr (status_line, "502")) 237 } else if (strstr(status_line, "502")) {
228 result = STATE_CRITICAL; 238 result = STATE_CRITICAL;
229 else if (strstr (status_line, "503")) 239 } else if (strstr(status_line, "503")) {
230 result = STATE_CRITICAL; 240 result = STATE_CRITICAL;
241 }
231 242
232 else 243 else {
233 result = STATE_UNKNOWN; 244 result = STATE_UNKNOWN;
245 }
234 } 246 }
235 } 247 }
236 } 248 }
237 249
238 /* Return results */ 250 /* Return results */
239 if (result == STATE_OK) { 251 if (result == STATE_OK) {
240 252 if (config.check_critical_time && (end_time - start_time) > config.critical_time) {
241 if (check_critical_time 253 result = STATE_CRITICAL;
242 && (end_time - start_time) > critical_time) result = STATE_CRITICAL; 254 } else if (config.check_warning_time && (end_time - start_time) > config.warning_time) {
243 else if (check_warning_time 255 result = STATE_WARNING;
244 && (end_time - start_time) > warning_time) result = 256 }
245 STATE_WARNING;
246 257
247 /* Put some HTML in here to create a dynamic link */ 258 /* Put some HTML in here to create a dynamic link */
248 printf (_("REAL %s - %d second response time\n"), 259 printf(_("REAL %s - %d second response time\n"), state_text(result), (int)(end_time - start_time));
249 state_text (result), 260 } else {
250 (int) (end_time - start_time)); 261 printf("%s\n", status_line);
251 } 262 }
252 else
253 printf ("%s\n", status_line);
254 263
255 /* close the connection */ 264 /* close the connection */
256 close (sd); 265 close(socket);
257 266
258 /* reset the alarm */ 267 /* reset the alarm */
259 alarm (0); 268 alarm(0);
260 269
261 return result; 270 exit(result);
262} 271}
263 272
264
265
266/* process command-line arguments */ 273/* process command-line arguments */
267int 274check_real_config_wrapper process_arguments(int argc, char **argv) {
268process_arguments (int argc, char **argv) 275 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, {"IPaddress", required_argument, 0, 'I'},
269{ 276 {"expect", required_argument, 0, 'e'}, {"url", required_argument, 0, 'u'},
270 int c; 277 {"port", required_argument, 0, 'p'}, {"critical", required_argument, 0, 'c'},
271 278 {"warning", required_argument, 0, 'w'}, {"timeout", required_argument, 0, 't'},
272 int option = 0; 279 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
273 static struct option longopts[] = { 280 {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
274 {"hostname", required_argument, 0, 'H'}, 281
275 {"IPaddress", required_argument, 0, 'I'}, 282 check_real_config_wrapper result = {
276 {"expect", required_argument, 0, 'e'}, 283 .errorcode = OK,
277 {"url", required_argument, 0, 'u'}, 284 .config = check_real_config_init(),
278 {"port", required_argument, 0, 'p'},
279 {"critical", required_argument, 0, 'c'},
280 {"warning", required_argument, 0, 'w'},
281 {"timeout", required_argument, 0, 't'},
282 {"verbose", no_argument, 0, 'v'},
283 {"version", no_argument, 0, 'V'},
284 {"help", no_argument, 0, 'h'},
285 {0, 0, 0, 0}
286 }; 285 };
287 286
288 if (argc < 2) 287 if (argc < 2) {
289 return ERROR; 288 result.errorcode = ERROR;
289 return result;
290 }
290 291
291 for (c = 1; c < argc; c++) { 292 for (int i = 1; i < argc; i++) {
292 if (strcmp ("-to", argv[c]) == 0) 293 if (strcmp("-to", argv[i]) == 0) {
293 strcpy (argv[c], "-t"); 294 strcpy(argv[i], "-t");
294 else if (strcmp ("-wt", argv[c]) == 0) 295 } else if (strcmp("-wt", argv[i]) == 0) {
295 strcpy (argv[c], "-w"); 296 strcpy(argv[i], "-w");
296 else if (strcmp ("-ct", argv[c]) == 0) 297 } else if (strcmp("-ct", argv[i]) == 0) {
297 strcpy (argv[c], "-c"); 298 strcpy(argv[i], "-c");
299 }
298 } 300 }
299 301
300 while (1) { 302 while (true) {
301 c = getopt_long (argc, argv, "+hvVI:H:e:u:p:w:c:t:", longopts, 303 int option = 0;
302 &option); 304 int option_char = getopt_long(argc, argv, "+hvVI:H:e:u:p:w:c:t:", longopts, &option);
303 305
304 if (c == -1 || c == EOF) 306 if (option_char == -1 || option_char == EOF) {
305 break; 307 break;
308 }
306 309
307 switch (c) { 310 switch (option_char) {
308 case 'I': /* hostname */ 311 case 'I': /* hostname */
309 case 'H': /* hostname */ 312 case 'H': /* hostname */
310 if (server_address) 313 if (result.config.server_address) {
311 break; 314 break;
312 else if (is_host (optarg)) 315 } else if (is_host(optarg)) {
313 server_address = optarg; 316 result.config.server_address = optarg;
314 else 317 } else {
315 usage2 (_("Invalid hostname/address"), optarg); 318 usage2(_("Invalid hostname/address"), optarg);
319 }
316 break; 320 break;
317 case 'e': /* string to expect in response header */ 321 case 'e': /* string to expect in response header */
318 server_expect = optarg; 322 result.config.server_expect = optarg;
319 break; 323 break;
320 case 'u': /* server URL */ 324 case 'u': /* server URL */
321 server_url = optarg; 325 result.config.server_url = optarg;
322 break; 326 break;
323 case 'p': /* port */ 327 case 'p': /* port */
324 if (is_intpos (optarg)) { 328 if (is_intpos(optarg)) {
325 server_port = atoi (optarg); 329 result.config.server_port = atoi(optarg);
326 } 330 } else {
327 else { 331 usage4(_("Port must be a positive integer"));
328 usage4 (_("Port must be a positive integer"));
329 } 332 }
330 break; 333 break;
331 case 'w': /* warning time threshold */ 334 case 'w': /* warning time threshold */
332 if (is_intnonneg (optarg)) { 335 if (is_intnonneg(optarg)) {
333 warning_time = atoi (optarg); 336 result.config.warning_time = atoi(optarg);
334 check_warning_time = true; 337 result.config.check_warning_time = true;
335 } 338 } else {
336 else { 339 usage4(_("Warning time must be a positive integer"));
337 usage4 (_("Warning time must be a positive integer"));
338 } 340 }
339 break; 341 break;
340 case 'c': /* critical time threshold */ 342 case 'c': /* critical time threshold */
341 if (is_intnonneg (optarg)) { 343 if (is_intnonneg(optarg)) {
342 critical_time = atoi (optarg); 344 result.config.critical_time = atoi(optarg);
343 check_critical_time = true; 345 result.config.check_critical_time = true;
344 } 346 } else {
345 else { 347 usage4(_("Critical time must be a positive integer"));
346 usage4 (_("Critical time must be a positive integer"));
347 } 348 }
348 break; 349 break;
349 case 'v': /* verbose */ 350 case 'v': /* verbose */
350 verbose = true; 351 verbose = true;
351 break; 352 break;
352 case 't': /* timeout */ 353 case 't': /* timeout */
353 if (is_intnonneg (optarg)) { 354 if (is_intnonneg(optarg)) {
354 socket_timeout = atoi (optarg); 355 socket_timeout = atoi(optarg);
355 } 356 } else {
356 else { 357 usage4(_("Timeout interval must be a positive integer"));
357 usage4 (_("Timeout interval must be a positive integer"));
358 } 358 }
359 break; 359 break;
360 case 'V': /* version */ 360 case 'V': /* version */
361 print_revision (progname, NP_VERSION); 361 print_revision(progname, NP_VERSION);
362 exit (STATE_UNKNOWN); 362 exit(STATE_UNKNOWN);
363 case 'h': /* help */ 363 case 'h': /* help */
364 print_help (); 364 print_help();
365 exit (STATE_UNKNOWN); 365 exit(STATE_UNKNOWN);
366 case '?': /* usage */ 366 case '?': /* usage */
367 usage5 (); 367 usage5();
368 } 368 }
369 } 369 }
370 370
371 c = optind; 371 int option_char = optind;
372 if (server_address==NULL && argc>c) { 372 if (result.config.server_address == NULL && argc > option_char) {
373 if (is_host (argv[c])) { 373 if (is_host(argv[option_char])) {
374 server_address = argv[c++]; 374 result.config.server_address = argv[option_char++];
375 } 375 } else {
376 else { 376 usage2(_("Invalid hostname/address"), argv[option_char]);
377 usage2 (_("Invalid hostname/address"), argv[c]);
378 } 377 }
379 } 378 }
380 379
381 if (server_address==NULL) 380 if (result.config.server_address == NULL) {
382 usage4 (_("You must provide a server to check")); 381 usage4(_("You must provide a server to check"));
383 382 }
384 if (host_name==NULL)
385 host_name = strdup (server_address);
386
387 if (server_expect == NULL)
388 server_expect = strdup(EXPECT);
389
390 return validate_arguments ();
391}
392 383
384 if (result.config.host_name == NULL) {
385 result.config.host_name = strdup(result.config.server_address);
386 }
393 387
388 if (result.config.server_expect == NULL) {
389 result.config.server_expect = strdup(EXPECT);
390 }
394 391
395int 392 return result;
396validate_arguments (void)
397{
398 return OK;
399} 393}
400 394
401 395void print_help(void) {
402
403void
404print_help (void)
405{
406 char *myport; 396 char *myport;
407 xasprintf (&myport, "%d", PORT); 397 xasprintf(&myport, "%d", PORT);
408 398
409 print_revision (progname, NP_VERSION); 399 print_revision(progname, NP_VERSION);
410 400
411 printf ("Copyright (c) 1999 Pedro Leite <leite@cic.ua.pt>\n"); 401 printf("Copyright (c) 1999 Pedro Leite <leite@cic.ua.pt>\n");
412 printf (COPYRIGHT, copyright, email); 402 printf(COPYRIGHT, copyright, email);
413 403
414 printf ("%s\n", _("This plugin tests the REAL service on the specified host.")); 404 printf("%s\n", _("This plugin tests the REAL service on the specified host."));
415 405
416 printf ("\n\n"); 406 printf("\n\n");
417 407
418 print_usage (); 408 print_usage();
419 409
420 printf (UT_HELP_VRSN); 410 printf(UT_HELP_VRSN);
421 printf (UT_EXTRA_OPTS); 411 printf(UT_EXTRA_OPTS);
422 412
423 printf (UT_HOST_PORT, 'p', myport); 413 printf(UT_HOST_PORT, 'p', myport);
424 414
425 printf (" %s\n", "-u, --url=STRING"); 415 printf(" %s\n", "-u, --url=STRING");
426 printf (" %s\n", _("Connect to this url")); 416 printf(" %s\n", _("Connect to this url"));
427 printf (" %s\n", "-e, --expect=STRING"); 417 printf(" %s\n", "-e, --expect=STRING");
428 printf (_("String to expect in first line of server response (default: %s)\n"), 418 printf(_("String to expect in first line of server response (default: %s)\n"), EXPECT);
429 EXPECT);
430 419
431 printf (UT_WARN_CRIT); 420 printf(UT_WARN_CRIT);
432 421
433 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 422 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
434 423
435 printf (UT_VERBOSE); 424 printf(UT_VERBOSE);
436 425
437 printf ("\n"); 426 printf("\n");
438 printf ("%s\n", _("This plugin will attempt to open an RTSP connection with the host.")); 427 printf("%s\n", _("This plugin will attempt to open an RTSP connection with the host."));
439 printf ("%s\n", _("Successful connects return STATE_OK, refusals and timeouts return")); 428 printf("%s\n", _("Successful connects return STATE_OK, refusals and timeouts return"));
440 printf ("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful connects,")); 429 printf("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful connects,"));
441 printf ("%s\n", _("but incorrect response messages from the host result in STATE_WARNING return")); 430 printf("%s\n", _("but incorrect response messages from the host result in STATE_WARNING return"));
442 printf ("%s\n", _("values.")); 431 printf("%s\n", _("values."));
443 432
444 printf (UT_SUPPORT); 433 printf(UT_SUPPORT);
445} 434}
446 435
447 436void print_usage(void) {
448 437 printf("%s\n", _("Usage:"));
449void 438 printf("%s -H host [-e expect] [-p port] [-w warn] [-c crit] [-t timeout] [-v]\n", progname);
450print_usage (void)
451{
452 printf ("%s\n", _("Usage:"));
453 printf ("%s -H host [-e expect] [-p port] [-w warn] [-c crit] [-t timeout] [-v]\n", progname);
454} 439}
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 986c3e18..44b735f9 100644
--- a/plugins/check_smtp.c
+++ b/plugins/check_smtp.c
@@ -1,437 +1,429 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_smtp plugin 3 * Monitoring check_smtp plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2023 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_smtp plugin 10 * This file contains the check_smtp plugin
11* 11 *
12* This plugin will attempt to open an SMTP connection with the host. 12 * This plugin will attempt to open an SMTP connection with the host.
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_smtp"; 31const char *progname = "check_smtp";
32const char *copyright = "2000-2007"; 32const char *copyright = "2000-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 "netutils.h" 36#include "netutils.h"
37#include "utils.h" 37#include "utils.h"
38#include "base64.h" 38#include "base64.h"
39#include "regex.h"
39 40
40#include <ctype.h> 41#include <ctype.h>
42#include "check_smtp.d/config.h"
43#include "../lib/states.h"
44
45#define PROXY_PREFIX "PROXY TCP4 0.0.0.0 0.0.0.0 25 25\r\n"
46#define SMTP_HELO "HELO "
47#define SMTP_EHLO "EHLO "
48#define SMTP_LHLO "LHLO "
49#define SMTP_QUIT "QUIT\r\n"
50#define SMTP_STARTTLS "STARTTLS\r\n"
51#define SMTP_AUTH_LOGIN "AUTH LOGIN\r\n"
41 52
53#define EHLO_SUPPORTS_STARTTLS 1
54
55typedef struct {
56 int errorcode;
57 check_smtp_config config;
58} check_smtp_config_wrapper;
59static check_smtp_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
60
61int my_recv(check_smtp_config config, void *buf, int num, int socket_descriptor, bool ssl_established) {
42#ifdef HAVE_SSL 62#ifdef HAVE_SSL
43bool check_cert = false; 63 if ((config.use_starttls || config.use_ssl) && ssl_established) {
44int days_till_exp_warn, days_till_exp_crit; 64 return np_net_ssl_read(buf, num);
45# define my_recv(buf, len) (((use_starttls || use_ssl) && ssl_established) ? np_net_ssl_read(buf, len) : read(sd, buf, len)) 65 }
46# define my_send(buf, len) (((use_starttls || use_ssl) && ssl_established) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0)) 66 return (int)read(socket_descriptor, buf, (size_t)num);
47#else /* ifndef HAVE_SSL */ 67#else /* ifndef HAVE_SSL */
48# define my_recv(buf, len) read(sd, buf, len) 68 return read(socket_descriptor, buf, len)
49# define my_send(buf, len) send(sd, buf, len, 0)
50#endif 69#endif
70}
51 71
52enum { 72int my_send(check_smtp_config config, void *buf, int num, int socket_descriptor, bool ssl_established) {
53 SMTP_PORT = 25, 73#ifdef HAVE_SSL
54 SMTPS_PORT = 465 74 if ((config.use_starttls || config.use_ssl) && ssl_established) {
55};
56#define PROXY_PREFIX "PROXY TCP4 0.0.0.0 0.0.0.0 25 25\r\n"
57#define SMTP_EXPECT "220"
58#define SMTP_HELO "HELO "
59#define SMTP_EHLO "EHLO "
60#define SMTP_LHLO "LHLO "
61#define SMTP_QUIT "QUIT\r\n"
62#define SMTP_STARTTLS "STARTTLS\r\n"
63#define SMTP_AUTH_LOGIN "AUTH LOGIN\r\n"
64
65#define EHLO_SUPPORTS_STARTTLS 1
66 75
67int process_arguments (int, char **); 76 return np_net_ssl_write(buf, num);
68int validate_arguments (void); 77 }
69void print_help (void); 78 return (int)send(socket_descriptor, buf, (size_t)num, 0);
70void print_usage (void); 79#else /* ifndef HAVE_SSL */
71void smtp_quit(void); 80 return send(socket_descriptor, buf, len, 0);
72int recvline(char *, size_t); 81#endif
73int recvlines(char *, size_t); 82}
74int my_close(void);
75 83
76#include "regex.h" 84static void print_help(void);
77char regex_expect[MAX_INPUT_BUFFER] = ""; 85void print_usage(void);
78regex_t preg; 86static char *smtp_quit(check_smtp_config /*config*/, char /*buffer*/[MAX_INPUT_BUFFER], int /*socket_descriptor*/,
79regmatch_t pmatch[10]; 87 bool /*ssl_established*/);
80char timestamp[20] = ""; 88static int recvline(char * /*buf*/, size_t /*bufsize*/, check_smtp_config /*config*/, int /*socket_descriptor*/, bool /*ssl_established*/);
81char errbuf[MAX_INPUT_BUFFER]; 89static int recvlines(check_smtp_config /*config*/, char * /*buf*/, size_t /*bufsize*/, int /*socket_descriptor*/, bool /*ssl_established*/);
82int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 90static int my_close(int /*socket_descriptor*/);
83int eflags = 0;
84int errcode, excode;
85
86int server_port = SMTP_PORT;
87int server_port_option = 0;
88char *server_address = NULL;
89char *server_expect = NULL;
90char *mail_command = NULL;
91char *from_arg = NULL;
92int send_mail_from=0;
93int ncommands=0;
94int command_size=0;
95int nresponses=0;
96int response_size=0;
97char **commands = NULL;
98char **responses = NULL;
99char *authtype = NULL;
100char *authuser = NULL;
101char *authpass = NULL;
102double warning_time = 0;
103bool check_warning_time = false;
104double critical_time = 0;
105bool check_critical_time = false;
106int verbose = 0;
107bool use_ssl = false;
108bool use_starttls = false;
109bool use_sni = false;
110bool use_proxy_prefix = false;
111bool use_ehlo = false;
112bool use_lhlo = false;
113bool ssl_established = false;
114char *localhostname = NULL;
115int sd;
116char buffer[MAX_INPUT_BUFFER];
117enum {
118 TCP_PROTOCOL = 1,
119 UDP_PROTOCOL = 2,
120};
121bool ignore_send_quit_failure = false;
122
123
124int
125main (int argc, char **argv)
126{
127 bool supports_tls = false;
128 int n = 0;
129 double elapsed_time;
130 long microsec;
131 int result = STATE_UNKNOWN;
132 char *cmd_str = NULL;
133 char *helocmd = NULL;
134 char *error_msg = "";
135 char *server_response = NULL;
136 struct timeval tv;
137 91
138 /* Catch pipe errors in read/write - sometimes occurs when writing QUIT */ 92static int verbose = 0;
139 (void) signal (SIGPIPE, SIG_IGN);
140 93
141 setlocale (LC_ALL, ""); 94int main(int argc, char **argv) {
142 bindtextdomain (PACKAGE, LOCALEDIR); 95 setlocale(LC_ALL, "");
143 textdomain (PACKAGE); 96 bindtextdomain(PACKAGE, LOCALEDIR);
97 textdomain(PACKAGE);
144 98
145 /* Parse extra opts if any */ 99 /* Parse extra opts if any */
146 argv=np_extra_opts (&argc, argv, progname); 100 argv = np_extra_opts(&argc, argv, progname);
147 101
148 if (process_arguments (argc, argv) == ERROR) 102 check_smtp_config_wrapper tmp_config = process_arguments(argc, argv);
149 usage4 (_("Could not parse arguments")); 103
104 if (tmp_config.errorcode == ERROR) {
105 usage4(_("Could not parse arguments"));
106 }
107
108 const check_smtp_config config = tmp_config.config;
150 109
151 /* If localhostname not set on command line, use gethostname to set */ 110 /* If localhostname not set on command line, use gethostname to set */
152 if(! localhostname){ 111 char *localhostname = config.localhostname;
153 localhostname = malloc (HOST_MAX_BYTES); 112 if (!localhostname) {
154 if(!localhostname){ 113 localhostname = malloc(HOST_MAX_BYTES);
114 if (!localhostname) {
155 printf(_("malloc() failed!\n")); 115 printf(_("malloc() failed!\n"));
156 return STATE_CRITICAL; 116 exit(STATE_CRITICAL);
157 } 117 }
158 if(gethostname(localhostname, HOST_MAX_BYTES)){ 118 if (gethostname(localhostname, HOST_MAX_BYTES)) {
159 printf(_("gethostname() failed!\n")); 119 printf(_("gethostname() failed!\n"));
160 return STATE_CRITICAL; 120 exit(STATE_CRITICAL);
161 } 121 }
162 } 122 }
163 if(use_lhlo) 123
164 xasprintf (&helocmd, "%s%s%s", SMTP_LHLO, localhostname, "\r\n"); 124 char *helocmd = NULL;
165 else if(use_ehlo) 125 if (config.use_lhlo) {
166 xasprintf (&helocmd, "%s%s%s", SMTP_EHLO, localhostname, "\r\n"); 126 xasprintf(&helocmd, "%s%s%s", SMTP_LHLO, localhostname, "\r\n");
167 else 127 } else if (config.use_ehlo) {
168 xasprintf (&helocmd, "%s%s%s", SMTP_HELO, localhostname, "\r\n"); 128 xasprintf(&helocmd, "%s%s%s", SMTP_EHLO, localhostname, "\r\n");
169 129 } else {
170 if (verbose) 130 xasprintf(&helocmd, "%s%s%s", SMTP_HELO, localhostname, "\r\n");
131 }
132
133 if (verbose) {
171 printf("HELOCMD: %s", helocmd); 134 printf("HELOCMD: %s", helocmd);
135 }
172 136
137 char *mail_command = strdup("MAIL ");
138 char *cmd_str = NULL;
173 /* initialize the MAIL command with optional FROM command */ 139 /* initialize the MAIL command with optional FROM command */
174 xasprintf (&cmd_str, "%sFROM:<%s>%s", mail_command, from_arg, "\r\n"); 140 xasprintf(&cmd_str, "%sFROM:<%s>%s", mail_command, config.from_arg, "\r\n");
175 141
176 if (verbose && send_mail_from) 142 if (verbose && config.send_mail_from) {
177 printf ("FROM CMD: %s", cmd_str); 143 printf("FROM CMD: %s", cmd_str);
144 }
145
146 /* Catch pipe errors in read/write - sometimes occurs when writing QUIT */
147 (void)signal(SIGPIPE, SIG_IGN);
178 148
179 /* initialize alarm signal handling */ 149 /* initialize alarm signal handling */
180 (void) signal (SIGALRM, socket_timeout_alarm_handler); 150 (void)signal(SIGALRM, socket_timeout_alarm_handler);
181 151
182 /* set socket timeout */ 152 /* set socket timeout */
183 (void) alarm (socket_timeout); 153 (void)alarm(socket_timeout);
184 154
155 struct timeval start_time;
185 /* start timer */ 156 /* start timer */
186 gettimeofday (&tv, NULL); 157 gettimeofday(&start_time, NULL);
187 158
159 int socket_descriptor = 0;
188 /* try to connect to the host at the given port number */ 160 /* try to connect to the host at the given port number */
189 result = my_tcp_connect (server_address, server_port, &sd); 161 mp_state_enum result = my_tcp_connect(config.server_address, config.server_port, &socket_descriptor);
190 162
163 char *error_msg = "";
164 char buffer[MAX_INPUT_BUFFER];
165 bool ssl_established = false;
191 if (result == STATE_OK) { /* we connected */ 166 if (result == STATE_OK) { /* we connected */
192 /* If requested, send PROXY header */ 167 /* If requested, send PROXY header */
193 if (use_proxy_prefix) { 168 if (config.use_proxy_prefix) {
194 if (verbose) 169 if (verbose) {
195 printf ("Sending header %s\n", PROXY_PREFIX); 170 printf("Sending header %s\n", PROXY_PREFIX);
196 my_send(PROXY_PREFIX, strlen(PROXY_PREFIX)); 171 }
172 my_send(config, PROXY_PREFIX, strlen(PROXY_PREFIX), socket_descriptor, ssl_established);
197 } 173 }
198 174
199#ifdef HAVE_SSL 175#ifdef HAVE_SSL
200 if (use_ssl) { 176 if (config.use_ssl) {
201 result = np_net_ssl_init_with_hostname(sd, (use_sni ? server_address : NULL)); 177 result = np_net_ssl_init_with_hostname(socket_descriptor, (config.use_sni ? config.server_address : NULL));
202 if (result != STATE_OK) { 178 if (result != STATE_OK) {
203 printf (_("CRITICAL - Cannot create SSL context.\n")); 179 printf(_("CRITICAL - Cannot create SSL context.\n"));
204 close(sd); 180 close(socket_descriptor);
205 np_net_ssl_cleanup(); 181 np_net_ssl_cleanup();
206 return STATE_CRITICAL; 182 exit(STATE_CRITICAL);
207 } else {
208 ssl_established = 1;
209 } 183 }
184 ssl_established = true;
210 } 185 }
211#endif 186#endif
212 187
213 /* watch for the SMTP connection string and */ 188 /* watch for the SMTP connection string and */
214 /* return a WARNING status if we couldn't read any data */ 189 /* return a WARNING status if we couldn't read any data */
215 if (recvlines(buffer, MAX_INPUT_BUFFER) <= 0) { 190 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) {
216 printf (_("recv() failed\n")); 191 printf(_("recv() failed\n"));
217 return STATE_WARNING; 192 exit(STATE_WARNING);
218 } 193 }
219 194
195 char *server_response = NULL;
220 /* save connect return (220 hostname ..) for later use */ 196 /* save connect return (220 hostname ..) for later use */
221 xasprintf(&server_response, "%s", buffer); 197 xasprintf(&server_response, "%s", buffer);
222 198
223 /* send the HELO/EHLO command */ 199 /* send the HELO/EHLO command */
224 my_send(helocmd, strlen(helocmd)); 200 my_send(config, helocmd, (int)strlen(helocmd), socket_descriptor, ssl_established);
225 201
226 /* allow for response to helo command to reach us */ 202 /* allow for response to helo command to reach us */
227 if (recvlines(buffer, MAX_INPUT_BUFFER) <= 0) { 203 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) {
228 printf (_("recv() failed\n")); 204 printf(_("recv() failed\n"));
229 return STATE_WARNING; 205 exit(STATE_WARNING);
230 } else if(use_ehlo || use_lhlo){ 206 }
231 if(strstr(buffer, "250 STARTTLS") != NULL || 207
232 strstr(buffer, "250-STARTTLS") != NULL){ 208 bool supports_tls = false;
233 supports_tls=true; 209 if (config.use_ehlo || config.use_lhlo) {
210 if (strstr(buffer, "250 STARTTLS") != NULL || strstr(buffer, "250-STARTTLS") != NULL) {
211 supports_tls = true;
234 } 212 }
235 } 213 }
236 214
237 if(use_starttls && ! supports_tls){ 215 if (config.use_starttls && !supports_tls) {
238 printf(_("WARNING - TLS not supported by server\n")); 216 printf(_("WARNING - TLS not supported by server\n"));
239 smtp_quit(); 217 smtp_quit(config, buffer, socket_descriptor, ssl_established);
240 return STATE_WARNING; 218 exit(STATE_WARNING);
241 } 219 }
242 220
243#ifdef HAVE_SSL 221#ifdef HAVE_SSL
244 if(use_starttls) { 222 if (config.use_starttls) {
245 /* send the STARTTLS command */ 223 /* send the STARTTLS command */
246 send(sd, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0); 224 send(socket_descriptor, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0);
247 225
248 recvlines(buffer, MAX_INPUT_BUFFER); /* wait for it */ 226 recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established); /* wait for it */
249 if (!strstr (buffer, SMTP_EXPECT)) { 227 if (!strstr(buffer, SMTP_EXPECT)) {
250 printf (_("Server does not support STARTTLS\n")); 228 printf(_("Server does not support STARTTLS\n"));
251 smtp_quit(); 229 smtp_quit(config, buffer, socket_descriptor, ssl_established);
252 return STATE_UNKNOWN; 230 exit(STATE_UNKNOWN);
253 } 231 }
254 result = np_net_ssl_init_with_hostname(sd, (use_sni ? server_address : NULL)); 232
255 if(result != STATE_OK) { 233 result = np_net_ssl_init_with_hostname(socket_descriptor, (config.use_sni ? config.server_address : NULL));
256 printf (_("CRITICAL - Cannot create SSL context.\n")); 234 if (result != STATE_OK) {
257 close(sd); 235 printf(_("CRITICAL - Cannot create SSL context.\n"));
258 np_net_ssl_cleanup(); 236 close(socket_descriptor);
259 return STATE_CRITICAL; 237 np_net_ssl_cleanup();
260 } else { 238 exit(STATE_CRITICAL);
261 ssl_established = 1; 239 }
262 } 240
263 241 ssl_established = true;
264 /* 242
265 * Resend the EHLO command. 243 /*
266 * 244 * Resend the EHLO command.
267 * RFC 3207 (4.2) says: ``The client MUST discard any knowledge 245 *
268 * obtained from the server, such as the list of SMTP service 246 * RFC 3207 (4.2) says: ``The client MUST discard any knowledge
269 * extensions, which was not obtained from the TLS negotiation 247 * obtained from the server, such as the list of SMTP service
270 * itself. The client SHOULD send an EHLO command as the first 248 * extensions, which was not obtained from the TLS negotiation
271 * command after a successful TLS negotiation.'' For this 249 * itself. The client SHOULD send an EHLO command as the first
272 * reason, some MTAs will not allow an AUTH LOGIN command before 250 * command after a successful TLS negotiation.'' For this
273 * we resent EHLO via TLS. 251 * reason, some MTAs will not allow an AUTH LOGIN command before
274 */ 252 * we resent EHLO via TLS.
275 if (my_send(helocmd, strlen(helocmd)) <= 0) { 253 */
276 printf("%s\n", _("SMTP UNKNOWN - Cannot send EHLO command via TLS.")); 254 if (my_send(config, helocmd, strlen(helocmd), socket_descriptor, ssl_established) <= 0) {
277 my_close(); 255 printf("%s\n", _("SMTP UNKNOWN - Cannot send EHLO command via TLS."));
278 return STATE_UNKNOWN; 256 my_close(socket_descriptor);
279 } 257 exit(STATE_UNKNOWN);
280 if (verbose) 258 }
281 printf(_("sent %s"), helocmd); 259
282 if ((n = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) { 260 if (verbose) {
283 printf("%s\n", _("SMTP UNKNOWN - Cannot read EHLO response via TLS.")); 261 printf(_("sent %s"), helocmd);
284 my_close(); 262 }
285 return STATE_UNKNOWN;
286 }
287 if (verbose) {
288 printf("%s", buffer);
289 }
290 263
291# ifdef USE_OPENSSL 264 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) {
292 if ( check_cert ) { 265 printf("%s\n", _("SMTP UNKNOWN - Cannot read EHLO response via TLS."));
293 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit); 266 my_close(socket_descriptor);
294 smtp_quit(); 267 exit(STATE_UNKNOWN);
295 my_close(); 268 }
296 return result; 269
297 } 270 if (verbose) {
298# endif /* USE_OPENSSL */ 271 printf("%s", buffer);
272 }
273
274# ifdef USE_OPENSSL
275 if (config.check_cert) {
276 result = np_net_ssl_check_cert(config.days_till_exp_warn, config.days_till_exp_crit);
277 smtp_quit(config, buffer, socket_descriptor, ssl_established);
278 my_close(socket_descriptor);
279 exit(result);
280 }
281# endif /* USE_OPENSSL */
299 } 282 }
300#endif 283#endif
301 284
302 if (verbose) 285 if (verbose) {
303 printf ("%s", buffer); 286 printf("%s", buffer);
287 }
304 288
305 /* save buffer for later use */ 289 /* save buffer for later use */
306 xasprintf(&server_response, "%s%s", server_response, buffer); 290 xasprintf(&server_response, "%s%s", server_response, buffer);
307 /* strip the buffer of carriage returns */ 291 /* strip the buffer of carriage returns */
308 strip (server_response); 292 strip(server_response);
309 293
310 /* make sure we find the droids we are looking for */ 294 /* make sure we find the droids we are looking for */
311 if (!strstr (server_response, server_expect)) { 295 if (!strstr(server_response, config.server_expect)) {
312 if (server_port == SMTP_PORT) 296 if (config.server_port == SMTP_PORT) {
313 printf (_("Invalid SMTP response received from host: %s\n"), server_response); 297 printf(_("Invalid SMTP response received from host: %s\n"), server_response);
314 else 298 } else {
315 printf (_("Invalid SMTP response received from host on port %d: %s\n"), 299 printf(_("Invalid SMTP response received from host on port %d: %s\n"), config.server_port, server_response);
316 server_port, server_response); 300 }
317 return STATE_WARNING; 301 exit(STATE_WARNING);
318 } 302 }
319 303
320 if (send_mail_from) { 304 if (config.send_mail_from) {
321 my_send(cmd_str, strlen(cmd_str)); 305 my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established);
322 if (recvlines(buffer, MAX_INPUT_BUFFER) >= 1 && verbose) 306 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >= 1 && verbose) {
323 printf("%s", buffer); 307 printf("%s", buffer);
308 }
324 } 309 }
325 310
326 n = 0; 311 int counter = 0;
327 while (n < ncommands) { 312 while (counter < config.ncommands) {
328 xasprintf (&cmd_str, "%s%s", commands[n], "\r\n"); 313 xasprintf(&cmd_str, "%s%s", config.commands[counter], "\r\n");
329 my_send(cmd_str, strlen(cmd_str)); 314 my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established);
330 if (recvlines(buffer, MAX_INPUT_BUFFER) >= 1 && verbose) 315 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >= 1 && verbose) {
331 printf("%s", buffer); 316 printf("%s", buffer);
332 strip (buffer); 317 }
333 if (n < nresponses) { 318 strip(buffer);
334 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 319 if (counter < config.nresponses) {
335 errcode = regcomp (&preg, responses[n], cflags); 320 int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
321 regex_t preg;
322 int errcode = regcomp(&preg, config.responses[counter], cflags);
323 char errbuf[MAX_INPUT_BUFFER];
336 if (errcode != 0) { 324 if (errcode != 0) {
337 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 325 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
338 printf (_("Could Not Compile Regular Expression")); 326 printf(_("Could Not Compile Regular Expression"));
339 return ERROR; 327 exit(STATE_UNKNOWN);
340 } 328 }
341 excode = regexec (&preg, buffer, 10, pmatch, eflags); 329
330 regmatch_t pmatch[10];
331 int eflags = 0;
332 int excode = regexec(&preg, buffer, 10, pmatch, eflags);
342 if (excode == 0) { 333 if (excode == 0) {
343 result = STATE_OK; 334 result = STATE_OK;
344 } 335 } else if (excode == REG_NOMATCH) {
345 else if (excode == REG_NOMATCH) {
346 result = STATE_WARNING; 336 result = STATE_WARNING;
347 printf (_("SMTP %s - Invalid response '%s' to command '%s'\n"), state_text (result), buffer, commands[n]); 337 printf(_("SMTP %s - Invalid response '%s' to command '%s'\n"), state_text(result), buffer, config.commands[counter]);
348 } 338 } else {
349 else { 339 regerror(excode, &preg, errbuf, MAX_INPUT_BUFFER);
350 regerror (excode, &preg, errbuf, MAX_INPUT_BUFFER); 340 printf(_("Execute Error: %s\n"), errbuf);
351 printf (_("Execute Error: %s\n"), errbuf);
352 result = STATE_UNKNOWN; 341 result = STATE_UNKNOWN;
353 } 342 }
354 } 343 }
355 n++; 344 counter++;
356 } 345 }
357 346
358 if (authtype != NULL) { 347 if (config.authtype != NULL) {
359 if (strcmp (authtype, "LOGIN") == 0) { 348 if (strcmp(config.authtype, "LOGIN") == 0) {
360 char *abuf; 349 char *abuf;
361 int ret; 350 int ret;
362 do { 351 do {
363 if (authuser == NULL) { 352 if (config.authuser == NULL) {
364 result = STATE_CRITICAL; 353 result = STATE_CRITICAL;
365 xasprintf(&error_msg, _("no authuser specified, ")); 354 xasprintf(&error_msg, _("no authuser specified, "));
366 break; 355 break;
367 } 356 }
368 if (authpass == NULL) { 357 if (config.authpass == NULL) {
369 result = STATE_CRITICAL; 358 result = STATE_CRITICAL;
370 xasprintf(&error_msg, _("no authpass specified, ")); 359 xasprintf(&error_msg, _("no authpass specified, "));
371 break; 360 break;
372 } 361 }
373 362
374 /* send AUTH LOGIN */ 363 /* send AUTH LOGIN */
375 my_send(SMTP_AUTH_LOGIN, strlen(SMTP_AUTH_LOGIN)); 364 my_send(config, SMTP_AUTH_LOGIN, strlen(SMTP_AUTH_LOGIN), socket_descriptor, ssl_established);
376 if (verbose) 365 if (verbose) {
377 printf (_("sent %s\n"), "AUTH LOGIN"); 366 printf(_("sent %s\n"), "AUTH LOGIN");
367 }
378 368
379 if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) { 369 if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established)) <= 0) {
380 xasprintf(&error_msg, _("recv() failed after AUTH LOGIN, ")); 370 xasprintf(&error_msg, _("recv() failed after AUTH LOGIN, "));
381 result = STATE_WARNING; 371 result = STATE_WARNING;
382 break; 372 break;
383 } 373 }
384 if (verbose) 374 if (verbose) {
385 printf (_("received %s\n"), buffer); 375 printf(_("received %s\n"), buffer);
376 }
386 377
387 if (strncmp (buffer, "334", 3) != 0) { 378 if (strncmp(buffer, "334", 3) != 0) {
388 result = STATE_CRITICAL; 379 result = STATE_CRITICAL;
389 xasprintf(&error_msg, _("invalid response received after AUTH LOGIN, ")); 380 xasprintf(&error_msg, _("invalid response received after AUTH LOGIN, "));
390 break; 381 break;
391 } 382 }
392 383
393 /* encode authuser with base64 */ 384 /* encode authuser with base64 */
394 base64_encode_alloc (authuser, strlen(authuser), &abuf); 385 base64_encode_alloc(config.authuser, strlen(config.authuser), &abuf);
395 xasprintf(&abuf, "%s\r\n", abuf); 386 xasprintf(&abuf, "%s\r\n", abuf);
396 my_send(abuf, strlen(abuf)); 387 my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established);
397 if (verbose) 388 if (verbose) {
398 printf (_("sent %s\n"), abuf); 389 printf(_("sent %s\n"), abuf);
390 }
399 391
400 if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) { 392 if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established)) <= 0) {
401 result = STATE_CRITICAL; 393 result = STATE_CRITICAL;
402 xasprintf(&error_msg, _("recv() failed after sending authuser, ")); 394 xasprintf(&error_msg, _("recv() failed after sending authuser, "));
403 break; 395 break;
404 } 396 }
405 if (verbose) { 397 if (verbose) {
406 printf (_("received %s\n"), buffer); 398 printf(_("received %s\n"), buffer);
407 } 399 }
408 if (strncmp (buffer, "334", 3) != 0) { 400 if (strncmp(buffer, "334", 3) != 0) {
409 result = STATE_CRITICAL; 401 result = STATE_CRITICAL;
410 xasprintf(&error_msg, _("invalid response received after authuser, ")); 402 xasprintf(&error_msg, _("invalid response received after authuser, "));
411 break; 403 break;
412 } 404 }
413 /* encode authpass with base64 */ 405 /* encode authpass with base64 */
414 base64_encode_alloc (authpass, strlen(authpass), &abuf); 406 base64_encode_alloc(config.authpass, strlen(config.authpass), &abuf);
415 xasprintf(&abuf, "%s\r\n", abuf); 407 xasprintf(&abuf, "%s\r\n", abuf);
416 my_send(abuf, strlen(abuf)); 408 my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established);
417 if (verbose) { 409 if (verbose) {
418 printf (_("sent %s\n"), abuf); 410 printf(_("sent %s\n"), abuf);
419 } 411 }
420 if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) { 412 if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established)) <= 0) {
421 result = STATE_CRITICAL; 413 result = STATE_CRITICAL;
422 xasprintf(&error_msg, _("recv() failed after sending authpass, ")); 414 xasprintf(&error_msg, _("recv() failed after sending authpass, "));
423 break; 415 break;
424 } 416 }
425 if (verbose) { 417 if (verbose) {
426 printf (_("received %s\n"), buffer); 418 printf(_("received %s\n"), buffer);
427 } 419 }
428 if (strncmp (buffer, "235", 3) != 0) { 420 if (strncmp(buffer, "235", 3) != 0) {
429 result = STATE_CRITICAL; 421 result = STATE_CRITICAL;
430 xasprintf(&error_msg, _("invalid response received after authpass, ")); 422 xasprintf(&error_msg, _("invalid response received after authpass, "));
431 break; 423 break;
432 } 424 }
433 break; 425 break;
434 } while (0); 426 } while (false);
435 } else { 427 } else {
436 result = STATE_CRITICAL; 428 result = STATE_CRITICAL;
437 xasprintf(&error_msg, _("only authtype LOGIN is supported, ")); 429 xasprintf(&error_msg, _("only authtype LOGIN is supported, "));
@@ -439,243 +431,243 @@ main (int argc, char **argv)
439 } 431 }
440 432
441 /* tell the server we're done */ 433 /* tell the server we're done */
442 smtp_quit(); 434 smtp_quit(config, buffer, socket_descriptor, ssl_established);
443 435
444 /* finally close the connection */ 436 /* finally close the connection */
445 close (sd); 437 close(socket_descriptor);
446 } 438 }
447 439
448 /* reset the alarm */ 440 /* reset the alarm */
449 alarm (0); 441 alarm(0);
450 442
451 microsec = deltime (tv); 443 long microsec = deltime(start_time);
452 elapsed_time = (double)microsec / 1.0e6; 444 double elapsed_time = (double)microsec / 1.0e6;
453 445
454 if (result == STATE_OK) { 446 if (result == STATE_OK) {
455 if (check_critical_time && elapsed_time > critical_time) 447 if (config.check_critical_time && elapsed_time > config.critical_time) {
456 result = STATE_CRITICAL; 448 result = STATE_CRITICAL;
457 else if (check_warning_time && elapsed_time > warning_time) 449 } else if (config.check_warning_time && elapsed_time > config.warning_time) {
458 result = STATE_WARNING; 450 result = STATE_WARNING;
451 }
459 } 452 }
460 453
461 printf (_("SMTP %s - %s%.3f sec. response time%s%s|%s\n"), 454 printf(_("SMTP %s - %s%.3f sec. response time%s%s|%s\n"), state_text(result), error_msg, elapsed_time, verbose ? ", " : "",
462 state_text (result), 455 verbose ? buffer : "",
463 error_msg, 456 fperfdata("time", elapsed_time, "s", config.check_warning_time, config.warning_time, config.check_critical_time,
464 elapsed_time, 457 config.critical_time, true, 0, false, 0));
465 verbose?", ":"", verbose?buffer:"",
466 fperfdata ("time", elapsed_time, "s",
467 (int)check_warning_time, warning_time,
468 (int)check_critical_time, critical_time,
469 true, 0, false, 0));
470 458
471 return result; 459 exit(result);
472} 460}
473 461
474
475
476/* process command-line arguments */ 462/* process command-line arguments */
477int 463check_smtp_config_wrapper process_arguments(int argc, char **argv) {
478process_arguments (int argc, char **argv)
479{
480 int c;
481 char* temp;
482
483 bool implicit_tls = false;
484
485 enum { 464 enum {
486 SNI_OPTION 465 SNI_OPTION = CHAR_MAX + 1
487 }; 466 };
488 467
489 int option = 0; 468 int option = 0;
490 static struct option longopts[] = { 469 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
491 {"hostname", required_argument, 0, 'H'}, 470 {"expect", required_argument, 0, 'e'},
492 {"expect", required_argument, 0, 'e'}, 471 {"critical", required_argument, 0, 'c'},
493 {"critical", required_argument, 0, 'c'}, 472 {"warning", required_argument, 0, 'w'},
494 {"warning", required_argument, 0, 'w'}, 473 {"timeout", required_argument, 0, 't'},
495 {"timeout", required_argument, 0, 't'}, 474 {"port", required_argument, 0, 'p'},
496 {"port", required_argument, 0, 'p'}, 475 {"from", required_argument, 0, 'f'},
497 {"from", required_argument, 0, 'f'}, 476 {"fqdn", required_argument, 0, 'F'},
498 {"fqdn", required_argument, 0, 'F'}, 477 {"authtype", required_argument, 0, 'A'},
499 {"authtype", required_argument, 0, 'A'}, 478 {"authuser", required_argument, 0, 'U'},
500 {"authuser", required_argument, 0, 'U'}, 479 {"authpass", required_argument, 0, 'P'},
501 {"authpass", required_argument, 0, 'P'}, 480 {"command", required_argument, 0, 'C'},
502 {"command", required_argument, 0, 'C'}, 481 {"response", required_argument, 0, 'R'},
503 {"response", required_argument, 0, 'R'}, 482 {"verbose", no_argument, 0, 'v'},
504 {"verbose", no_argument, 0, 'v'}, 483 {"version", no_argument, 0, 'V'},
505 {"version", no_argument, 0, 'V'}, 484 {"use-ipv4", no_argument, 0, '4'},
506 {"use-ipv4", no_argument, 0, '4'}, 485 {"use-ipv6", no_argument, 0, '6'},
507 {"use-ipv6", no_argument, 0, '6'}, 486 {"help", no_argument, 0, 'h'},
508 {"help", no_argument, 0, 'h'}, 487 {"lmtp", no_argument, 0, 'L'},
509 {"lmtp", no_argument, 0, 'L'}, 488 {"ssl", no_argument, 0, 's'},
510 {"ssl", no_argument, 0, 's'}, 489 {"tls", no_argument, 0, 's'},
511 {"tls", no_argument, 0, 's'}, 490 {"starttls", no_argument, 0, 'S'},
512 {"starttls",no_argument,0,'S'}, 491 {"sni", no_argument, 0, SNI_OPTION},
513 {"sni", no_argument, 0, SNI_OPTION}, 492 {"certificate", required_argument, 0, 'D'},
514 {"certificate",required_argument,0,'D'}, 493 {"ignore-quit-failure", no_argument, 0, 'q'},
515 {"ignore-quit-failure",no_argument,0,'q'}, 494 {"proxy", no_argument, 0, 'r'},
516 {"proxy",no_argument,0,'r'}, 495 {0, 0, 0, 0}};
517 {0, 0, 0, 0} 496
497 check_smtp_config_wrapper result = {
498 .config = check_smtp_config_init(),
499 .errorcode = OK,
518 }; 500 };
519 501
520 if (argc < 2) 502 if (argc < 2) {
521 return ERROR; 503 result.errorcode = ERROR;
504 return result;
505 }
522 506
523 for (c = 1; c < argc; c++) { 507 for (int index = 1; index < argc; index++) {
524 if (strcmp ("-to", argv[c]) == 0) 508 if (strcmp("-to", argv[index]) == 0) {
525 strcpy (argv[c], "-t"); 509 strcpy(argv[index], "-t");
526 else if (strcmp ("-wt", argv[c]) == 0) 510 } else if (strcmp("-wt", argv[index]) == 0) {
527 strcpy (argv[c], "-w"); 511 strcpy(argv[index], "-w");
528 else if (strcmp ("-ct", argv[c]) == 0) 512 } else if (strcmp("-ct", argv[index]) == 0) {
529 strcpy (argv[c], "-c"); 513 strcpy(argv[index], "-c");
514 }
530 } 515 }
531 516
532 while (1) { 517 int command_size = 0;
533 c = getopt_long (argc, argv, "+hVv46Lrt:p:f:e:c:w:H:C:R:sSD:F:A:U:P:q", 518 int response_size = 0;
534 longopts, &option); 519 bool implicit_tls = false;
520 int server_port_option = 0;
521 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);
535 523
536 if (c == -1 || c == EOF) 524 if (opt_index == -1 || opt_index == EOF) {
537 break; 525 break;
526 }
538 527
539 switch (c) { 528 switch (opt_index) {
540 case 'H': /* hostname */ 529 case 'H': /* hostname */
541 if (is_host (optarg)) { 530 if (is_host(optarg)) {
542 server_address = optarg; 531 result.config.server_address = optarg;
543 } 532 } else {
544 else { 533 usage2(_("Invalid hostname/address"), optarg);
545 usage2 (_("Invalid hostname/address"), optarg);
546 } 534 }
547 break; 535 break;
548 case 'p': /* port */ 536 case 'p': /* port */
549 if (is_intpos (optarg)) 537 if (is_intpos(optarg)) {
550 server_port_option = atoi (optarg); 538 server_port_option = atoi(optarg);
551 else 539 } else {
552 usage4 (_("Port must be a positive integer")); 540 usage4(_("Port must be a positive integer"));
541 }
553 break; 542 break;
554 case 'F': 543 case 'F':
555 /* localhostname */ 544 /* localhostname */
556 localhostname = strdup(optarg); 545 result.config.localhostname = strdup(optarg);
557 break; 546 break;
558 case 'f': /* from argument */ 547 case 'f': /* from argument */
559 from_arg = optarg + strspn(optarg, "<"); 548 result.config.from_arg = optarg + strspn(optarg, "<");
560 from_arg = strndup(from_arg, strcspn(from_arg, ">")); 549 result.config.from_arg = strndup(result.config.from_arg, strcspn(result.config.from_arg, ">"));
561 send_mail_from = 1; 550 result.config.send_mail_from = true;
562 break; 551 break;
563 case 'A': 552 case 'A':
564 authtype = optarg; 553 result.config.authtype = optarg;
565 use_ehlo = true; 554 result.config.use_ehlo = true;
566 break; 555 break;
567 case 'U': 556 case 'U':
568 authuser = optarg; 557 result.config.authuser = optarg;
569 break; 558 break;
570 case 'P': 559 case 'P':
571 authpass = optarg; 560 result.config.authpass = optarg;
572 break; 561 break;
573 case 'e': /* server expect string on 220 */ 562 case 'e': /* server expect string on 220 */
574 server_expect = optarg; 563 result.config.server_expect = optarg;
575 break; 564 break;
576 case 'C': /* commands */ 565 case 'C': /* commands */
577 if (ncommands >= command_size) { 566 if (result.config.ncommands >= command_size) {
578 command_size+=8; 567 command_size += 8;
579 commands = realloc (commands, sizeof(char *) * command_size); 568 result.config.commands = realloc(result.config.commands, sizeof(char *) * command_size);
580 if (commands == NULL) 569 if (result.config.commands == NULL) {
581 die (STATE_UNKNOWN, 570 die(STATE_UNKNOWN, _("Could not realloc() units [%d]\n"), result.config.ncommands);
582 _("Could not realloc() units [%d]\n"), ncommands); 571 }
583 } 572 }
584 commands[ncommands] = (char *) malloc (sizeof(char) * 255); 573 result.config.commands[result.config.ncommands] = (char *)malloc(sizeof(char) * 255);
585 strncpy (commands[ncommands], optarg, 255); 574 strncpy(result.config.commands[result.config.ncommands], optarg, 255);
586 ncommands++; 575 result.config.ncommands++;
587 break; 576 break;
588 case 'R': /* server responses */ 577 case 'R': /* server responses */
589 if (nresponses >= response_size) { 578 if (result.config.nresponses >= response_size) {
590 response_size += 8; 579 response_size += 8;
591 responses = realloc (responses, sizeof(char *) * response_size); 580 result.config.responses = realloc(result.config.responses, sizeof(char *) * response_size);
592 if (responses == NULL) 581 if (result.config.responses == NULL) {
593 die (STATE_UNKNOWN, 582 die(STATE_UNKNOWN, _("Could not realloc() units [%d]\n"), result.config.nresponses);
594 _("Could not realloc() units [%d]\n"), nresponses); 583 }
595 } 584 }
596 responses[nresponses] = (char *) malloc (sizeof(char) * 255); 585 result.config.responses[result.config.nresponses] = (char *)malloc(sizeof(char) * 255);
597 strncpy (responses[nresponses], optarg, 255); 586 strncpy(result.config.responses[result.config.nresponses], optarg, 255);
598 nresponses++; 587 result.config.nresponses++;
599 break; 588 break;
600 case 'c': /* critical time threshold */ 589 case 'c': /* critical time threshold */
601 if (!is_nonnegative (optarg)) 590 if (!is_nonnegative(optarg)) {
602 usage4 (_("Critical time must be a positive")); 591 usage4(_("Critical time must be a positive"));
603 else { 592 } else {
604 critical_time = strtod (optarg, NULL); 593 result.config.critical_time = strtod(optarg, NULL);
605 check_critical_time = true; 594 result.config.check_critical_time = true;
606 } 595 }
607 break; 596 break;
608 case 'w': /* warning time threshold */ 597 case 'w': /* warning time threshold */
609 if (!is_nonnegative (optarg)) 598 if (!is_nonnegative(optarg)) {
610 usage4 (_("Warning time must be a positive")); 599 usage4(_("Warning time must be a positive"));
611 else { 600 } else {
612 warning_time = strtod (optarg, NULL); 601 result.config.warning_time = strtod(optarg, NULL);
613 check_warning_time = true; 602 result.config.check_warning_time = true;
614 } 603 }
615 break; 604 break;
616 case 'v': /* verbose */ 605 case 'v': /* verbose */
617 verbose++; 606 verbose++;
618 break; 607 break;
619 case 'q': 608 case 'q':
620 ignore_send_quit_failure = true; /* ignore problem sending QUIT */ 609 result.config.ignore_send_quit_failure = true; /* ignore problem sending QUIT */
621 break; 610 break;
622 case 't': /* timeout */ 611 case 't': /* timeout */
623 if (is_intnonneg (optarg)) { 612 if (is_intnonneg(optarg)) {
624 socket_timeout = atoi (optarg); 613 socket_timeout = atoi(optarg);
625 } 614 } else {
626 else { 615 usage4(_("Timeout interval must be a positive integer"));
627 usage4 (_("Timeout interval must be a positive integer"));
628 } 616 }
629 break; 617 break;
630 case 'D': 618 case 'D': {
631 /* Check SSL cert validity */ 619 /* Check SSL cert validity */
632#ifdef USE_OPENSSL 620#ifdef USE_OPENSSL
633 if ((temp=strchr(optarg,','))!=NULL) { 621 char *temp;
634 *temp='\0'; 622 if ((temp = strchr(optarg, ',')) != NULL) {
635 if (!is_intnonneg (optarg)) 623 *temp = '\0';
636 usage2 ("Invalid certificate expiration period", optarg); 624 if (!is_intnonneg(optarg)) {
637 days_till_exp_warn = atoi(optarg); 625 usage2("Invalid certificate expiration period", optarg);
638 *temp=','; 626 }
639 temp++; 627 result.config.days_till_exp_warn = atoi(optarg);
640 if (!is_intnonneg (temp)) 628 *temp = ',';
641 usage2 (_("Invalid certificate expiration period"), temp); 629 temp++;
642 days_till_exp_crit = atoi (temp); 630 if (!is_intnonneg(temp)) {
643 } 631 usage2(_("Invalid certificate expiration period"), temp);
644 else { 632 }
645 days_till_exp_crit=0; 633 result.config.days_till_exp_crit = atoi(temp);
646 if (!is_intnonneg (optarg)) 634 } else {
647 usage2 ("Invalid certificate expiration period", optarg); 635 result.config.days_till_exp_crit = 0;
648 days_till_exp_warn = atoi (optarg); 636 if (!is_intnonneg(optarg)) {
649 } 637 usage2("Invalid certificate expiration period", optarg);
650 check_cert = true; 638 }
651 ignore_send_quit_failure = true; 639 result.config.days_till_exp_warn = atoi(optarg);
640 }
641 result.config.check_cert = true;
642 result.config.ignore_send_quit_failure = true;
652#else 643#else
653 usage (_("SSL support not available - install OpenSSL and recompile")); 644 usage(_("SSL support not available - install OpenSSL and recompile"));
654#endif 645#endif
655 implicit_tls = true; 646 implicit_tls = true;
656 // fallthrough 647 // fallthrough
657 case 's': 648 case 's':
658 /* ssl */ 649 /* ssl */
659 use_ssl = true; 650 result.config.use_ssl = true;
660 server_port = SMTPS_PORT; 651 result.config.server_port = SMTPS_PORT;
661 break; 652 break;
662 case 'S': 653 case 'S':
663 /* starttls */ 654 /* starttls */
664 use_starttls = true; 655 result.config.use_starttls = true;
665 use_ehlo = true; 656 result.config.use_ehlo = true;
666 break; 657 break;
658 }
667 case SNI_OPTION: 659 case SNI_OPTION:
668#ifdef HAVE_SSL 660#ifdef HAVE_SSL
669 use_sni = true; 661 result.config.use_sni = true;
670#else 662#else
671 usage (_("SSL support not available - install OpenSSL and recompile")); 663 usage(_("SSL support not available - install OpenSSL and recompile"));
672#endif 664#endif
673 break; 665 break;
674 case 'r': 666 case 'r':
675 use_proxy_prefix = true; 667 result.config.use_proxy_prefix = true;
676 break; 668 break;
677 case 'L': 669 case 'L':
678 use_lhlo = true; 670 result.config.use_lhlo = true;
679 break; 671 break;
680 case '4': 672 case '4':
681 address_family = AF_INET; 673 address_family = AF_INET;
@@ -684,102 +676,79 @@ process_arguments (int argc, char **argv)
684#ifdef USE_IPV6 676#ifdef USE_IPV6
685 address_family = AF_INET6; 677 address_family = AF_INET6;
686#else 678#else
687 usage4 (_("IPv6 support not available")); 679 usage4(_("IPv6 support not available"));
688#endif 680#endif
689 break; 681 break;
690 case 'V': /* version */ 682 case 'V': /* version */
691 print_revision (progname, NP_VERSION); 683 print_revision(progname, NP_VERSION);
692 exit (STATE_UNKNOWN); 684 exit(STATE_UNKNOWN);
693 case 'h': /* help */ 685 case 'h': /* help */
694 print_help (); 686 print_help();
695 exit (STATE_UNKNOWN); 687 exit(STATE_UNKNOWN);
696 case '?': /* help */ 688 case '?': /* help */
697 usage5 (); 689 usage5();
698 } 690 }
699 } 691 }
700 692
701 c = optind; 693 int c = optind;
702 if (server_address == NULL) { 694 if (result.config.server_address == NULL) {
703 if (argv[c]) { 695 if (argv[c]) {
704 if (is_host (argv[c])) 696 if (is_host(argv[c])) {
705 server_address = argv[c]; 697 result.config.server_address = argv[c];
706 else 698 } else {
707 usage2 (_("Invalid hostname/address"), argv[c]); 699 usage2(_("Invalid hostname/address"), argv[c]);
708 } 700 }
709 else { 701 } else {
710 xasprintf (&server_address, "127.0.0.1"); 702 result.config.server_address = strdup("localhost");
711 } 703 }
712 } 704 }
713 705
714 if (server_expect == NULL) 706 if (result.config.use_starttls && result.config.use_ssl) {
715 server_expect = strdup (SMTP_EXPECT);
716
717 if (mail_command == NULL)
718 mail_command = strdup("MAIL ");
719
720 if (from_arg==NULL)
721 from_arg = strdup(" ");
722
723 if (use_starttls && use_ssl) {
724 if (implicit_tls) { 707 if (implicit_tls) {
725 use_ssl = false; 708 result.config.use_ssl = false;
726 server_port = SMTP_PORT;
727 } else { 709 } else {
728 usage4 (_("Set either -s/--ssl/--tls or -S/--starttls")); 710 usage4(_("Set either -s/--ssl/--tls or -S/--starttls"));
729 } 711 }
730 } 712 }
731 713
732 if (server_port_option != 0) { 714 if (server_port_option != 0) {
733 server_port = server_port_option; 715 result.config.server_port = server_port_option;
734 } 716 }
735 717
736 return validate_arguments (); 718 return result;
737}
738
739
740
741int
742validate_arguments (void)
743{
744 return OK;
745} 719}
746 720
747 721char *smtp_quit(check_smtp_config config, char buffer[MAX_INPUT_BUFFER], int socket_descriptor, bool ssl_established) {
748void 722 int sent_bytes = my_send(config, SMTP_QUIT, strlen(SMTP_QUIT), socket_descriptor, ssl_established);
749smtp_quit(void) 723 if (sent_bytes < 0) {
750{ 724 if (config.ignore_send_quit_failure) {
751 int bytes; 725 if (verbose) {
752 int n;
753
754 n = my_send(SMTP_QUIT, strlen(SMTP_QUIT));
755 if(n < 0) {
756 if(ignore_send_quit_failure) {
757 if(verbose) {
758 printf(_("Connection closed by server before sending QUIT command\n")); 726 printf(_("Connection closed by server before sending QUIT command\n"));
759 } 727 }
760 return; 728 return buffer;
761 } 729 }
762 die (STATE_UNKNOWN, 730 die(STATE_UNKNOWN, _("Connection closed by server before sending QUIT command\n"));
763 _("Connection closed by server before sending QUIT command\n"));
764 } 731 }
765 732
766 if (verbose) 733 if (verbose) {
767 printf(_("sent %s\n"), "QUIT"); 734 printf(_("sent %s\n"), "QUIT");
735 }
768 736
769 /* read the response but don't care about problems */ 737 /* read the response but don't care about problems */
770 bytes = recvlines(buffer, MAX_INPUT_BUFFER); 738 int bytes = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established);
771 if (verbose) { 739 if (verbose) {
772 if (bytes < 0) 740 if (bytes < 0) {
773 printf(_("recv() failed after QUIT.")); 741 printf(_("recv() failed after QUIT."));
774 else if (bytes == 0) 742 } else if (bytes == 0) {
775 printf(_("Connection reset by peer.")); 743 printf(_("Connection reset by peer."));
776 else { 744 } else {
777 buffer[bytes] = '\0'; 745 buffer[bytes] = '\0';
778 printf(_("received %s\n"), buffer); 746 printf(_("received %s\n"), buffer);
779 } 747 }
780 } 748 }
781}
782 749
750 return buffer;
751}
783 752
784/* 753/*
785 * Receive one line, copy it into buf and nul-terminate it. Returns the 754 * Receive one line, copy it into buf and nul-terminate it. Returns the
@@ -790,24 +759,22 @@ smtp_quit(void)
790 * function which buffers the data, move that to netutils.c and change 759 * function which buffers the data, move that to netutils.c and change
791 * check_smtp and other plugins to use that. Also, remove (\r)\n. 760 * check_smtp and other plugins to use that. Also, remove (\r)\n.
792 */ 761 */
793int 762int recvline(char *buf, size_t bufsize, check_smtp_config config, int socket_descriptor, bool ssl_established) {
794recvline(char *buf, size_t bufsize)
795{
796 int result; 763 int result;
797 unsigned i; 764 int counter;
798 765
799 for (i = result = 0; i < bufsize - 1; i++) { 766 for (counter = result = 0; counter < bufsize - 1; counter++) {
800 if ((result = my_recv(&buf[i], 1)) != 1) 767 if ((result = my_recv(config, &buf[counter], 1, socket_descriptor, ssl_established)) != 1) {
801 break; 768 break;
802 if (buf[i] == '\n') { 769 }
803 buf[++i] = '\0'; 770 if (buf[counter] == '\n') {
804 return i; 771 buf[++counter] = '\0';
772 return counter;
805 } 773 }
806 } 774 }
807 return (result == 1 || i == 0) ? -2 : result; /* -2 if out of space */ 775 return (result == 1 || counter == 0) ? -2 : result; /* -2 if out of space */
808} 776}
809 777
810
811/* 778/*
812 * Receive one or more lines, copy them into buf and nul-terminate it. Returns 779 * Receive one or more lines, copy them into buf and nul-terminate it. Returns
813 * the number of bytes written to buf (excluding the '\0') or 0 on EOF or <0 on 780 * the number of bytes written to buf (excluding the '\0') or 0 on EOF or <0 on
@@ -822,117 +789,103 @@ recvline(char *buf, size_t bufsize)
822 * 789 *
823 * TODO: Move this to netutils.c. Also, remove \r and possibly the final \n. 790 * TODO: Move this to netutils.c. Also, remove \r and possibly the final \n.
824 */ 791 */
825int 792int recvlines(check_smtp_config config, char *buf, size_t bufsize, int socket_descriptor, bool ssl_established) {
826recvlines(char *buf, size_t bufsize) 793 int result;
827{ 794 int counter;
828 int result, i; 795
829 796 for (counter = 0; /* forever */; counter += result) {
830 for (i = 0; /* forever */; i += result) 797 if (!((result = recvline(buf + counter, bufsize - counter, config, socket_descriptor, ssl_established)) > 3 &&
831 if (!((result = recvline(buf + i, bufsize - i)) > 3 && 798 isdigit((int)buf[counter]) && isdigit((int)buf[counter + 1]) && isdigit((int)buf[counter + 2]) && buf[counter + 3] == '-')) {
832 isdigit((int)buf[i]) &&
833 isdigit((int)buf[i + 1]) &&
834 isdigit((int)buf[i + 2]) &&
835 buf[i + 3] == '-'))
836 break; 799 break;
800 }
801 }
837 802
838 return (result <= 0) ? result : result + i; 803 return (result <= 0) ? result : result + counter;
839} 804}
840 805
841 806int my_close(int socket_descriptor) {
842int
843my_close (void)
844{
845 int result; 807 int result;
846 result = close(sd); 808 result = close(socket_descriptor);
847#ifdef HAVE_SSL 809#ifdef HAVE_SSL
848 np_net_ssl_cleanup(); 810 np_net_ssl_cleanup();
849#endif 811#endif
850 return result; 812 return result;
851} 813}
852 814
853 815void print_help(void) {
854void
855print_help (void)
856{
857 char *myport; 816 char *myport;
858 xasprintf (&myport, "%d", SMTP_PORT); 817 xasprintf(&myport, "%d", SMTP_PORT);
859 818
860 print_revision (progname, NP_VERSION); 819 print_revision(progname, NP_VERSION);
861 820
862 printf ("Copyright (c) 1999-2001 Ethan Galstad <nagios@nagios.org>\n"); 821 printf("Copyright (c) 1999-2001 Ethan Galstad <nagios@nagios.org>\n");
863 printf (COPYRIGHT, copyright, email); 822 printf(COPYRIGHT, copyright, email);
864 823
865 printf("%s\n", _("This plugin will attempt to open an SMTP connection with the host.")); 824 printf("%s\n", _("This plugin will attempt to open an SMTP connection with the host."));
866 825
867 printf ("\n\n"); 826 printf("\n\n");
868 827
869 print_usage (); 828 print_usage();
870 829
871 printf (UT_HELP_VRSN); 830 printf(UT_HELP_VRSN);
872 printf (UT_EXTRA_OPTS); 831 printf(UT_EXTRA_OPTS);
873 832
874 printf (UT_HOST_PORT, 'p', myport); 833 printf(UT_HOST_PORT, 'p', myport);
875 834
876 printf (UT_IPv46); 835 printf(UT_IPv46);
877 836
878 printf (" %s\n", "-e, --expect=STRING"); 837 printf(" %s\n", "-e, --expect=STRING");
879 printf (_(" String to expect in first line of server response (default: '%s')\n"), SMTP_EXPECT); 838 printf(_(" String to expect in first line of server response (default: '%s')\n"), SMTP_EXPECT);
880 printf (" %s\n", "-C, --command=STRING"); 839 printf(" %s\n", "-C, --command=STRING");
881 printf (" %s\n", _("SMTP command (may be used repeatedly)")); 840 printf(" %s\n", _("SMTP command (may be used repeatedly)"));
882 printf (" %s\n", "-R, --response=STRING"); 841 printf(" %s\n", "-R, --response=STRING");
883 printf (" %s\n", _("Expected response to command (may be used repeatedly)")); 842 printf(" %s\n", _("Expected response to command (may be used repeatedly)"));
884 printf (" %s\n", "-f, --from=STRING"); 843 printf(" %s\n", "-f, --from=STRING");
885 printf (" %s\n", _("FROM-address to include in MAIL command, required by Exchange 2000")), 844 printf(" %s\n", _("FROM-address to include in MAIL command, required by Exchange 2000")), printf(" %s\n", "-F, --fqdn=STRING");
886 printf (" %s\n", "-F, --fqdn=STRING"); 845 printf(" %s\n", _("FQDN used for HELO"));
887 printf (" %s\n", _("FQDN used for HELO")); 846 printf(" %s\n", "-r, --proxy");
888 printf (" %s\n", "-r, --proxy"); 847 printf(" %s\n", _("Use PROXY protocol prefix for the connection."));
889 printf (" %s\n", _("Use PROXY protocol prefix for the connection."));
890#ifdef HAVE_SSL 848#ifdef HAVE_SSL
891 printf (" %s\n", "-D, --certificate=INTEGER[,INTEGER]"); 849 printf(" %s\n", "-D, --certificate=INTEGER[,INTEGER]");
892 printf (" %s\n", _("Minimum number of days a certificate has to be valid.")); 850 printf(" %s\n", _("Minimum number of days a certificate has to be valid."));
893 printf (" %s\n", "-s, --ssl, --tls"); 851 printf(" %s\n", "-s, --ssl, --tls");
894 printf (" %s\n", _("Use SSL/TLS for the connection.")); 852 printf(" %s\n", _("Use SSL/TLS for the connection."));
895 printf (_(" Sets default port to %d.\n"), SMTPS_PORT); 853 printf(_(" Sets default port to %d.\n"), SMTPS_PORT);
896 printf (" %s\n", "-S, --starttls"); 854 printf(" %s\n", "-S, --starttls");
897 printf (" %s\n", _("Use STARTTLS for the connection.")); 855 printf(" %s\n", _("Use STARTTLS for the connection."));
898 printf (" %s\n", "--sni"); 856 printf(" %s\n", "--sni");
899 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)")); 857 printf(" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
900#endif 858#endif
901 859
902 printf (" %s\n", "-A, --authtype=STRING"); 860 printf(" %s\n", "-A, --authtype=STRING");
903 printf (" %s\n", _("SMTP AUTH type to check (default none, only LOGIN supported)")); 861 printf(" %s\n", _("SMTP AUTH type to check (default none, only LOGIN supported)"));
904 printf (" %s\n", "-U, --authuser=STRING"); 862 printf(" %s\n", "-U, --authuser=STRING");
905 printf (" %s\n", _("SMTP AUTH username")); 863 printf(" %s\n", _("SMTP AUTH username"));
906 printf (" %s\n", "-P, --authpass=STRING"); 864 printf(" %s\n", "-P, --authpass=STRING");
907 printf (" %s\n", _("SMTP AUTH password")); 865 printf(" %s\n", _("SMTP AUTH password"));
908 printf (" %s\n", "-L, --lmtp"); 866 printf(" %s\n", "-L, --lmtp");
909 printf (" %s\n", _("Send LHLO instead of HELO/EHLO")); 867 printf(" %s\n", _("Send LHLO instead of HELO/EHLO"));
910 printf (" %s\n", "-q, --ignore-quit-failure"); 868 printf(" %s\n", "-q, --ignore-quit-failure");
911 printf (" %s\n", _("Ignore failure when sending QUIT command to server")); 869 printf(" %s\n", _("Ignore failure when sending QUIT command to server"));
912
913 printf (UT_WARN_CRIT);
914 870
915 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 871 printf(UT_WARN_CRIT);
916 872
917 printf (UT_VERBOSE); 873 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
874
875 printf(UT_VERBOSE);
918 876
919 printf("\n"); 877 printf("\n");
920 printf ("%s\n", _("Successful connects return STATE_OK, refusals and timeouts return")); 878 printf("%s\n", _("Successful connects return STATE_OK, refusals and timeouts return"));
921 printf ("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful")); 879 printf("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful"));
922 printf ("%s\n", _("connects, but incorrect response messages from the host result in")); 880 printf("%s\n", _("connects, but incorrect response messages from the host result in"));
923 printf ("%s\n", _("STATE_WARNING return values.")); 881 printf("%s\n", _("STATE_WARNING return values."));
924 882
925 printf (UT_SUPPORT); 883 printf(UT_SUPPORT);
926} 884}
927 885
928 886void print_usage(void) {
929 887 printf("%s\n", _("Usage:"));
930void 888 printf("%s -H host [-p port] [-4|-6] [-e expect] [-C command] [-R response] [-f from addr]\n", progname);
931print_usage (void) 889 printf("[-A authtype -U authuser -P authpass] [-w warn] [-c crit] [-t timeout] [-q]\n");
932{ 890 printf("[-F fqdn] [-S] [-L] [-D warn days cert expire[,crit days cert expire]] [-r] [--sni] [-v] \n");
933 printf ("%s\n", _("Usage:"));
934 printf ("%s -H host [-p port] [-4|-6] [-e expect] [-C command] [-R response] [-f from addr]\n", progname);
935 printf ("[-A authtype -U authuser -P authpass] [-w warn] [-c crit] [-t timeout] [-q]\n");
936 printf ("[-F fqdn] [-S] [-L] [-D warn days cert expire[,crit days cert expire]] [-r] [--sni] [-v] \n");
937} 891}
938
diff --git a/plugins/check_smtp.d/config.h b/plugins/check_smtp.d/config.h
new file mode 100644
index 00000000..0a6511ef
--- /dev/null
+++ b/plugins/check_smtp.d/config.h
@@ -0,0 +1,92 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5#include <string.h>
6
7enum {
8 SMTP_PORT = 25,
9 SMTPS_PORT = 465
10};
11
12#define SMTP_EXPECT "220"
13
14typedef struct {
15 int server_port;
16 char *server_address;
17 char *localhostname;
18 char *server_expect;
19 bool ignore_send_quit_failure;
20
21 double warning_time;
22 bool check_warning_time;
23 double critical_time;
24 bool check_critical_time;
25 bool use_ehlo;
26 bool use_lhlo;
27
28 char *from_arg;
29 bool send_mail_from;
30
31 int ncommands;
32 char **commands;
33
34 int nresponses;
35 char **responses;
36
37 char *authtype;
38 char *authuser;
39 char *authpass;
40
41 bool use_proxy_prefix;
42#ifdef HAVE_SSL
43 bool check_cert;
44 int days_till_exp_warn;
45 int days_till_exp_crit;
46 bool use_ssl;
47 bool use_starttls;
48 bool use_sni;
49#endif
50} check_smtp_config;
51
52check_smtp_config check_smtp_config_init() {
53 check_smtp_config tmp = {
54 .server_port = SMTP_PORT,
55 .server_address = NULL,
56 .localhostname = NULL,
57
58 .server_expect = SMTP_EXPECT,
59 .ignore_send_quit_failure = false,
60
61 .warning_time = 0,
62 .check_warning_time = false,
63 .critical_time = 0,
64 .check_critical_time = false,
65 .use_ehlo = false,
66 .use_lhlo = false,
67
68 .from_arg = strdup(" "),
69 .send_mail_from = false,
70
71 .ncommands = 0,
72 .commands = NULL,
73
74 .nresponses = 0,
75 .responses = NULL,
76
77 .authtype = NULL,
78 .authuser = NULL,
79 .authpass = NULL,
80
81 .use_proxy_prefix = false,
82#ifdef HAVE_SSL
83 .check_cert = false,
84 .days_till_exp_warn = 0,
85 .days_till_exp_crit = 0,
86 .use_ssl = false,
87 .use_starttls = false,
88 .use_sni = false,
89#endif
90 };
91 return tmp;
92}
diff --git a/plugins/check_snmp.c b/plugins/check_snmp.c
index 90a04027..c1d8e2dd 100644
--- a/plugins/check_snmp.c
+++ b/plugins/check_snmp.c
@@ -1,35 +1,35 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_snmp plugin 3 * Monitoring check_snmp plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2007 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_snmp plugin 10 * This file contains the check_snmp plugin
11* 11 *
12* Check status of remote machines and obtain system information via SNMP 12 * Check status of remote machines and obtain system information via SNMP
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_snmp"; 31const char *progname = "check_snmp";
32const char *copyright = "1999-2007"; 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"
@@ -37,60 +37,68 @@ const char *email = "devel@monitoring-plugins.org";
37#include "utils.h" 37#include "utils.h"
38#include "utils_cmd.h" 38#include "utils_cmd.h"
39 39
40#define DEFAULT_COMMUNITY "public" 40#define DEFAULT_COMMUNITY "public"
41#define DEFAULT_PORT "161" 41#define DEFAULT_PORT "161"
42#define DEFAULT_MIBLIST "ALL" 42#define DEFAULT_MIBLIST "ALL"
43#define DEFAULT_PROTOCOL "1" 43#define DEFAULT_PROTOCOL "1"
44#define DEFAULT_RETRIES 5 44#define DEFAULT_RETRIES 5
45#define DEFAULT_AUTH_PROTOCOL "MD5" 45#define DEFAULT_AUTH_PROTOCOL "MD5"
46#define DEFAULT_PRIV_PROTOCOL "DES" 46#define DEFAULT_PRIV_PROTOCOL "DES"
47#define DEFAULT_DELIMITER "=" 47#define DEFAULT_DELIMITER "="
48#define DEFAULT_OUTPUT_DELIMITER " " 48#define DEFAULT_OUTPUT_DELIMITER " "
49#define DEFAULT_BUFFER_SIZE 100 49#define DEFAULT_BUFFER_SIZE 100
50 50
51#define mark(a) ((a)!=0?"*":"") 51#define mark(a) ((a) != 0 ? "*" : "")
52 52
53#define CHECK_UNDEF 0 53#define CHECK_UNDEF 0
54#define CRIT_PRESENT 1 54#define CRIT_PRESENT 1
55#define CRIT_STRING 2 55#define CRIT_STRING 2
56#define CRIT_REGEX 4 56#define CRIT_REGEX 4
57#define WARN_PRESENT 8 57#define WARN_PRESENT 8
58 58
59#define OID_COUNT_STEP 8 59#define OID_COUNT_STEP 8
60 60
61/* Longopts only arguments */ 61/* Longopts only arguments */
62#define L_CALCULATE_RATE CHAR_MAX+1 62#define L_CALCULATE_RATE CHAR_MAX + 1
63#define L_RATE_MULTIPLIER CHAR_MAX+2 63#define L_RATE_MULTIPLIER CHAR_MAX + 2
64#define L_INVERT_SEARCH CHAR_MAX+3 64#define L_INVERT_SEARCH CHAR_MAX + 3
65#define L_OFFSET CHAR_MAX+4 65#define L_OFFSET CHAR_MAX + 4
66#define L_IGNORE_MIB_PARSING_ERRORS CHAR_MAX+5 66#define L_IGNORE_MIB_PARSING_ERRORS CHAR_MAX + 5
67 67
68/* Gobble to string - stop incrementing c when c[0] match one of the 68/* Gobble to string - stop incrementing c when c[0] match one of the
69 * characters in s */ 69 * characters in s */
70#define GOBBLE_TOS(c, s) while(c[0]!='\0' && strchr(s, c[0])==NULL) { c++; } 70#define GOBBLE_TOS(c, s) \
71 while (c[0] != '\0' && strchr(s, c[0]) == NULL) { \
72 c++; \
73 }
71/* Given c, keep track of backslashes (bk) and double-quotes (dq) 74/* Given c, keep track of backslashes (bk) and double-quotes (dq)
72 * from c[0] */ 75 * from c[0] */
73#define COUNT_SEQ(c, bk, dq) switch(c[0]) {\ 76#define COUNT_SEQ(c, bk, dq) \
74 case '\\': \ 77 switch (c[0]) { \
75 if (bk) bk--; \ 78 case '\\': \
76 else bk++; \ 79 if (bk) \
77 break; \ 80 bk--; \
78 case '"': \ 81 else \
79 if (!dq) { dq++; } \ 82 bk++; \
80 else if(!bk) { dq--; } \ 83 break; \
81 else { bk--; } \ 84 case '"': \
82 break; \ 85 if (!dq) { \
86 dq++; \
87 } else if (!bk) { \
88 dq--; \
89 } else { \
90 bk--; \
91 } \
92 break; \
83 } 93 }
84 94
85 95static int process_arguments(int, char **);
86 96static int validate_arguments(void);
87static int process_arguments (int, char **); 97static char *thisarg(char *str);
88static int validate_arguments (void); 98static char *nextarg(char *str);
89static char *thisarg (char *str); 99void print_usage(void);
90static char *nextarg (char *str); 100static void print_help(void);
91void print_usage (void); 101static char *multiply(char *str);
92static void print_help (void);
93static char *multiply (char *str);
94 102
95#include "regex.h" 103#include "regex.h"
96static char regex_expect[MAX_INPUT_BUFFER] = ""; 104static char regex_expect[MAX_INPUT_BUFFER] = "";
@@ -122,7 +130,7 @@ static char *units;
122static char *port; 130static char *port;
123static char *snmpcmd; 131static char *snmpcmd;
124static char string_value[MAX_INPUT_BUFFER] = ""; 132static char string_value[MAX_INPUT_BUFFER] = "";
125static int invert_search=0; 133static int invert_search = 0;
126static char **labels = NULL; 134static char **labels = NULL;
127static char **unitv = NULL; 135static char **unitv = NULL;
128static size_t nlabels = 0; 136static size_t nlabels = 0;
@@ -154,17 +162,18 @@ static state_data *previous_state;
154static double *previous_value; 162static double *previous_value;
155static size_t previous_size = OID_COUNT_STEP; 163static size_t previous_size = OID_COUNT_STEP;
156static int perf_labels = 1; 164static int perf_labels = 1;
157static char* ip_version = ""; 165static char *ip_version = "";
158static double multiplier = 1.0; 166static double multiplier = 1.0;
159static char *fmtstr = ""; 167static char *fmtstr = "";
160static bool fmtstr_set = false; 168static bool fmtstr_set = false;
161static char buffer[DEFAULT_BUFFER_SIZE]; 169static char buffer[DEFAULT_BUFFER_SIZE];
162static bool ignore_mib_parsing_errors = false; 170static bool ignore_mib_parsing_errors = false;
163 171
164static char *fix_snmp_range(char *th) 172static char *fix_snmp_range(char *th) {
165{ 173 double left;
166 double left, right; 174 double right;
167 char *colon, *ret; 175 char *colon;
176 char *ret;
168 177
169 if ((colon = strchr(th, ':')) == NULL || *(colon + 1) == '\0') 178 if ((colon = strchr(th, ':')) == NULL || *(colon + 1) == '\0')
170 return th; 179 return th;
@@ -182,12 +191,12 @@ static char *fix_snmp_range(char *th)
182 return ret; 191 return ret;
183} 192}
184 193
185int 194int main(int argc, char **argv) {
186main (int argc, char **argv) 195 int len;
187{ 196 int total_oids;
188 int len, total_oids;
189 size_t line; 197 size_t line;
190 unsigned int bk_count = 0, dq_count = 0; 198 unsigned int bk_count = 0;
199 unsigned int dq_count = 0;
191 int iresult = STATE_UNKNOWN; 200 int iresult = STATE_UNKNOWN;
192 int result = STATE_UNKNOWN; 201 int result = STATE_UNKNOWN;
193 int return_code = 0; 202 int return_code = 0;
@@ -200,80 +209,83 @@ main (int argc, char **argv)
200 char *outbuff; 209 char *outbuff;
201 char *ptr = NULL; 210 char *ptr = NULL;
202 char *show = NULL; 211 char *show = NULL;
203 char *th_warn=NULL; 212 char *th_warn = NULL;
204 char *th_crit=NULL; 213 char *th_crit = NULL;
205 char type[8] = ""; 214 char type[8] = "";
206 output chld_out, chld_err; 215 output chld_out;
207 char *previous_string=NULL; 216 output chld_err;
208 char *ap=NULL; 217 char *previous_string = NULL;
209 char *state_string=NULL; 218 char *ap = NULL;
210 size_t response_length, current_length, string_length; 219 char *state_string = NULL;
211 char *temp_string=NULL; 220 size_t response_length;
212 char *quote_string=NULL; 221 size_t current_length;
222 size_t string_length;
223 char *temp_string = NULL;
224 char *quote_string = NULL;
213 time_t current_time; 225 time_t current_time;
214 double temp_double; 226 double temp_double;
215 time_t duration; 227 time_t duration;
216 char *conv = "12345678"; 228 char *conv = "12345678";
217 int is_counter=0; 229 int is_counter = 0;
218 230
219 setlocale (LC_ALL, ""); 231 setlocale(LC_ALL, "");
220 bindtextdomain (PACKAGE, LOCALEDIR); 232 bindtextdomain(PACKAGE, LOCALEDIR);
221 textdomain (PACKAGE); 233 textdomain(PACKAGE);
222 234
223 labels = malloc (labels_size * sizeof(*labels)); 235 labels = malloc(labels_size * sizeof(*labels));
224 unitv = malloc (unitv_size * sizeof(*unitv)); 236 unitv = malloc(unitv_size * sizeof(*unitv));
225 thlds = malloc (thlds_size * sizeof(*thlds)); 237 thlds = malloc(thlds_size * sizeof(*thlds));
226 response_value = malloc (response_size * sizeof(*response_value)); 238 response_value = malloc(response_size * sizeof(*response_value));
227 previous_value = malloc (previous_size * sizeof(*previous_value)); 239 previous_value = malloc(previous_size * sizeof(*previous_value));
228 eval_method = calloc (eval_size, sizeof(*eval_method)); 240 eval_method = calloc(eval_size, sizeof(*eval_method));
229 oids = calloc(oids_size, sizeof (char *)); 241 oids = calloc(oids_size, sizeof(char *));
230 242
231 label = strdup ("SNMP"); 243 label = strdup("SNMP");
232 units = strdup (""); 244 units = strdup("");
233 port = strdup (DEFAULT_PORT); 245 port = strdup(DEFAULT_PORT);
234 outbuff = strdup (""); 246 outbuff = strdup("");
235 delimiter = strdup (" = "); 247 delimiter = strdup(" = ");
236 output_delim = strdup (DEFAULT_OUTPUT_DELIMITER); 248 output_delim = strdup(DEFAULT_OUTPUT_DELIMITER);
237 timeout_interval = DEFAULT_SOCKET_TIMEOUT; 249 timeout_interval = DEFAULT_SOCKET_TIMEOUT;
238 retries = DEFAULT_RETRIES; 250 retries = DEFAULT_RETRIES;
239 251
240 np_init( (char *) progname, argc, argv ); 252 np_init((char *)progname, argc, argv);
241 253
242 /* Parse extra opts if any */ 254 /* Parse extra opts if any */
243 argv=np_extra_opts (&argc, argv, progname); 255 argv = np_extra_opts(&argc, argv, progname);
244 256
245 np_set_args(argc, argv); 257 np_set_args(argc, argv);
246 258
247 time(&current_time); 259 time(&current_time);
248 260
249 if (process_arguments (argc, argv) == ERROR) 261 if (process_arguments(argc, argv) == ERROR)
250 usage4 (_("Could not parse arguments")); 262 usage4(_("Could not parse arguments"));
251 263
252 if(calculate_rate) { 264 if (calculate_rate) {
253 if (!strcmp(label, "SNMP")) 265 if (!strcmp(label, "SNMP"))
254 label = strdup("SNMP RATE"); 266 label = strdup("SNMP RATE");
255 267
256 size_t i = 0; 268 size_t i = 0;
257 269
258 previous_state = np_state_read(); 270 previous_state = np_state_read();
259 if(previous_state!=NULL) { 271 if (previous_state != NULL) {
260 /* Split colon separated values */ 272 /* Split colon separated values */
261 previous_string = strdup((char *) previous_state->data); 273 previous_string = strdup((char *)previous_state->data);
262 while((ap = strsep(&previous_string, ":")) != NULL) { 274 while ((ap = strsep(&previous_string, ":")) != NULL) {
263 if(verbose>2) 275 if (verbose > 2)
264 printf("State for %zd=%s\n", i, ap); 276 printf("State for %zd=%s\n", i, ap);
265 while (i >= previous_size) { 277 while (i >= previous_size) {
266 previous_size += OID_COUNT_STEP; 278 previous_size += OID_COUNT_STEP;
267 previous_value = realloc(previous_value, previous_size * sizeof(*previous_value)); 279 previous_value = realloc(previous_value, previous_size * sizeof(*previous_value));
268 } 280 }
269 previous_value[i++]=strtod(ap,NULL); 281 previous_value[i++] = strtod(ap, NULL);
270 } 282 }
271 } 283 }
272 } 284 }
273 285
274 /* Populate the thresholds */ 286 /* Populate the thresholds */
275 th_warn=warning_thresholds; 287 th_warn = warning_thresholds;
276 th_crit=critical_thresholds; 288 th_crit = critical_thresholds;
277 for (size_t i = 0; i < numoids; i++) { 289 for (size_t i = 0; i < numoids; i++) {
278 char *w = th_warn ? strndup(th_warn, strcspn(th_warn, ",")) : NULL; 290 char *w = th_warn ? strndup(th_warn, strcspn(th_warn, ",")) : NULL;
279 char *c = th_crit ? strndup(th_crit, strcspn(th_crit, ",")) : NULL; 291 char *c = th_crit ? strndup(th_crit, strcspn(th_crit, ",")) : NULL;
@@ -287,53 +299,52 @@ main (int argc, char **argv)
287 } 299 }
288 300
289 /* Skip empty thresholds, while avoiding segfault */ 301 /* Skip empty thresholds, while avoiding segfault */
290 set_thresholds(&thlds[i], 302 set_thresholds(&thlds[i], w ? strpbrk(w, NP_THRESHOLDS_CHARS) : NULL, c ? strpbrk(c, NP_THRESHOLDS_CHARS) : NULL);
291 w ? strpbrk(w, NP_THRESHOLDS_CHARS) : NULL,
292 c ? strpbrk(c, NP_THRESHOLDS_CHARS) : NULL);
293 if (w) { 303 if (w) {
294 th_warn=strchr(th_warn, ','); 304 th_warn = strchr(th_warn, ',');
295 if (th_warn) th_warn++; 305 if (th_warn)
306 th_warn++;
296 free(w); 307 free(w);
297 } 308 }
298 if (c) { 309 if (c) {
299 th_crit=strchr(th_crit, ','); 310 th_crit = strchr(th_crit, ',');
300 if (th_crit) th_crit++; 311 if (th_crit)
312 th_crit++;
301 free(c); 313 free(c);
302 } 314 }
303 } 315 }
304 316
305 /* Create the command array to execute */ 317 /* Create the command array to execute */
306 if(usesnmpgetnext) { 318 if (usesnmpgetnext) {
307 snmpcmd = strdup (PATH_TO_SNMPGETNEXT); 319 snmpcmd = strdup(PATH_TO_SNMPGETNEXT);
308 }else{ 320 } else {
309 snmpcmd = strdup (PATH_TO_SNMPGET); 321 snmpcmd = strdup(PATH_TO_SNMPGET);
310 } 322 }
311 323
312 /* 10 arguments to pass before context and authpriv options + 1 for host and numoids. Add one for terminating NULL */ 324 /* 10 arguments to pass before context and authpriv options + 1 for host and numoids. Add one for terminating NULL */
313 325
314 unsigned index = 0; 326 unsigned index = 0;
315 command_line = calloc (11 + numcontext + numauthpriv + 1 + numoids + 1, sizeof (char *)); 327 command_line = calloc(11 + numcontext + numauthpriv + 1 + numoids + 1, sizeof(char *));
316 328
317 command_line[index++] = snmpcmd; 329 command_line[index++] = snmpcmd;
318 command_line[index++] = strdup ("-Le"); 330 command_line[index++] = strdup("-Le");
319 command_line[index++] = strdup ("-t"); 331 command_line[index++] = strdup("-t");
320 xasprintf (&command_line[index++], "%d", timeout_interval); 332 xasprintf(&command_line[index++], "%d", timeout_interval);
321 command_line[index++] = strdup ("-r"); 333 command_line[index++] = strdup("-r");
322 xasprintf (&command_line[index++], "%d", retries); 334 xasprintf(&command_line[index++], "%d", retries);
323 command_line[index++] = strdup ("-m"); 335 command_line[index++] = strdup("-m");
324 command_line[index++] = strdup (miblist); 336 command_line[index++] = strdup(miblist);
325 command_line[index++] = "-v"; 337 command_line[index++] = "-v";
326 command_line[index++] = strdup (proto); 338 command_line[index++] = strdup(proto);
327 339
328 xasprintf(&cl_hidden_auth, "%s -Le -t %d -r %d -m %s -v %s", 340 xasprintf(&cl_hidden_auth, "%s -Le -t %d -r %d -m %s -v %s", snmpcmd, timeout_interval, retries, strlen(miblist) ? miblist : "''",
329 snmpcmd, timeout_interval, retries, strlen(miblist) ? miblist : "''", proto); 341 proto);
330 342
331 if (ignore_mib_parsing_errors) { 343 if (ignore_mib_parsing_errors) {
332 command_line[index++] = "-Pe"; 344 command_line[index++] = "-Pe";
333 xasprintf(&cl_hidden_auth, "%s -Pe", cl_hidden_auth); 345 xasprintf(&cl_hidden_auth, "%s -Pe", cl_hidden_auth);
334 } 346 }
335 347
336
337 for (int i = 0; i < numcontext; i++) { 348 for (int i = 0; i < numcontext; i++) {
338 command_line[index++] = contextargs[i]; 349 command_line[index++] = contextargs[i];
339 } 350 }
@@ -342,12 +353,9 @@ main (int argc, char **argv)
342 command_line[index++] = authpriv[i]; 353 command_line[index++] = authpriv[i];
343 } 354 }
344 355
345 xasprintf (&command_line[index++], "%s:%s", server_address, port); 356 xasprintf(&command_line[index++], "%s:%s", server_address, port);
346 357
347 xasprintf(&cl_hidden_auth, "%s [context] [authpriv] %s:%s", 358 xasprintf(&cl_hidden_auth, "%s [context] [authpriv] %s:%s", cl_hidden_auth, server_address, port);
348 cl_hidden_auth,
349 server_address,
350 port);
351 359
352 for (size_t i = 0; i < numoids; i++) { 360 for (size_t i = 0; i < numoids; i++) {
353 command_line[index++] = oids[i]; 361 command_line[index++] = oids[i];
@@ -357,17 +365,17 @@ main (int argc, char **argv)
357 command_line[index++] = NULL; 365 command_line[index++] = NULL;
358 366
359 if (verbose) { 367 if (verbose) {
360 printf ("%s\n", cl_hidden_auth); 368 printf("%s\n", cl_hidden_auth);
361 } 369 }
362 370
363 /* Set signal handling and alarm */ 371 /* Set signal handling and alarm */
364 if (signal (SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) { 372 if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
365 usage4 (_("Cannot catch SIGALRM")); 373 usage4(_("Cannot catch SIGALRM"));
366 } 374 }
367 alarm(timeout_interval * retries + 5); 375 alarm(timeout_interval * retries + 5);
368 376
369 /* Run the command */ 377 /* Run the command */
370 return_code = cmd_run_array (command_line, &chld_out, &chld_err, 0); 378 return_code = cmd_run_array(command_line, &chld_out, &chld_err, 0);
371 379
372 /* disable alarm again */ 380 /* disable alarm again */
373 alarm(0); 381 alarm(0);
@@ -377,80 +385,74 @@ main (int argc, char **argv)
377 Do this way so that if there is stderr, will get added to output, which helps problem diagnosis 385 Do this way so that if there is stderr, will get added to output, which helps problem diagnosis
378 */ 386 */
379 if (return_code != 0) 387 if (return_code != 0)
380 external_error=1; 388 external_error = 1;
381 if (chld_out.lines == 0) 389 if (chld_out.lines == 0)
382 external_error=1; 390 external_error = 1;
383 if (external_error) { 391 if (external_error) {
384 if (chld_err.lines > 0) { 392 if (chld_err.lines > 0) {
385 printf (_("External command error: %s\n"), chld_err.line[0]); 393 printf(_("External command error: %s\n"), chld_err.line[0]);
386 for (size_t i = 1; i < chld_err.lines; i++) { 394 for (size_t i = 1; i < chld_err.lines; i++) {
387 printf ("%s\n", chld_err.line[i]); 395 printf("%s\n", chld_err.line[i]);
388 } 396 }
389 } else { 397 } else {
390 printf(_("External command error with no output (return code: %d)\n"), return_code); 398 printf(_("External command error with no output (return code: %d)\n"), return_code);
391 } 399 }
392 exit (STATE_UNKNOWN); 400 exit(STATE_UNKNOWN);
393 } 401 }
394 402
395 if (verbose) { 403 if (verbose) {
396 for (size_t i = 0; i < chld_out.lines; i++) { 404 for (size_t i = 0; i < chld_out.lines; i++) {
397 printf ("%s\n", chld_out.line[i]); 405 printf("%s\n", chld_out.line[i]);
398 } 406 }
399 } 407 }
400 408
401 line = 0; 409 line = 0;
402 total_oids = 0; 410 total_oids = 0;
403 for (size_t i = 0; line < chld_out.lines && i < numoids ; line++, i++, total_oids++) { 411 for (size_t i = 0; line < chld_out.lines && i < numoids; line++, i++, total_oids++) {
404 if(calculate_rate) 412 if (calculate_rate)
405 conv = "%.10g"; 413 conv = "%.10g";
406 else 414 else
407 conv = "%.0f"; 415 conv = "%.0f";
408 416
409 ptr = chld_out.line[line]; 417 ptr = chld_out.line[line];
410 oidname = strpcpy (oidname, ptr, delimiter); 418 oidname = strpcpy(oidname, ptr, delimiter);
411 response = strstr (ptr, delimiter); 419 response = strstr(ptr, delimiter);
412 if (response == NULL) 420 if (response == NULL)
413 break; 421 break;
414 422
415 if (verbose > 2) { 423 if (verbose > 2) {
416 printf("Processing oid %zi (line %zi)\n oidname: %s\n response: %s\n", i+1, line+1, oidname, response); 424 printf("Processing oid %zi (line %zi)\n oidname: %s\n response: %s\n", i + 1, line + 1, oidname, response);
417 } 425 }
418 426
419 /* Clean up type array - Sol10 does not necessarily zero it out */ 427 /* Clean up type array - Sol10 does not necessarily zero it out */
420 bzero(type, sizeof(type)); 428 bzero(type, sizeof(type));
421 429
422 is_counter=0; 430 is_counter = 0;
423 /* We strip out the datatype indicator for PHBs */ 431 /* We strip out the datatype indicator for PHBs */
424 if (strstr (response, "Gauge: ")) { 432 if (strstr(response, "Gauge: ")) {
425 show = multiply (strstr (response, "Gauge: ") + 7); 433 show = multiply(strstr(response, "Gauge: ") + 7);
426 } 434 } else if (strstr(response, "Gauge32: ")) {
427 else if (strstr (response, "Gauge32: ")) { 435 show = multiply(strstr(response, "Gauge32: ") + 9);
428 show = multiply (strstr (response, "Gauge32: ") + 9); 436 } else if (strstr(response, "Counter32: ")) {
429 } 437 show = strstr(response, "Counter32: ") + 11;
430 else if (strstr (response, "Counter32: ")) { 438 is_counter = 1;
431 show = strstr (response, "Counter32: ") + 11; 439 if (!calculate_rate)
432 is_counter=1;
433 if(!calculate_rate)
434 strcpy(type, "c"); 440 strcpy(type, "c");
435 } 441 } else if (strstr(response, "Counter64: ")) {
436 else if (strstr (response, "Counter64: ")) { 442 show = strstr(response, "Counter64: ") + 11;
437 show = strstr (response, "Counter64: ") + 11; 443 is_counter = 1;
438 is_counter=1; 444 if (!calculate_rate)
439 if(!calculate_rate)
440 strcpy(type, "c"); 445 strcpy(type, "c");
441 } 446 } else if (strstr(response, "INTEGER: ")) {
442 else if (strstr (response, "INTEGER: ")) { 447 show = multiply(strstr(response, "INTEGER: ") + 9);
443 show = multiply (strstr (response, "INTEGER: ") + 9);
444 448
445 if (fmtstr_set) { 449 if (fmtstr_set) {
446 conv = fmtstr; 450 conv = fmtstr;
447 } 451 }
448 } 452 } else if (strstr(response, "OID: ")) {
449 else if (strstr (response, "OID: ")) { 453 show = strstr(response, "OID: ") + 5;
450 show = strstr (response, "OID: ") + 5; 454 } else if (strstr(response, "STRING: ")) {
451 } 455 show = strstr(response, "STRING: ") + 8;
452 else if (strstr (response, "STRING: ")) {
453 show = strstr (response, "STRING: ") + 8;
454 conv = "%.10g"; 456 conv = "%.10g";
455 457
456 /* Get the rest of the string on multi-line strings */ 458 /* Get the rest of the string on multi-line strings */
@@ -464,15 +466,17 @@ main (int argc, char **argv)
464 466
465 if (dq_count) { /* unfinished line */ 467 if (dq_count) { /* unfinished line */
466 /* copy show verbatim first */ 468 /* copy show verbatim first */
467 if (!mult_resp) mult_resp = strdup(""); 469 if (!mult_resp)
468 xasprintf (&mult_resp, "%s%s:\n%s\n", mult_resp, oids[i], show); 470 mult_resp = strdup("");
471 xasprintf(&mult_resp, "%s%s:\n%s\n", mult_resp, oids[i], show);
469 /* then strip out unmatched double-quote from single-line output */ 472 /* then strip out unmatched double-quote from single-line output */
470 if (show[0] == '"') show++; 473 if (show[0] == '"')
474 show++;
471 475
472 /* Keep reading until we match end of double-quoted string */ 476 /* Keep reading until we match end of double-quoted string */
473 for (line++; line < chld_out.lines; line++) { 477 for (line++; line < chld_out.lines; line++) {
474 ptr = chld_out.line[line]; 478 ptr = chld_out.line[line];
475 xasprintf (&mult_resp, "%s%s\n", mult_resp, ptr); 479 xasprintf(&mult_resp, "%s%s\n", mult_resp, ptr);
476 480
477 COUNT_SEQ(ptr, bk_count, dq_count) 481 COUNT_SEQ(ptr, bk_count, dq_count)
478 while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') { 482 while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
@@ -481,15 +485,14 @@ main (int argc, char **argv)
481 COUNT_SEQ(ptr, bk_count, dq_count) 485 COUNT_SEQ(ptr, bk_count, dq_count)
482 } 486 }
483 /* Break for loop before next line increment when done */ 487 /* Break for loop before next line increment when done */
484 if (!dq_count) break; 488 if (!dq_count)
489 break;
485 } 490 }
486 } 491 }
487 492
488 } 493 } else if (strstr(response, "Timeticks: ")) {
489 else if (strstr (response, "Timeticks: ")) { 494 show = strstr(response, "Timeticks: ");
490 show = strstr (response, "Timeticks: "); 495 } else
491 }
492 else
493 show = response + 3; 496 show = response + 3;
494 497
495 iresult = STATE_DEPENDENT; 498 iresult = STATE_DEPENDENT;
@@ -500,68 +503,67 @@ main (int argc, char **argv)
500 if (verbose > 2) { 503 if (verbose > 2) {
501 print_thresholds(" thresholds", thlds[i]); 504 print_thresholds(" thresholds", thlds[i]);
502 } 505 }
503 ptr = strpbrk (show, "-0123456789"); 506 ptr = strpbrk(show, "-0123456789");
504 if (ptr == NULL){ 507 if (ptr == NULL) {
505 if (nulloid == 3) 508 if (nulloid == 3)
506 die (STATE_UNKNOWN,_("No valid data returned (%s)\n"), show); 509 die(STATE_UNKNOWN, _("No valid data returned (%s)\n"), show);
507 else if (nulloid == 0) 510 else if (nulloid == 0)
508 die (STATE_OK,_("No valid data returned (%s)\n"), show); 511 die(STATE_OK, _("No valid data returned (%s)\n"), show);
509 else if (nulloid == 1) 512 else if (nulloid == 1)
510 die (STATE_WARNING,_("No valid data returned (%s)\n"), show); 513 die(STATE_WARNING, _("No valid data returned (%s)\n"), show);
511 else if (nulloid == 2) 514 else if (nulloid == 2)
512 die (STATE_CRITICAL,_("No valid data returned (%s)\n"), show); 515 die(STATE_CRITICAL, _("No valid data returned (%s)\n"), show);
513 } 516 }
514 while (i >= response_size) { 517 while (i >= response_size) {
515 response_size += OID_COUNT_STEP; 518 response_size += OID_COUNT_STEP;
516 response_value = realloc(response_value, response_size * sizeof(*response_value)); 519 response_value = realloc(response_value, response_size * sizeof(*response_value));
517 } 520 }
518 response_value[i] = strtod (ptr, NULL) + offset; 521 response_value[i] = strtod(ptr, NULL) + offset;
519 522
520 if(calculate_rate) { 523 if (calculate_rate) {
521 if (previous_state!=NULL) { 524 if (previous_state != NULL) {
522 duration = current_time-previous_state->time; 525 duration = current_time - previous_state->time;
523 if(duration<=0) 526 if (duration <= 0)
524 die(STATE_UNKNOWN,_("Time duration between plugin calls is invalid")); 527 die(STATE_UNKNOWN, _("Time duration between plugin calls is invalid"));
525 temp_double = response_value[i]-previous_value[i]; 528 temp_double = response_value[i] - previous_value[i];
526 /* Simple overflow catcher (same as in rrdtool, rrd_update.c) */ 529 /* Simple overflow catcher (same as in rrdtool, rrd_update.c) */
527 if(is_counter) { 530 if (is_counter) {
528 if(temp_double<(double)0.0) 531 if (temp_double < (double)0.0)
529 temp_double+=(double)4294967296.0; /* 2^32 */ 532 temp_double += (double)4294967296.0; /* 2^32 */
530 if(temp_double<(double)0.0) 533 if (temp_double < (double)0.0)
531 temp_double+=(double)18446744069414584320.0; /* 2^64-2^32 */; 534 temp_double += (double)18446744069414584320.0; /* 2^64-2^32 */
535 ;
532 } 536 }
533 /* Convert to per second, then use multiplier */ 537 /* Convert to per second, then use multiplier */
534 temp_double = temp_double/duration*rate_multiplier; 538 temp_double = temp_double / duration * rate_multiplier;
535 iresult = get_status(temp_double, thlds[i]); 539 iresult = get_status(temp_double, thlds[i]);
536 xasprintf (&show, conv, temp_double); 540 xasprintf(&show, conv, temp_double);
537 } 541 }
538 } else { 542 } else {
539 iresult = get_status(response_value[i], thlds[i]); 543 iresult = get_status(response_value[i], thlds[i]);
540 xasprintf (&show, conv, response_value[i]); 544 xasprintf(&show, conv, response_value[i]);
541 } 545 }
542 } 546 }
543 547
544 /* Process this block for string matching */ 548 /* Process this block for string matching */
545 else if (eval_size > i && eval_method[i] & CRIT_STRING) { 549 else if (eval_size > i && eval_method[i] & CRIT_STRING) {
546 if (strcmp (show, string_value)) 550 if (strcmp(show, string_value))
547 iresult = (invert_search==0) ? STATE_CRITICAL : STATE_OK; 551 iresult = (invert_search == 0) ? STATE_CRITICAL : STATE_OK;
548 else 552 else
549 iresult = (invert_search==0) ? STATE_OK : STATE_CRITICAL; 553 iresult = (invert_search == 0) ? STATE_OK : STATE_CRITICAL;
550 } 554 }
551 555
552 /* Process this block for regex matching */ 556 /* Process this block for regex matching */
553 else if (eval_size > i && eval_method[i] & CRIT_REGEX) { 557 else if (eval_size > i && eval_method[i] & CRIT_REGEX) {
554 excode = regexec (&preg, response, 10, pmatch, eflags); 558 excode = regexec(&preg, response, 10, pmatch, eflags);
555 if (excode == 0) { 559 if (excode == 0) {
556 iresult = (invert_search==0) ? STATE_OK : STATE_CRITICAL; 560 iresult = (invert_search == 0) ? STATE_OK : STATE_CRITICAL;
557 } 561 } else if (excode != REG_NOMATCH) {
558 else if (excode != REG_NOMATCH) { 562 regerror(excode, &preg, errbuf, MAX_INPUT_BUFFER);
559 regerror (excode, &preg, errbuf, MAX_INPUT_BUFFER); 563 printf(_("Execute Error: %s\n"), errbuf);
560 printf (_("Execute Error: %s\n"), errbuf); 564 exit(STATE_CRITICAL);
561 exit (STATE_CRITICAL); 565 } else {
562 } 566 iresult = (invert_search == 0) ? STATE_CRITICAL : STATE_OK;
563 else {
564 iresult = (invert_search==0) ? STATE_CRITICAL : STATE_OK;
565 } 567 }
566 } 568 }
567 569
@@ -577,294 +579,283 @@ main (int argc, char **argv)
577 } 579 }
578 580
579 /* Result is the worst outcome of all the OIDs tested */ 581 /* Result is the worst outcome of all the OIDs tested */
580 result = max_state (result, iresult); 582 result = max_state(result, iresult);
581 583
582 /* Prepend a label for this OID if there is one */ 584 /* Prepend a label for this OID if there is one */
583 if (nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL) 585 if (nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
584 xasprintf (&outbuff, "%s%s%s %s%s%s", outbuff, 586 xasprintf(&outbuff, "%s%s%s %s%s%s", outbuff, (i == 0) ? " " : output_delim, labels[i], mark(iresult), show, mark(iresult));
585 (i == 0) ? " " : output_delim,
586 labels[i], mark (iresult), show, mark (iresult));
587 else 587 else
588 xasprintf (&outbuff, "%s%s%s%s%s", outbuff, (i == 0) ? " " : output_delim, 588 xasprintf(&outbuff, "%s%s%s%s%s", outbuff, (i == 0) ? " " : output_delim, mark(iresult), show, mark(iresult));
589 mark (iresult), show, mark (iresult));
590 589
591 /* Append a unit string for this OID if there is one */ 590 /* Append a unit string for this OID if there is one */
592 if (nunits > (size_t)0 && (size_t)i < nunits && unitv[i] != NULL) 591 if (nunits > (size_t)0 && (size_t)i < nunits && unitv[i] != NULL)
593 xasprintf (&outbuff, "%s %s", outbuff, unitv[i]); 592 xasprintf(&outbuff, "%s %s", outbuff, unitv[i]);
594 593
595 /* Write perfdata with whatever can be parsed by strtod, if possible */ 594 /* Write perfdata with whatever can be parsed by strtod, if possible */
596 ptr = NULL; 595 ptr = NULL;
597 strtod(show, &ptr); 596 strtod(show, &ptr);
598 if (ptr > show) { 597 if (ptr > show) {
599 if (perf_labels && nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL) 598 if (perf_labels && nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
600 temp_string=labels[i]; 599 temp_string = labels[i];
601 else 600 else
602 temp_string=oidname; 601 temp_string = oidname;
603 if (strpbrk (temp_string, " ='\"") == NULL) { 602 if (strpbrk(temp_string, " ='\"") == NULL) {
604 strncat(perfstr, temp_string, sizeof(perfstr)-strlen(perfstr)-1); 603 strncat(perfstr, temp_string, sizeof(perfstr) - strlen(perfstr) - 1);
605 } else { 604 } else {
606 if (strpbrk (temp_string, "'") == NULL) { 605 if (strpbrk(temp_string, "'") == NULL) {
607 quote_string="'"; 606 quote_string = "'";
608 } else { 607 } else {
609 quote_string="\""; 608 quote_string = "\"";
610 } 609 }
611 strncat(perfstr, quote_string, sizeof(perfstr)-strlen(perfstr)-1); 610 strncat(perfstr, quote_string, sizeof(perfstr) - strlen(perfstr) - 1);
612 strncat(perfstr, temp_string, sizeof(perfstr)-strlen(perfstr)-1); 611 strncat(perfstr, temp_string, sizeof(perfstr) - strlen(perfstr) - 1);
613 strncat(perfstr, quote_string, sizeof(perfstr)-strlen(perfstr)-1); 612 strncat(perfstr, quote_string, sizeof(perfstr) - strlen(perfstr) - 1);
614 } 613 }
615 strncat(perfstr, "=", sizeof(perfstr)-strlen(perfstr)-1); 614 strncat(perfstr, "=", sizeof(perfstr) - strlen(perfstr) - 1);
616 len = sizeof(perfstr)-strlen(perfstr)-1; 615 len = sizeof(perfstr) - strlen(perfstr) - 1;
617 strncat(perfstr, show, len>ptr-show ? ptr-show : len); 616 strncat(perfstr, show, len > ptr - show ? ptr - show : len);
618 617
619 if (strcmp(type, "") != 0) { 618 if (strcmp(type, "") != 0) {
620 strncat(perfstr, type, sizeof(perfstr)-strlen(perfstr)-1); 619 strncat(perfstr, type, sizeof(perfstr) - strlen(perfstr) - 1);
621 } 620 }
622 621
623 if (warning_thresholds) { 622 if (warning_thresholds) {
624 strncat(perfstr, ";", sizeof(perfstr)-strlen(perfstr)-1); 623 strncat(perfstr, ";", sizeof(perfstr) - strlen(perfstr) - 1);
625 if(thlds[i]->warning && thlds[i]->warning->text) 624 if (thlds[i]->warning && thlds[i]->warning->text)
626 strncat(perfstr, thlds[i]->warning->text, sizeof(perfstr)-strlen(perfstr)-1); 625 strncat(perfstr, thlds[i]->warning->text, sizeof(perfstr) - strlen(perfstr) - 1);
627 } 626 }
628 627
629 if (critical_thresholds) { 628 if (critical_thresholds) {
630 if (!warning_thresholds) 629 if (!warning_thresholds)
631 strncat(perfstr, ";", sizeof(perfstr)-strlen(perfstr)-1); 630 strncat(perfstr, ";", sizeof(perfstr) - strlen(perfstr) - 1);
632 strncat(perfstr, ";", sizeof(perfstr)-strlen(perfstr)-1); 631 strncat(perfstr, ";", sizeof(perfstr) - strlen(perfstr) - 1);
633 if(thlds[i]->critical && thlds[i]->critical->text) 632 if (thlds[i]->critical && thlds[i]->critical->text)
634 strncat(perfstr, thlds[i]->critical->text, sizeof(perfstr)-strlen(perfstr)-1); 633 strncat(perfstr, thlds[i]->critical->text, sizeof(perfstr) - strlen(perfstr) - 1);
635 } 634 }
636 635
637 strncat(perfstr, " ", sizeof(perfstr)-strlen(perfstr)-1); 636 strncat(perfstr, " ", sizeof(perfstr) - strlen(perfstr) - 1);
638 } 637 }
639 } 638 }
640 639
641 /* Save state data, as all data collected now */ 640 /* Save state data, as all data collected now */
642 if(calculate_rate) { 641 if (calculate_rate) {
643 string_length=1024; 642 string_length = 1024;
644 state_string=malloc(string_length); 643 state_string = malloc(string_length);
645 if(state_string==NULL) 644 if (state_string == NULL)
646 die(STATE_UNKNOWN, _("Cannot malloc")); 645 die(STATE_UNKNOWN, _("Cannot malloc"));
647 646
648 current_length=0; 647 current_length = 0;
649 for(int i = 0; i < total_oids; i++) { 648 for (int i = 0; i < total_oids; i++) {
650 xasprintf(&temp_string,"%.0f",response_value[i]); 649 xasprintf(&temp_string, "%.0f", response_value[i]);
651 if(temp_string==NULL) 650 if (temp_string == NULL)
652 die(STATE_UNKNOWN,_("Cannot asprintf()")); 651 die(STATE_UNKNOWN, _("Cannot asprintf()"));
653 response_length = strlen(temp_string); 652 response_length = strlen(temp_string);
654 if(current_length+response_length>string_length) { 653 if (current_length + response_length > string_length) {
655 string_length=current_length+1024; 654 string_length = current_length + 1024;
656 state_string=realloc(state_string,string_length); 655 state_string = realloc(state_string, string_length);
657 if(state_string==NULL) 656 if (state_string == NULL)
658 die(STATE_UNKNOWN, _("Cannot realloc()")); 657 die(STATE_UNKNOWN, _("Cannot realloc()"));
659 } 658 }
660 strcpy(&state_string[current_length],temp_string); 659 strcpy(&state_string[current_length], temp_string);
661 current_length=current_length+response_length; 660 current_length = current_length + response_length;
662 state_string[current_length]=':'; 661 state_string[current_length] = ':';
663 current_length++; 662 current_length++;
664 free(temp_string); 663 free(temp_string);
665 } 664 }
666 state_string[--current_length]='\0'; 665 state_string[--current_length] = '\0';
667 if (verbose > 2) 666 if (verbose > 2)
668 printf("State string=%s\n",state_string); 667 printf("State string=%s\n", state_string);
669 668
670 /* This is not strictly the same as time now, but any subtle variations will cancel out */ 669 /* This is not strictly the same as time now, but any subtle variations will cancel out */
671 np_state_write_string(current_time, state_string ); 670 np_state_write_string(current_time, state_string);
672 if(previous_state==NULL) { 671 if (previous_state == NULL) {
673 /* Or should this be highest state? */ 672 /* Or should this be highest state? */
674 die( STATE_OK, _("No previous data to calculate rate - assume okay" ) ); 673 die(STATE_OK, _("No previous data to calculate rate - assume okay"));
675 } 674 }
676 } 675 }
677 676
678 printf ("%s %s -%s %s\n", label, state_text (result), outbuff, perfstr); 677 printf("%s %s -%s %s\n", label, state_text(result), outbuff, perfstr);
679 if (mult_resp) printf ("%s", mult_resp); 678 if (mult_resp)
679 printf("%s", mult_resp);
680 680
681 return result; 681 return result;
682} 682}
683 683
684
685
686/* process command-line arguments */ 684/* process command-line arguments */
687int 685int process_arguments(int argc, char **argv) {
688process_arguments (int argc, char **argv) 686 static struct option longopts[] = {STD_LONG_OPTS,
689{ 687 {"community", required_argument, 0, 'C'},
690 char *ptr; 688 {"oid", required_argument, 0, 'o'},
691 int c = 1; 689 {"object", required_argument, 0, 'o'},
692 size_t j = 0, jj = 0; 690 {"delimiter", required_argument, 0, 'd'},
693 691 {"nulloid", required_argument, 0, 'z'},
694 int option = 0; 692 {"output-delimiter", required_argument, 0, 'D'},
695 static struct option longopts[] = { 693 {"string", required_argument, 0, 's'},
696 STD_LONG_OPTS, 694 {"timeout", required_argument, 0, 't'},
697 {"community", required_argument, 0, 'C'}, 695 {"regex", required_argument, 0, 'r'},
698 {"oid", required_argument, 0, 'o'}, 696 {"ereg", required_argument, 0, 'r'},
699 {"object", required_argument, 0, 'o'}, 697 {"eregi", required_argument, 0, 'R'},
700 {"delimiter", required_argument, 0, 'd'}, 698 {"label", required_argument, 0, 'l'},
701 {"nulloid", required_argument, 0, 'z'}, 699 {"units", required_argument, 0, 'u'},
702 {"output-delimiter", required_argument, 0, 'D'}, 700 {"port", required_argument, 0, 'p'},
703 {"string", required_argument, 0, 's'}, 701 {"retries", required_argument, 0, 'e'},
704 {"timeout", required_argument, 0, 't'}, 702 {"miblist", required_argument, 0, 'm'},
705 {"regex", required_argument, 0, 'r'}, 703 {"protocol", required_argument, 0, 'P'},
706 {"ereg", required_argument, 0, 'r'}, 704 {"context", required_argument, 0, 'N'},
707 {"eregi", required_argument, 0, 'R'}, 705 {"seclevel", required_argument, 0, 'L'},
708 {"label", required_argument, 0, 'l'}, 706 {"secname", required_argument, 0, 'U'},
709 {"units", required_argument, 0, 'u'}, 707 {"authproto", required_argument, 0, 'a'},
710 {"port", required_argument, 0, 'p'}, 708 {"privproto", required_argument, 0, 'x'},
711 {"retries", required_argument, 0, 'e'}, 709 {"authpasswd", required_argument, 0, 'A'},
712 {"miblist", required_argument, 0, 'm'}, 710 {"privpasswd", required_argument, 0, 'X'},
713 {"protocol", required_argument, 0, 'P'}, 711 {"next", no_argument, 0, 'n'},
714 {"context", required_argument, 0, 'N'}, 712 {"rate", no_argument, 0, L_CALCULATE_RATE},
715 {"seclevel", required_argument, 0, 'L'}, 713 {"rate-multiplier", required_argument, 0, L_RATE_MULTIPLIER},
716 {"secname", required_argument, 0, 'U'}, 714 {"offset", required_argument, 0, L_OFFSET},
717 {"authproto", required_argument, 0, 'a'}, 715 {"invert-search", no_argument, 0, L_INVERT_SEARCH},
718 {"privproto", required_argument, 0, 'x'}, 716 {"perf-oids", no_argument, 0, 'O'},
719 {"authpasswd", required_argument, 0, 'A'}, 717 {"ipv4", no_argument, 0, '4'},
720 {"privpasswd", required_argument, 0, 'X'}, 718 {"ipv6", no_argument, 0, '6'},
721 {"next", no_argument, 0, 'n'}, 719 {"multiplier", required_argument, 0, 'M'},
722 {"rate", no_argument, 0, L_CALCULATE_RATE}, 720 {"fmtstr", required_argument, 0, 'f'},
723 {"rate-multiplier", required_argument, 0, L_RATE_MULTIPLIER}, 721 {"ignore-mib-parsing-errors", no_argument, false, L_IGNORE_MIB_PARSING_ERRORS},
724 {"offset", required_argument, 0, L_OFFSET}, 722 {0, 0, 0, 0}};
725 {"invert-search", no_argument, 0, L_INVERT_SEARCH},
726 {"perf-oids", no_argument, 0, 'O'},
727 {"ipv4", no_argument, 0, '4'},
728 {"ipv6", no_argument, 0, '6'},
729 {"multiplier", required_argument, 0, 'M'},
730 {"fmtstr", required_argument, 0, 'f'},
731 {"ignore-mib-parsing-errors", no_argument, false, L_IGNORE_MIB_PARSING_ERRORS},
732 {0, 0, 0, 0}
733 };
734 723
735 if (argc < 2) 724 if (argc < 2)
736 return ERROR; 725 return ERROR;
737 726
738 /* reverse compatibility for very old non-POSIX usage forms */ 727 /* reverse compatibility for very old non-POSIX usage forms */
739 for (c = 1; c < argc; c++) { 728 for (int c = 1; c < argc; c++) {
740 if (strcmp ("-to", argv[c]) == 0) 729 if (strcmp("-to", argv[c]) == 0)
741 strcpy (argv[c], "-t"); 730 strcpy(argv[c], "-t");
742 if (strcmp ("-wv", argv[c]) == 0) 731 if (strcmp("-wv", argv[c]) == 0)
743 strcpy (argv[c], "-w"); 732 strcpy(argv[c], "-w");
744 if (strcmp ("-cv", argv[c]) == 0) 733 if (strcmp("-cv", argv[c]) == 0)
745 strcpy (argv[c], "-c"); 734 strcpy(argv[c], "-c");
746 } 735 }
747 736
748 while (1) { 737 size_t j = 0;
749 c = 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:", 738 size_t jj = 0;
750 longopts, &option); 739 while (true) {
740 int option = 0;
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);
751 742
752 if (c == -1 || c == EOF) 743 if (option_char == -1 || option_char == EOF)
753 break; 744 break;
754 745
755 switch (c) { 746 switch (option_char) {
756 case '?': /* usage */ 747 case '?': /* usage */
757 usage5 (); 748 usage5();
758 case 'h': /* help */ 749 case 'h': /* help */
759 print_help (); 750 print_help();
760 exit (STATE_UNKNOWN); 751 exit(STATE_UNKNOWN);
761 case 'V': /* version */ 752 case 'V': /* version */
762 print_revision (progname, NP_VERSION); 753 print_revision(progname, NP_VERSION);
763 exit (STATE_UNKNOWN); 754 exit(STATE_UNKNOWN);
764 case 'v': /* verbose */ 755 case 'v': /* verbose */
765 verbose++; 756 verbose++;
766 break; 757 break;
767 758
768 /* Connection info */ 759 /* Connection info */
769 case 'C': /* group or community */ 760 case 'C': /* group or community */
770 community = optarg; 761 community = optarg;
771 break; 762 break;
772 case 'H': /* Host or server */ 763 case 'H': /* Host or server */
773 server_address = optarg; 764 server_address = optarg;
774 break; 765 break;
775 case 'p': /* TCP port number */ 766 case 'p': /* TCP port number */
776 port = optarg; 767 port = optarg;
777 break; 768 break;
778 case 'm': /* List of MIBS */ 769 case 'm': /* List of MIBS */
779 miblist = optarg; 770 miblist = optarg;
780 break; 771 break;
781 case 'n': /* usesnmpgetnext */ 772 case 'n': /* usesnmpgetnext */
782 usesnmpgetnext = true; 773 usesnmpgetnext = true;
783 break; 774 break;
784 case 'P': /* SNMP protocol version */ 775 case 'P': /* SNMP protocol version */
785 proto = optarg; 776 proto = optarg;
786 break; 777 break;
787 case 'N': /* SNMPv3 context */ 778 case 'N': /* SNMPv3 context */
788 context = optarg; 779 context = optarg;
789 break; 780 break;
790 case 'L': /* security level */ 781 case 'L': /* security level */
791 seclevel = optarg; 782 seclevel = optarg;
792 break; 783 break;
793 case 'U': /* security username */ 784 case 'U': /* security username */
794 secname = optarg; 785 secname = optarg;
795 break; 786 break;
796 case 'a': /* auth protocol */ 787 case 'a': /* auth protocol */
797 authproto = optarg; 788 authproto = optarg;
798 break; 789 break;
799 case 'x': /* priv protocol */ 790 case 'x': /* priv protocol */
800 privproto = optarg; 791 privproto = optarg;
801 break; 792 break;
802 case 'A': /* auth passwd */ 793 case 'A': /* auth passwd */
803 authpasswd = optarg; 794 authpasswd = optarg;
804 break; 795 break;
805 case 'X': /* priv passwd */ 796 case 'X': /* priv passwd */
806 privpasswd = optarg; 797 privpasswd = optarg;
807 break; 798 break;
808 case 't': /* timeout period */ 799 case 't': /* timeout period */
809 if (!is_integer (optarg)) 800 if (!is_integer(optarg))
810 usage2 (_("Timeout interval must be a positive integer"), optarg); 801 usage2(_("Timeout interval must be a positive integer"), optarg);
811 else 802 else
812 timeout_interval = atoi (optarg); 803 timeout_interval = atoi(optarg);
813 break; 804 break;
814 805
815 /* Test parameters */ 806 /* Test parameters */
816 case 'c': /* critical threshold */ 807 case 'c': /* critical threshold */
817 critical_thresholds = optarg; 808 critical_thresholds = optarg;
818 break; 809 break;
819 case 'w': /* warning threshold */ 810 case 'w': /* warning threshold */
820 warning_thresholds = optarg; 811 warning_thresholds = optarg;
821 break; 812 break;
822 case 'e': /* PRELIMINARY - may change */ 813 case 'e': /* PRELIMINARY - may change */
823 case 'E': /* PRELIMINARY - may change */ 814 case 'E': /* PRELIMINARY - may change */
824 if (!is_integer (optarg)) 815 if (!is_integer(optarg))
825 usage2 (_("Retries interval must be a positive integer"), optarg); 816 usage2(_("Retries interval must be a positive integer"), optarg);
826 else 817 else
827 retries = atoi(optarg); 818 retries = atoi(optarg);
828 break; 819 break;
829 case 'o': /* object identifier */ 820 case 'o': /* object identifier */
830 if ( strspn( optarg, "0123456789.," ) != strlen( optarg ) ) { 821 if (strspn(optarg, "0123456789.,") != strlen(optarg)) {
831 /* 822 /*
832 * we have something other than digits, periods and comas, 823 * we have something other than digits, periods and comas,
833 * so we have a mib variable, rather than just an SNMP OID, 824 * so we have a mib variable, rather than just an SNMP OID,
834 * so we have to actually read the mib files 825 * so we have to actually read the mib files
835 */ 826 */
836 needmibs = true; 827 needmibs = true;
837 } 828 }
838 for (ptr = strtok(optarg, ", "); ptr != NULL; ptr = strtok(NULL, ", "), j++) { 829 for (char *ptr = strtok(optarg, ", "); ptr != NULL; ptr = strtok(NULL, ", "), j++) {
839 while (j >= oids_size) { 830 while (j >= oids_size) {
840 oids_size += OID_COUNT_STEP; 831 oids_size += OID_COUNT_STEP;
841 oids = realloc(oids, oids_size * sizeof (*oids)); 832 oids = realloc(oids, oids_size * sizeof(*oids));
842 } 833 }
843 oids[j] = strdup(ptr); 834 oids[j] = strdup(ptr);
844 } 835 }
845 numoids = j; 836 numoids = j;
846 if (c == 'E' || c == 'e') { 837 if (option_char == 'E' || option_char == 'e') {
847 jj++; 838 jj++;
848 while (j+1 >= eval_size) { 839 while (j + 1 >= eval_size) {
849 eval_size += OID_COUNT_STEP; 840 eval_size += OID_COUNT_STEP;
850 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method)); 841 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method));
851 memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8); 842 memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8);
852 } 843 }
853 if (c == 'E') 844 if (option_char == 'E')
854 eval_method[j+1] |= WARN_PRESENT; 845 eval_method[j + 1] |= WARN_PRESENT;
855 else if (c == 'e') 846 else if (option_char == 'e')
856 eval_method[j+1] |= CRIT_PRESENT; 847 eval_method[j + 1] |= CRIT_PRESENT;
857 } 848 }
858 break; 849 break;
859 case 'z': /* Null OID Return Check */ 850 case 'z': /* Null OID Return Check */
860 if (!is_integer (optarg)) 851 if (!is_integer(optarg))
861 usage2 (_("Exit status must be a positive integer"), optarg); 852 usage2(_("Exit status must be a positive integer"), optarg);
862 else 853 else
863 nulloid = atoi(optarg); 854 nulloid = atoi(optarg);
864 break; 855 break;
865 case 's': /* string or substring */ 856 case 's': /* string or substring */
866 strncpy (string_value, optarg, sizeof (string_value) - 1); 857 strncpy(string_value, optarg, sizeof(string_value) - 1);
867 string_value[sizeof (string_value) - 1] = 0; 858 string_value[sizeof(string_value) - 1] = 0;
868 while (jj >= eval_size) { 859 while (jj >= eval_size) {
869 eval_size += OID_COUNT_STEP; 860 eval_size += OID_COUNT_STEP;
870 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method)); 861 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method));
@@ -872,17 +863,17 @@ process_arguments (int argc, char **argv)
872 } 863 }
873 eval_method[jj++] = CRIT_STRING; 864 eval_method[jj++] = CRIT_STRING;
874 break; 865 break;
875 case 'R': /* regex */ 866 case 'R': /* regex */
876 cflags = REG_ICASE; 867 cflags = REG_ICASE;
877 // fall through 868 // fall through
878 case 'r': /* regex */ 869 case 'r': /* regex */
879 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 870 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
880 strncpy (regex_expect, optarg, sizeof (regex_expect) - 1); 871 strncpy(regex_expect, optarg, sizeof(regex_expect) - 1);
881 regex_expect[sizeof (regex_expect) - 1] = 0; 872 regex_expect[sizeof(regex_expect) - 1] = 0;
882 errcode = regcomp (&preg, regex_expect, cflags); 873 errcode = regcomp(&preg, regex_expect, cflags);
883 if (errcode != 0) { 874 if (errcode != 0) {
884 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 875 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
885 printf (_("Could Not Compile Regular Expression")); 876 printf(_("Could Not Compile Regular Expression"));
886 return ERROR; 877 return ERROR;
887 } 878 }
888 while (jj >= eval_size) { 879 while (jj >= eval_size) {
@@ -893,64 +884,64 @@ process_arguments (int argc, char **argv)
893 eval_method[jj++] = CRIT_REGEX; 884 eval_method[jj++] = CRIT_REGEX;
894 break; 885 break;
895 886
896 /* Format */ 887 /* Format */
897 case 'd': /* delimiter */ 888 case 'd': /* delimiter */
898 delimiter = strscpy (delimiter, optarg); 889 delimiter = strscpy(delimiter, optarg);
899 break; 890 break;
900 case 'D': /* output-delimiter */ 891 case 'D': /* output-delimiter */
901 output_delim = strscpy (output_delim, optarg); 892 output_delim = strscpy(output_delim, optarg);
902 break; 893 break;
903 case 'l': /* label */ 894 case 'l': /* label */
904 nlabels++; 895 nlabels++;
905 if (nlabels > labels_size) { 896 if (nlabels > labels_size) {
906 labels_size += 8; 897 labels_size += 8;
907 labels = realloc (labels, labels_size * sizeof(*labels)); 898 labels = realloc(labels, labels_size * sizeof(*labels));
908 if (labels == NULL) 899 if (labels == NULL)
909 die (STATE_UNKNOWN, _("Could not reallocate labels[%d]"), (int)nlabels); 900 die(STATE_UNKNOWN, _("Could not reallocate labels[%d]"), (int)nlabels);
910 } 901 }
911 labels[nlabels - 1] = optarg; 902 labels[nlabels - 1] = optarg;
912 ptr = thisarg (optarg); 903 char *ptr = thisarg(optarg);
913 labels[nlabels - 1] = ptr; 904 labels[nlabels - 1] = ptr;
914 if (ptr[0] == '\'') 905 if (ptr[0] == '\'')
915 labels[nlabels - 1] = ptr + 1; 906 labels[nlabels - 1] = ptr + 1;
916 while (ptr && (ptr = nextarg (ptr))) { 907 while (ptr && (ptr = nextarg(ptr))) {
917 nlabels++; 908 nlabels++;
918 if (nlabels > labels_size) { 909 if (nlabels > labels_size) {
919 labels_size += 8; 910 labels_size += 8;
920 labels = realloc (labels, labels_size * sizeof(*labels)); 911 labels = realloc(labels, labels_size * sizeof(*labels));
921 if (labels == NULL) 912 if (labels == NULL)
922 die (STATE_UNKNOWN, _("Could not reallocate labels\n")); 913 die(STATE_UNKNOWN, _("Could not reallocate labels\n"));
923 } 914 }
924 ptr = thisarg (ptr); 915 ptr = thisarg(ptr);
925 if (ptr[0] == '\'') 916 if (ptr[0] == '\'')
926 labels[nlabels - 1] = ptr + 1; 917 labels[nlabels - 1] = ptr + 1;
927 else 918 else
928 labels[nlabels - 1] = ptr; 919 labels[nlabels - 1] = ptr;
929 } 920 }
930 break; 921 break;
931 case 'u': /* units */ 922 case 'u': /* units */
932 units = optarg; 923 units = optarg;
933 nunits++; 924 nunits++;
934 if (nunits > unitv_size) { 925 if (nunits > unitv_size) {
935 unitv_size += 8; 926 unitv_size += 8;
936 unitv = realloc (unitv, unitv_size * sizeof(*unitv)); 927 unitv = realloc(unitv, unitv_size * sizeof(*unitv));
937 if (unitv == NULL) 928 if (unitv == NULL)
938 die (STATE_UNKNOWN, _("Could not reallocate units [%d]\n"), (int)nunits); 929 die(STATE_UNKNOWN, _("Could not reallocate units [%d]\n"), (int)nunits);
939 } 930 }
940 unitv[nunits - 1] = optarg; 931 unitv[nunits - 1] = optarg;
941 ptr = thisarg (optarg); 932 ptr = thisarg(optarg);
942 unitv[nunits - 1] = ptr; 933 unitv[nunits - 1] = ptr;
943 if (ptr[0] == '\'') 934 if (ptr[0] == '\'')
944 unitv[nunits - 1] = ptr + 1; 935 unitv[nunits - 1] = ptr + 1;
945 while (ptr && (ptr = nextarg (ptr))) { 936 while (ptr && (ptr = nextarg(ptr))) {
946 if (nunits > unitv_size) { 937 if (nunits > unitv_size) {
947 unitv_size += 8; 938 unitv_size += 8;
948 unitv = realloc (unitv, unitv_size * sizeof(*unitv)); 939 unitv = realloc(unitv, unitv_size * sizeof(*unitv));
949 if (units == NULL) 940 if (units == NULL)
950 die (STATE_UNKNOWN, _("Could not realloc() units\n")); 941 die(STATE_UNKNOWN, _("Could not realloc() units\n"));
951 } 942 }
952 nunits++; 943 nunits++;
953 ptr = thisarg (ptr); 944 ptr = thisarg(ptr);
954 if (ptr[0] == '\'') 945 if (ptr[0] == '\'')
955 unitv[nunits - 1] = ptr + 1; 946 unitv[nunits - 1] = ptr + 1;
956 else 947 else
@@ -958,38 +949,38 @@ process_arguments (int argc, char **argv)
958 } 949 }
959 break; 950 break;
960 case L_CALCULATE_RATE: 951 case L_CALCULATE_RATE:
961 if(calculate_rate==0) 952 if (calculate_rate == 0)
962 np_enable_state(NULL, 1); 953 np_enable_state(NULL, 1);
963 calculate_rate = 1; 954 calculate_rate = 1;
964 break; 955 break;
965 case L_RATE_MULTIPLIER: 956 case L_RATE_MULTIPLIER:
966 if(!is_integer(optarg)||((rate_multiplier=atoi(optarg))<=0)) 957 if (!is_integer(optarg) || ((rate_multiplier = atoi(optarg)) <= 0))
967 usage2(_("Rate multiplier must be a positive integer"),optarg); 958 usage2(_("Rate multiplier must be a positive integer"), optarg);
968 break; 959 break;
969 case L_OFFSET: 960 case L_OFFSET:
970 offset=strtod(optarg,NULL); 961 offset = strtod(optarg, NULL);
971 break; 962 break;
972 case L_INVERT_SEARCH: 963 case L_INVERT_SEARCH:
973 invert_search=1; 964 invert_search = 1;
974 break; 965 break;
975 case 'O': 966 case 'O':
976 perf_labels=0; 967 perf_labels = 0;
977 break; 968 break;
978 case '4': 969 case '4':
979 break; 970 break;
980 case '6': 971 case '6':
981 xasprintf(&ip_version, "udp6:"); 972 xasprintf(&ip_version, "udp6:");
982 if(verbose>2) 973 if (verbose > 2)
983 printf("IPv6 detected! Will pass \"udp6:\" to snmpget.\n"); 974 printf("IPv6 detected! Will pass \"udp6:\" to snmpget.\n");
984 break; 975 break;
985 case 'M': 976 case 'M':
986 if ( strspn( optarg, "0123456789.," ) == strlen( optarg ) ) { 977 if (strspn(optarg, "0123456789.,") == strlen(optarg)) {
987 multiplier=strtod(optarg,NULL); 978 multiplier = strtod(optarg, NULL);
988 } 979 }
989 break; 980 break;
990 case 'f': 981 case 'f':
991 if (multiplier != 1.0) { 982 if (multiplier != 1.0) {
992 fmtstr=optarg; 983 fmtstr = optarg;
993 fmtstr_set = true; 984 fmtstr_set = true;
994 } 985 }
995 break; 986 break;
@@ -1002,12 +993,11 @@ process_arguments (int argc, char **argv)
1002 server_address = argv[optind]; 993 server_address = argv[optind];
1003 994
1004 if (community == NULL) 995 if (community == NULL)
1005 community = strdup (DEFAULT_COMMUNITY); 996 community = strdup(DEFAULT_COMMUNITY);
1006 997
1007 return validate_arguments (); 998 return validate_arguments();
1008} 999}
1009 1000
1010
1011/****************************************************************************** 1001/******************************************************************************
1012 1002
1013@@- 1003@@-
@@ -1026,17 +1016,13 @@ selected.</para>
1026-@@ 1016-@@
1027******************************************************************************/ 1017******************************************************************************/
1028 1018
1029 1019static int validate_arguments() {
1030
1031static int
1032validate_arguments ()
1033{
1034 /* check whether to load locally installed MIBS (CPU/disk intensive) */ 1020 /* check whether to load locally installed MIBS (CPU/disk intensive) */
1035 if (miblist == NULL) { 1021 if (miblist == NULL) {
1036 if (needmibs) { 1022 if (needmibs) {
1037 miblist = strdup (DEFAULT_MIBLIST); 1023 miblist = strdup(DEFAULT_MIBLIST);
1038 }else{ 1024 } else {
1039 miblist = ""; /* don't read any mib files for numeric oids */ 1025 miblist = ""; /* don't read any mib files for numeric oids */
1040 } 1026 }
1041 } 1027 }
1042 1028
@@ -1051,18 +1037,17 @@ validate_arguments ()
1051 if (proto == NULL) 1037 if (proto == NULL)
1052 xasprintf(&proto, DEFAULT_PROTOCOL); 1038 xasprintf(&proto, DEFAULT_PROTOCOL);
1053 1039
1054 if ((strcmp(proto,"1") == 0) || (strcmp(proto, "2c")==0)) { /* snmpv1 or snmpv2c */ 1040 if ((strcmp(proto, "1") == 0) || (strcmp(proto, "2c") == 0)) { /* snmpv1 or snmpv2c */
1055 numauthpriv = 2; 1041 numauthpriv = 2;
1056 authpriv = calloc (numauthpriv, sizeof (char *)); 1042 authpriv = calloc(numauthpriv, sizeof(char *));
1057 authpriv[0] = strdup ("-c"); 1043 authpriv[0] = strdup("-c");
1058 authpriv[1] = strdup (community); 1044 authpriv[1] = strdup(community);
1059 } 1045 } else if (strcmp(proto, "3") == 0) { /* snmpv3 args */
1060 else if ( strcmp (proto, "3") == 0 ) { /* snmpv3 args */
1061 if (!(context == NULL)) { 1046 if (!(context == NULL)) {
1062 numcontext = 2; 1047 numcontext = 2;
1063 contextargs = calloc (numcontext, sizeof (char *)); 1048 contextargs = calloc(numcontext, sizeof(char *));
1064 contextargs[0] = strdup ("-n"); 1049 contextargs[0] = strdup("-n");
1065 contextargs[1] = strdup (context); 1050 contextargs[1] = strdup(context);
1066 } 1051 }
1067 1052
1068 if (seclevel == NULL) 1053 if (seclevel == NULL)
@@ -1073,284 +1058,266 @@ validate_arguments ()
1073 1058
1074 if (strcmp(seclevel, "noAuthNoPriv") == 0) { 1059 if (strcmp(seclevel, "noAuthNoPriv") == 0) {
1075 numauthpriv = 4; 1060 numauthpriv = 4;
1076 authpriv = calloc (numauthpriv, sizeof (char *)); 1061 authpriv = calloc(numauthpriv, sizeof(char *));
1077 authpriv[0] = strdup ("-l"); 1062 authpriv[0] = strdup("-l");
1078 authpriv[1] = strdup ("noAuthNoPriv"); 1063 authpriv[1] = strdup("noAuthNoPriv");
1079 authpriv[2] = strdup ("-u"); 1064 authpriv[2] = strdup("-u");
1080 authpriv[3] = strdup (secname); 1065 authpriv[3] = strdup(secname);
1081 } else { 1066 } else {
1082 if (! ( (strcmp(seclevel, "authNoPriv")==0) || (strcmp(seclevel, "authPriv")==0) ) ) { 1067 if (!((strcmp(seclevel, "authNoPriv") == 0) || (strcmp(seclevel, "authPriv") == 0))) {
1083 usage2 (_("Invalid seclevel"), seclevel); 1068 usage2(_("Invalid seclevel"), seclevel);
1084 } 1069 }
1085 1070
1086 if (authproto == NULL ) 1071 if (authproto == NULL)
1087 xasprintf(&authproto, DEFAULT_AUTH_PROTOCOL); 1072 xasprintf(&authproto, DEFAULT_AUTH_PROTOCOL);
1088 1073
1089 if (authpasswd == NULL) 1074 if (authpasswd == NULL)
1090 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "authpasswd"); 1075 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "authpasswd");
1091 1076
1092 if ( strcmp(seclevel, "authNoPriv") == 0 ) { 1077 if (strcmp(seclevel, "authNoPriv") == 0) {
1093 numauthpriv = 8; 1078 numauthpriv = 8;
1094 authpriv = calloc (numauthpriv, sizeof (char *)); 1079 authpriv = calloc(numauthpriv, sizeof(char *));
1095 authpriv[0] = strdup ("-l"); 1080 authpriv[0] = strdup("-l");
1096 authpriv[1] = strdup ("authNoPriv"); 1081 authpriv[1] = strdup("authNoPriv");
1097 authpriv[2] = strdup ("-a"); 1082 authpriv[2] = strdup("-a");
1098 authpriv[3] = strdup (authproto); 1083 authpriv[3] = strdup(authproto);
1099 authpriv[4] = strdup ("-u"); 1084 authpriv[4] = strdup("-u");
1100 authpriv[5] = strdup (secname); 1085 authpriv[5] = strdup(secname);
1101 authpriv[6] = strdup ("-A"); 1086 authpriv[6] = strdup("-A");
1102 authpriv[7] = strdup (authpasswd); 1087 authpriv[7] = strdup(authpasswd);
1103 } else if ( strcmp(seclevel, "authPriv") == 0 ) { 1088 } else if (strcmp(seclevel, "authPriv") == 0) {
1104 if (privproto == NULL ) 1089 if (privproto == NULL)
1105 xasprintf(&privproto, DEFAULT_PRIV_PROTOCOL); 1090 xasprintf(&privproto, DEFAULT_PRIV_PROTOCOL);
1106 1091
1107 if (privpasswd == NULL) 1092 if (privpasswd == NULL)
1108 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "privpasswd"); 1093 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "privpasswd");
1109 1094
1110 numauthpriv = 12; 1095 numauthpriv = 12;
1111 authpriv = calloc (numauthpriv, sizeof (char *)); 1096 authpriv = calloc(numauthpriv, sizeof(char *));
1112 authpriv[0] = strdup ("-l"); 1097 authpriv[0] = strdup("-l");
1113 authpriv[1] = strdup ("authPriv"); 1098 authpriv[1] = strdup("authPriv");
1114 authpriv[2] = strdup ("-a"); 1099 authpriv[2] = strdup("-a");
1115 authpriv[3] = strdup (authproto); 1100 authpriv[3] = strdup(authproto);
1116 authpriv[4] = strdup ("-u"); 1101 authpriv[4] = strdup("-u");
1117 authpriv[5] = strdup (secname); 1102 authpriv[5] = strdup(secname);
1118 authpriv[6] = strdup ("-A"); 1103 authpriv[6] = strdup("-A");
1119 authpriv[7] = strdup (authpasswd); 1104 authpriv[7] = strdup(authpasswd);
1120 authpriv[8] = strdup ("-x"); 1105 authpriv[8] = strdup("-x");
1121 authpriv[9] = strdup (privproto); 1106 authpriv[9] = strdup(privproto);
1122 authpriv[10] = strdup ("-X"); 1107 authpriv[10] = strdup("-X");
1123 authpriv[11] = strdup (privpasswd); 1108 authpriv[11] = strdup(privpasswd);
1124 } 1109 }
1125 } 1110 }
1126 1111
1127 } 1112 } else {
1128 else { 1113 usage2(_("Invalid SNMP version"), proto);
1129 usage2 (_("Invalid SNMP version"), proto);
1130 } 1114 }
1131 1115
1132 return OK; 1116 return OK;
1133} 1117}
1134 1118
1135
1136
1137/* trim leading whitespace 1119/* trim leading whitespace
1138 if there is a leading quote, make sure it balances */ 1120 if there is a leading quote, make sure it balances */
1139 1121
1140static char * 1122static char *thisarg(char *str) {
1141thisarg (char *str) 1123 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */
1142{ 1124 if (str[0] == '\'') { /* handle SIMPLE quoted strings */
1143 str += strspn (str, " \t\r\n"); /* trim any leading whitespace */ 1125 if (strlen(str) == 1 || !strstr(str + 1, "'"))
1144 if (str[0] == '\'') { /* handle SIMPLE quoted strings */ 1126 die(STATE_UNKNOWN, _("Unbalanced quotes\n"));
1145 if (strlen (str) == 1 || !strstr (str + 1, "'"))
1146 die (STATE_UNKNOWN, _("Unbalanced quotes\n"));
1147 } 1127 }
1148 return str; 1128 return str;
1149} 1129}
1150 1130
1151
1152
1153/* if there's a leading quote, advance to the trailing quote 1131/* if there's a leading quote, advance to the trailing quote
1154 set the trailing quote to '\x0' 1132 set the trailing quote to '\x0'
1155 if the string continues, advance beyond the comma */ 1133 if the string continues, advance beyond the comma */
1156 1134
1157static char * 1135static char *nextarg(char *str) {
1158nextarg (char *str)
1159{
1160 if (str[0] == '\'') { 1136 if (str[0] == '\'') {
1161 str[0] = 0; 1137 str[0] = 0;
1162 if (strlen (str) > 1) { 1138 if (strlen(str) > 1) {
1163 str = strstr (str + 1, "'"); 1139 str = strstr(str + 1, "'");
1164 return (++str); 1140 return (++str);
1165 } 1141 } else {
1166 else {
1167 return NULL; 1142 return NULL;
1168 } 1143 }
1169 } 1144 }
1170 if (str[0] == ',') { 1145 if (str[0] == ',') {
1171 str[0] = 0; 1146 str[0] = 0;
1172 if (strlen (str) > 1) { 1147 if (strlen(str) > 1) {
1173 return (++str); 1148 return (++str);
1174 } 1149 } else {
1175 else {
1176 return NULL; 1150 return NULL;
1177 } 1151 }
1178 } 1152 }
1179 if ((str = strstr (str, ",")) && strlen (str) > 1) { 1153 if ((str = strstr(str, ",")) && strlen(str) > 1) {
1180 str[0] = 0; 1154 str[0] = 0;
1181 return (++str); 1155 return (++str);
1182 } 1156 }
1183 return NULL; 1157 return NULL;
1184} 1158}
1185 1159
1186
1187
1188/* multiply result (values 0 < n < 1 work as divider) */ 1160/* multiply result (values 0 < n < 1 work as divider) */
1189static char * 1161static char *multiply(char *str) {
1190multiply (char *str) 1162 if (multiplier == 1)
1191{ 1163 return (str);
1192 char *endptr;
1193 double val;
1194 char *conv = "%f";
1195
1196 if(multiplier == 1)
1197 return(str);
1198 1164
1199 if(verbose>2) 1165 if (verbose > 2)
1200 printf(" multiply input: %s\n", str); 1166 printf(" multiply input: %s\n", str);
1201 1167
1202 val = strtod (str, &endptr); 1168 char *endptr;
1169 double val = strtod(str, &endptr);
1203 if ((val == 0.0) && (endptr == str)) { 1170 if ((val == 0.0) && (endptr == str)) {
1204 die(STATE_UNKNOWN, _("multiplier set (%.1f), but input is not a number: %s"), multiplier, str); 1171 die(STATE_UNKNOWN, _("multiplier set (%.1f), but input is not a number: %s"), multiplier, str);
1205 } 1172 }
1206 1173
1207 if(verbose>2) 1174 if (verbose > 2)
1208 printf(" multiply extracted double: %f\n", val); 1175 printf(" multiply extracted double: %f\n", val);
1176
1209 val *= multiplier; 1177 val *= multiplier;
1178 char *conv = "%f";
1210 if (fmtstr_set) { 1179 if (fmtstr_set) {
1211 conv = fmtstr; 1180 conv = fmtstr;
1212 } 1181 }
1213 if (val == (int)val) { 1182 if (val == (int)val) {
1214 snprintf(buffer, DEFAULT_BUFFER_SIZE, "%.0f", val); 1183 snprintf(buffer, DEFAULT_BUFFER_SIZE, "%.0f", val);
1215 } else { 1184 } else {
1216 if(verbose>2) 1185 if (verbose > 2)
1217 printf(" multiply using format: %s\n", conv); 1186 printf(" multiply using format: %s\n", conv);
1218 snprintf(buffer, DEFAULT_BUFFER_SIZE, conv, val); 1187 snprintf(buffer, DEFAULT_BUFFER_SIZE, conv, val);
1219 } 1188 }
1220 if(verbose>2) 1189 if (verbose > 2)
1221 printf(" multiply result: %s\n", buffer); 1190 printf(" multiply result: %s\n", buffer);
1222 return buffer; 1191 return buffer;
1223} 1192}
1224 1193
1194static void print_help(void) {
1195 print_revision(progname, NP_VERSION);
1225 1196
1226static void 1197 printf(COPYRIGHT, copyright, email);
1227print_help (void)
1228{
1229 print_revision (progname, NP_VERSION);
1230
1231 printf (COPYRIGHT, copyright, email);
1232 1198
1233 printf ("%s\n", _("Check status of remote machines and obtain system information via SNMP")); 1199 printf("%s\n", _("Check status of remote machines and obtain system information via SNMP"));
1234 1200
1235 printf ("\n\n"); 1201 printf("\n\n");
1236 1202
1237 print_usage (); 1203 print_usage();
1238 1204
1239 printf (UT_HELP_VRSN); 1205 printf(UT_HELP_VRSN);
1240 printf (UT_EXTRA_OPTS); 1206 printf(UT_EXTRA_OPTS);
1241 printf (UT_IPv46); 1207 printf(UT_IPv46);
1242 1208
1243 printf (UT_HOST_PORT, 'p', DEFAULT_PORT); 1209 printf(UT_HOST_PORT, 'p', DEFAULT_PORT);
1244 1210
1245 /* SNMP and Authentication Protocol */ 1211 /* SNMP and Authentication Protocol */
1246 printf (" %s\n", "-n, --next"); 1212 printf(" %s\n", "-n, --next");
1247 printf (" %s\n", _("Use SNMP GETNEXT instead of SNMP GET")); 1213 printf(" %s\n", _("Use SNMP GETNEXT instead of SNMP GET"));
1248 printf (" %s\n", "-P, --protocol=[1|2c|3]"); 1214 printf(" %s\n", "-P, --protocol=[1|2c|3]");
1249 printf (" %s\n", _("SNMP protocol version")); 1215 printf(" %s\n", _("SNMP protocol version"));
1250 printf (" %s\n", "-N, --context=CONTEXT"); 1216 printf(" %s\n", "-N, --context=CONTEXT");
1251 printf (" %s\n", _("SNMPv3 context")); 1217 printf(" %s\n", _("SNMPv3 context"));
1252 printf (" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]"); 1218 printf(" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]");
1253 printf (" %s\n", _("SNMPv3 securityLevel")); 1219 printf(" %s\n", _("SNMPv3 securityLevel"));
1254 printf (" %s\n", "-a, --authproto=AUTHENTICATION_PROTOCOL"); 1220 printf(" %s\n", "-a, --authproto=AUTHENTICATION_PROTOCOL");
1255 printf (" %s\n", _("SNMPv3 authentication protocol (default MD5), available options depend on the specific version of the net-snmp tools")); 1221 printf(" %s\n",
1256 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")); 1222 _("SNMPv3 authentication protocol (default MD5), available options depend on the specific version of the net-snmp tools"));
1257 printf (" %s\n", "-x, --privproto=PRIVACY_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"));
1258 printf (" %s\n", _("SNMPv3 privacy protocol (default DES), available options depend on the specific version of the net-snmp tools")); 1224 printf(" %s\n", "-x, --privproto=PRIVACY_PROTOCOL");
1259 printf (" %s\n", _("if < 5.8 DES and AES should be available, if >= 5.8 additionally AES-192 and AES-256")); 1225 printf(" %s\n", _("SNMPv3 privacy protocol (default DES), available options depend on the specific version of the net-snmp tools"));
1226 printf(" %s\n", _("if < 5.8 DES and AES should be available, if >= 5.8 additionally AES-192 and AES-256"));
1260 1227
1261 /* Authentication Tokens*/ 1228 /* Authentication Tokens*/
1262 printf (" %s\n", "-C, --community=STRING"); 1229 printf(" %s\n", "-C, --community=STRING");
1263 printf (" %s ", _("Optional community string for SNMP communication")); 1230 printf(" %s ", _("Optional community string for SNMP communication"));
1264 printf ("(%s \"%s\")\n", _("default is") ,DEFAULT_COMMUNITY); 1231 printf("(%s \"%s\")\n", _("default is"), DEFAULT_COMMUNITY);
1265 printf (" %s\n", "-U, --secname=USERNAME"); 1232 printf(" %s\n", "-U, --secname=USERNAME");
1266 printf (" %s\n", _("SNMPv3 username")); 1233 printf(" %s\n", _("SNMPv3 username"));
1267 printf (" %s\n", "-A, --authpasswd=PASSWORD"); 1234 printf(" %s\n", "-A, --authpasswd=PASSWORD");
1268 printf (" %s\n", _("SNMPv3 authentication password")); 1235 printf(" %s\n", _("SNMPv3 authentication password"));
1269 printf (" %s\n", "-X, --privpasswd=PASSWORD"); 1236 printf(" %s\n", "-X, --privpasswd=PASSWORD");
1270 printf (" %s\n", _("SNMPv3 privacy password")); 1237 printf(" %s\n", _("SNMPv3 privacy password"));
1271 1238
1272 /* OID Stuff */ 1239 /* OID Stuff */
1273 printf (" %s\n", "-o, --oid=OID(s)"); 1240 printf(" %s\n", "-o, --oid=OID(s)");
1274 printf (" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query")); 1241 printf(" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query"));
1275 printf (" %s\n", "-m, --miblist=STRING"); 1242 printf(" %s\n", "-m, --miblist=STRING");
1276 printf (" %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'")); 1243 printf(" %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'"));
1277 printf (" %s\n", _("for symbolic OIDs.)")); 1244 printf(" %s\n", _("for symbolic OIDs.)"));
1278 printf (" %s\n", "-d, --delimiter=STRING"); 1245 printf(" %s\n", "-d, --delimiter=STRING");
1279 printf (" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER); 1246 printf(" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER);
1280 printf (" %s\n", _("Any data on the right hand side of the delimiter is considered")); 1247 printf(" %s\n", _("Any data on the right hand side of the delimiter is considered"));
1281 printf (" %s\n", _("to be the data that should be used in the evaluation.")); 1248 printf(" %s\n", _("to be the data that should be used in the evaluation."));
1282 printf (" %s\n", "-z, --nulloid=#"); 1249 printf(" %s\n", "-z, --nulloid=#");
1283 printf (" %s\n", _("If the check returns a 0 length string or NULL value")); 1250 printf(" %s\n", _("If the check returns a 0 length string or NULL value"));
1284 printf (" %s\n", _("This option allows you to choose what status you want it to exit")); 1251 printf(" %s\n", _("This option allows you to choose what status you want it to exit"));
1285 printf (" %s\n", _("Excluding this option renders the default exit of 3(STATE_UNKNOWN)")); 1252 printf(" %s\n", _("Excluding this option renders the default exit of 3(STATE_UNKNOWN)"));
1286 printf (" %s\n", _("0 = OK")); 1253 printf(" %s\n", _("0 = OK"));
1287 printf (" %s\n", _("1 = WARNING")); 1254 printf(" %s\n", _("1 = WARNING"));
1288 printf (" %s\n", _("2 = CRITICAL")); 1255 printf(" %s\n", _("2 = CRITICAL"));
1289 printf (" %s\n", _("3 = UNKNOWN")); 1256 printf(" %s\n", _("3 = UNKNOWN"));
1290 1257
1291 /* Tests Against Integers */ 1258 /* Tests Against Integers */
1292 printf (" %s\n", "-w, --warning=THRESHOLD(s)"); 1259 printf(" %s\n", "-w, --warning=THRESHOLD(s)");
1293 printf (" %s\n", _("Warning threshold range(s)")); 1260 printf(" %s\n", _("Warning threshold range(s)"));
1294 printf (" %s\n", "-c, --critical=THRESHOLD(s)"); 1261 printf(" %s\n", "-c, --critical=THRESHOLD(s)");
1295 printf (" %s\n", _("Critical threshold range(s)")); 1262 printf(" %s\n", _("Critical threshold range(s)"));
1296 printf (" %s\n", "--rate"); 1263 printf(" %s\n", "--rate");
1297 printf (" %s\n", _("Enable rate calculation. See 'Rate Calculation' below")); 1264 printf(" %s\n", _("Enable rate calculation. See 'Rate Calculation' below"));
1298 printf (" %s\n", "--rate-multiplier"); 1265 printf(" %s\n", "--rate-multiplier");
1299 printf (" %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute")); 1266 printf(" %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute"));
1300 printf (" %s\n", "--offset=OFFSET"); 1267 printf(" %s\n", "--offset=OFFSET");
1301 printf (" %s\n", _("Add/subtract the specified OFFSET to numeric sensor data")); 1268 printf(" %s\n", _("Add/subtract the specified OFFSET to numeric sensor data"));
1302 1269
1303 /* Tests Against Strings */ 1270 /* Tests Against Strings */
1304 printf (" %s\n", "-s, --string=STRING"); 1271 printf(" %s\n", "-s, --string=STRING");
1305 printf (" %s\n", _("Return OK state (for that OID) if STRING is an exact match")); 1272 printf(" %s\n", _("Return OK state (for that OID) if STRING is an exact match"));
1306 printf (" %s\n", "-r, --ereg=REGEX"); 1273 printf(" %s\n", "-r, --ereg=REGEX");
1307 printf (" %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches")); 1274 printf(" %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches"));
1308 printf (" %s\n", "-R, --eregi=REGEX"); 1275 printf(" %s\n", "-R, --eregi=REGEX");
1309 printf (" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches")); 1276 printf(" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches"));
1310 printf (" %s\n", "--invert-search"); 1277 printf(" %s\n", "--invert-search");
1311 printf (" %s\n", _("Invert search result (CRITICAL if found)")); 1278 printf(" %s\n", _("Invert search result (CRITICAL if found)"));
1312 1279
1313 /* Output Formatting */ 1280 /* Output Formatting */
1314 printf (" %s\n", "-l, --label=STRING"); 1281 printf(" %s\n", "-l, --label=STRING");
1315 printf (" %s\n", _("Prefix label for output from plugin")); 1282 printf(" %s\n", _("Prefix label for output from plugin"));
1316 printf (" %s\n", "-u, --units=STRING"); 1283 printf(" %s\n", "-u, --units=STRING");
1317 printf (" %s\n", _("Units label(s) for output data (e.g., 'sec.').")); 1284 printf(" %s\n", _("Units label(s) for output data (e.g., 'sec.')."));
1318 printf (" %s\n", "-D, --output-delimiter=STRING"); 1285 printf(" %s\n", "-D, --output-delimiter=STRING");
1319 printf (" %s\n", _("Separates output on multiple OID requests")); 1286 printf(" %s\n", _("Separates output on multiple OID requests"));
1320 printf (" %s\n", "-M, --multiplier=FLOAT"); 1287 printf(" %s\n", "-M, --multiplier=FLOAT");
1321 printf (" %s\n", _("Multiplies current value, 0 < n < 1 works as divider, defaults to 1")); 1288 printf(" %s\n", _("Multiplies current value, 0 < n < 1 works as divider, defaults to 1"));
1322 printf (" %s\n", "-f, --fmtstr=STRING"); 1289 printf(" %s\n", "-f, --fmtstr=STRING");
1323 printf (" %s\n", _("C-style format string for float values (see option -M)")); 1290 printf(" %s\n", _("C-style format string for float values (see option -M)"));
1324 1291
1325 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 1292 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1326 printf (" %s\n", _("NOTE the final timeout value is calculated using this formula: timeout_interval * retries + 5")); 1293 printf(" %s\n", _("NOTE the final timeout value is calculated using this formula: timeout_interval * retries + 5"));
1327 printf (" %s\n", "-e, --retries=INTEGER"); 1294 printf(" %s\n", "-e, --retries=INTEGER");
1328 printf (" %s%i\n", _("Number of retries to be used in the requests, default: "), DEFAULT_RETRIES); 1295 printf(" %s%i\n", _("Number of retries to be used in the requests, default: "), DEFAULT_RETRIES);
1329 1296
1330 printf (" %s\n", "-O, --perf-oids"); 1297 printf(" %s\n", "-O, --perf-oids");
1331 printf (" %s\n", _("Label performance data with OIDs instead of --label's")); 1298 printf(" %s\n", _("Label performance data with OIDs instead of --label's"));
1332 1299
1333 printf (" %s\n", "--ignore-mib-parsing-errors"); 1300 printf(" %s\n", "--ignore-mib-parsing-errors");
1334 printf (" %s\n", _("Tell snmpget to not print errors encountered when parsing MIB files")); 1301 printf(" %s\n", _("Tell snmpget to not print errors encountered when parsing MIB files"));
1335 1302
1336 printf (UT_VERBOSE); 1303 printf(UT_VERBOSE);
1337 1304
1338 printf ("\n"); 1305 printf("\n");
1339 printf ("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package.")); 1306 printf("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package."));
1340 printf ("%s\n", _("if you don't have the package installed, you will need to download it from")); 1307 printf("%s\n", _("if you don't have the package installed, you will need to download it from"));
1341 printf ("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin.")); 1308 printf("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin."));
1342 1309
1343 printf ("\n"); 1310 printf("\n");
1344 printf ("%s\n", _("Notes:")); 1311 printf("%s\n", _("Notes:"));
1345 printf (" %s\n", _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited ")); 1312 printf(" %s\n", _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited "));
1346 printf (" %s\n", _("list (lists with internal spaces must be quoted).")); 1313 printf(" %s\n", _("list (lists with internal spaces must be quoted)."));
1347 1314
1348 printf(" -%s", UT_THRESHOLDS_NOTES); 1315 printf(" -%s", UT_THRESHOLDS_NOTES);
1349 1316
1350 printf (" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'")); 1317 printf(" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'"));
1351 printf (" %s\n", _("- Note that only one string and one regex may be checked at present")); 1318 printf(" %s\n", _("- Note that only one string and one regex may be checked at present"));
1352 printf (" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value")); 1319 printf(" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value"));
1353 printf (" %s\n", _("returned from the SNMP query is an unsigned integer.")); 1320 printf(" %s\n", _("returned from the SNMP query is an unsigned integer."));
1354 1321
1355 printf("\n"); 1322 printf("\n");
1356 printf("%s\n", _("Rate Calculation:")); 1323 printf("%s\n", _("Rate Calculation:"));
@@ -1362,19 +1329,15 @@ print_help (void)
1362 printf(" %s\n", _("The state is uniquely determined by the arguments to the plugin, so")); 1329 printf(" %s\n", _("The state is uniquely determined by the arguments to the plugin, so"));
1363 printf(" %s\n", _("changing the arguments will create a new state file.")); 1330 printf(" %s\n", _("changing the arguments will create a new state file."));
1364 1331
1365 printf (UT_SUPPORT); 1332 printf(UT_SUPPORT);
1366} 1333}
1367 1334
1368 1335void print_usage(void) {
1369 1336 printf("%s\n", _("Usage:"));
1370void 1337 printf("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n", progname);
1371print_usage (void) 1338 printf("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n");
1372{ 1339 printf("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
1373 printf ("%s\n", _("Usage:")); 1340 printf("[-m miblist] [-P snmp version] [-N context] [-L seclevel] [-U secname]\n");
1374 printf ("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n",progname); 1341 printf("[-a authproto] [-A authpasswd] [-x privproto] [-X privpasswd] [-4|6]\n");
1375 printf ("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n"); 1342 printf("[-M multiplier [-f format]]\n");
1376 printf ("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
1377 printf ("[-m miblist] [-P snmp version] [-N context] [-L seclevel] [-U secname]\n");
1378 printf ("[-a authproto] [-A authpasswd] [-x privproto] [-X privpasswd] [-4|6]\n");
1379 printf ("[-M multiplier [-f format]]\n");
1380} 1343}
diff --git a/plugins/check_ssh.c b/plugins/check_ssh.c
index 34ef37b7..9d0d7cde 100644
--- a/plugins/check_ssh.c
+++ b/plugins/check_ssh.c
@@ -1,144 +1,158 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_ssh plugin 3 * Monitoring check_ssh plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2007 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_ssh plugin 10 * This file contains the check_ssh plugin
11* 11 *
12* Try to connect to an SSH server at specified server and port 12 * Try to connect to an SSH server at specified server and port
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#include "output.h"
32#include "perfdata.h"
33#include "states.h"
31const char *progname = "check_ssh"; 34const char *progname = "check_ssh";
32const char *copyright = "2000-2007"; 35const char *copyright = "2000-2024";
33const char *email = "devel@monitoring-plugins.org"; 36const char *email = "devel@monitoring-plugins.org";
34 37
35#include "./common.h" 38#include "./common.h"
36#include "./netutils.h" 39#include "./netutils.h"
37#include "utils.h" 40#include "utils.h"
41#include "./check_ssh.d/config.h"
38 42
39#ifndef MSG_DONTWAIT 43#ifndef MSG_DONTWAIT
40#define MSG_DONTWAIT 0 44# define MSG_DONTWAIT 0
41#endif 45#endif
42 46
43#define SSH_DFL_PORT 22 47#define BUFF_SZ 256
44#define BUFF_SZ 256
45
46int port = -1;
47char *server_name = NULL;
48char *remote_version = NULL;
49char *remote_protocol = NULL;
50bool verbose = false;
51 48
52int process_arguments (int, char **); 49static bool verbose = false;
53int validate_arguments (void);
54void print_help (void);
55void print_usage (void);
56 50
57int ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol); 51typedef struct process_arguments_wrapper {
52 int errorcode;
53 check_ssh_config config;
54} process_arguments_wrapper;
58 55
56static process_arguments_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
57static void print_help(void);
58void print_usage(void);
59 59
60int 60static int ssh_connect(mp_check *overall, char *haddr, int hport, char *remote_version, char *remote_protocol);
61main (int argc, char **argv)
62{
63 int result = STATE_UNKNOWN;
64 61
65 setlocale (LC_ALL, ""); 62int main(int argc, char **argv) {
66 bindtextdomain (PACKAGE, LOCALEDIR); 63 setlocale(LC_ALL, "");
67 textdomain (PACKAGE); 64 bindtextdomain(PACKAGE, LOCALEDIR);
65 textdomain(PACKAGE);
68 66
69 /* Parse extra opts if any */ 67 /* Parse extra opts if any */
70 argv=np_extra_opts (&argc, argv, progname); 68 argv = np_extra_opts(&argc, argv, progname);
71 69
72 if (process_arguments (argc, argv) == ERROR) 70 process_arguments_wrapper tmp_config = process_arguments(argc, argv);
73 usage4 (_("Could not parse arguments"));
74 71
75 /* initialize alarm signal handling */ 72 if (tmp_config.errorcode == ERROR) {
76 signal (SIGALRM, socket_timeout_alarm_handler); 73 usage4(_("Could not parse arguments"));
74 }
75
76 check_ssh_config config = tmp_config.config;
77
78 mp_check overall = mp_check_init();
79 if (config.output_format_is_set) {
80 mp_set_format(config.output_format);
81 }
77 82
78 alarm (socket_timeout); 83 /* initialize alarm signal handling */
84 signal(SIGALRM, socket_timeout_alarm_handler);
85 alarm(socket_timeout);
79 86
80 /* ssh_connect exits if error is found */ 87 /* ssh_connect exits if error is found */
81 result = ssh_connect (server_name, port, remote_version, remote_protocol); 88 ssh_connect(&overall, config.server_name, config.port, config.remote_version, config.remote_protocol);
82 89
83 alarm (0); 90 alarm(0);
84 91
85 return (result); 92 mp_exit(overall);
86} 93}
87 94
88 95#define output_format_index CHAR_MAX + 1
89 96
90/* process command-line arguments */ 97/* process command-line arguments */
91int 98process_arguments_wrapper process_arguments(int argc, char **argv) {
92process_arguments (int argc, char **argv) 99 static struct option longopts[] = {{"help", no_argument, 0, 'h'},
93{ 100 {"version", no_argument, 0, 'V'},
94 int c; 101 {"host", required_argument, 0, 'H'}, /* backward compatibility */
95 102 {"hostname", required_argument, 0, 'H'},
96 int option = 0; 103 {"port", required_argument, 0, 'p'},
97 static struct option longopts[] = { 104 {"use-ipv4", no_argument, 0, '4'},
98 {"help", no_argument, 0, 'h'}, 105 {"use-ipv6", no_argument, 0, '6'},
99 {"version", no_argument, 0, 'V'}, 106 {"timeout", required_argument, 0, 't'},
100 {"host", required_argument, 0, 'H'}, /* backward compatibility */ 107 {"verbose", no_argument, 0, 'v'},
101 {"hostname", required_argument, 0, 'H'}, 108 {"remote-version", required_argument, 0, 'r'},
102 {"port", required_argument, 0, 'p'}, 109 {"remote-protocol", required_argument, 0, 'P'},
103 {"use-ipv4", no_argument, 0, '4'}, 110 {"output-format", required_argument, 0, output_format_index},
104 {"use-ipv6", no_argument, 0, '6'}, 111 {0, 0, 0, 0}};
105 {"timeout", required_argument, 0, 't'}, 112
106 {"verbose", no_argument, 0, 'v'}, 113 process_arguments_wrapper result = {
107 {"remote-version", required_argument, 0, 'r'}, 114 .config = check_ssh_config_init(),
108 {"remote-protocol", required_argument, 0, 'P'}, 115 .errorcode = OK,
109 {0, 0, 0, 0}
110 }; 116 };
111 117
112 if (argc < 2) 118 if (argc < 2) {
113 return ERROR; 119 result.errorcode = ERROR;
120 return result;
121 }
114 122
115 for (c = 1; c < argc; c++) 123 for (int i = 1; i < argc; i++) {
116 if (strcmp ("-to", argv[c]) == 0) 124 if (strcmp("-to", argv[i]) == 0) {
117 strcpy (argv[c], "-t"); 125 strcpy(argv[i], "-t");
126 }
127 }
118 128
119 while (1) { 129 int option_char;
120 c = getopt_long (argc, argv, "+Vhv46t:r:H:p:P:", longopts, &option); 130 while (true) {
131 int option = 0;
132 option_char = getopt_long(argc, argv, "+Vhv46t:r:H:p:P:", longopts, &option);
121 133
122 if (c == -1 || c == EOF) 134 if (option_char == -1 || option_char == EOF) {
123 break; 135 break;
136 }
124 137
125 switch (c) { 138 switch (option_char) {
126 case '?': /* help */ 139 case '?': /* help */
127 usage5 (); 140 usage5();
128 case 'V': /* version */ 141 case 'V': /* version */
129 print_revision (progname, NP_VERSION); 142 print_revision(progname, NP_VERSION);
130 exit (STATE_UNKNOWN); 143 exit(STATE_UNKNOWN);
131 case 'h': /* help */ 144 case 'h': /* help */
132 print_help (); 145 print_help();
133 exit (STATE_UNKNOWN); 146 exit(STATE_UNKNOWN);
134 case 'v': /* verbose */ 147 case 'v': /* verbose */
135 verbose = true; 148 verbose = true;
136 break; 149 break;
137 case 't': /* timeout period */ 150 case 't': /* timeout period */
138 if (!is_integer (optarg)) 151 if (!is_intpos(optarg)) {
139 usage2 (_("Timeout interval must be a positive integer"), optarg); 152 usage2(_("Timeout interval must be a positive integer"), optarg);
140 else 153 } else {
141 socket_timeout = atoi (optarg); 154 socket_timeout = (unsigned int)atoi(optarg);
155 }
142 break; 156 break;
143 case '4': 157 case '4':
144 address_family = AF_INET; 158 address_family = AF_INET;
@@ -147,121 +161,121 @@ process_arguments (int argc, char **argv)
147#ifdef USE_IPV6 161#ifdef USE_IPV6
148 address_family = AF_INET6; 162 address_family = AF_INET6;
149#else 163#else
150 usage4 (_("IPv6 support not available")); 164 usage4(_("IPv6 support not available"));
151#endif 165#endif
152 break; 166 break;
153 case 'r': /* remote version */ 167 case 'r': /* remote version */
154 remote_version = optarg; 168 result.config.remote_version = optarg;
155 break; 169 break;
156 case 'P': /* remote version */ 170 case 'P': /* remote version */
157 remote_protocol = optarg; 171 result.config.remote_protocol = optarg;
158 break; 172 break;
159 case 'H': /* host */ 173 case 'H': /* host */
160 if (!is_host (optarg)) 174 if (!is_host(optarg)) {
161 usage2 (_("Invalid hostname/address"), optarg); 175 usage2(_("Invalid hostname/address"), optarg);
162 server_name = optarg; 176 }
177 result.config.server_name = optarg;
163 break; 178 break;
164 case 'p': /* port */ 179 case 'p': /* port */
165 if (is_intpos (optarg)) { 180 if (is_intpos(optarg)) {
166 port = atoi (optarg); 181 result.config.port = atoi(optarg);
182 } else {
183 usage2(_("Port number must be a positive integer"), optarg);
167 } 184 }
168 else { 185 break;
169 usage2 (_("Port number must be a positive integer"), optarg); 186 case output_format_index: {
187 parsed_output_format parser = mp_parse_output_format(optarg);
188 if (!parser.parsing_success) {
189 // TODO List all available formats here, maybe add anothoer usage function
190 printf("Invalid output format: %s\n", optarg);
191 exit(STATE_UNKNOWN);
170 } 192 }
193
194 result.config.output_format_is_set = true;
195 result.config.output_format = parser.output_format;
196 break;
197 }
171 } 198 }
172 } 199 }
173 200
174 c = optind; 201 option_char = optind;
175 if (server_name == NULL && c < argc) { 202 if (result.config.server_name == NULL && option_char < argc) {
176 if (is_host (argv[c])) { 203 if (is_host(argv[option_char])) {
177 server_name = argv[c++]; 204 result.config.server_name = argv[option_char++];
178 } 205 }
179 } 206 }
180 207
181 if (port == -1 && c < argc) { 208 if (result.config.port == -1 && option_char < argc) {
182 if (is_intpos (argv[c])) { 209 if (is_intpos(argv[option_char])) {
183 port = atoi (argv[c++]); 210 result.config.port = atoi(argv[option_char++]);
184 } 211 } else {
185 else { 212 print_usage();
186 print_usage (); 213 exit(STATE_UNKNOWN);
187 exit (STATE_UNKNOWN);
188 } 214 }
189 } 215 }
190 216
191 return validate_arguments (); 217 if (result.config.server_name == NULL) {
192} 218 result.errorcode = ERROR;
219 return result;
220 }
193 221
194int 222 return result;
195validate_arguments (void)
196{
197 if (server_name == NULL)
198 return ERROR;
199 if (port == -1) /* funky, but allows -p to override stray integer in args */
200 port = SSH_DFL_PORT;
201 return OK;
202} 223}
203 224
204
205/************************************************************************ 225/************************************************************************
206* 226 *
207* Try to connect to SSH server at specified server and port 227 * Try to connect to SSH server at specified server and port
208* 228 *
209*-----------------------------------------------------------------------*/ 229 *-----------------------------------------------------------------------*/
210
211
212int
213ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol)
214{
215 int sd;
216 int result;
217 int len = 0;
218 ssize_t recv_ret = 0;
219 char *version_control_string = NULL;
220 char *buffer = NULL;
221 char *ssh_proto = NULL;
222 char *ssh_server = NULL;
223 static char *rev_no = VERSION;
224 struct timeval tv;
225 double elapsed_time;
226 230
231int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_version, char *desired_remote_protocol) {
232 struct timeval tv;
227 gettimeofday(&tv, NULL); 233 gettimeofday(&tv, NULL);
228 234
229 result = my_tcp_connect (haddr, hport, &sd); 235 int socket;
236 int result = my_tcp_connect(haddr, hport, &socket);
230 237
231 if (result != STATE_OK) 238 mp_subcheck connection_sc = mp_subcheck_init();
239 if (result != STATE_OK) {
240 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);
242 mp_add_subcheck_to_check(overall, connection_sc);
232 return result; 243 return result;
244 }
233 245
234 char *output = (char *) calloc (BUFF_SZ + 1, sizeof(char)); 246 char *output = (char *)calloc(BUFF_SZ + 1, sizeof(char));
235 247 char *buffer = NULL;
236 unsigned int iteration = 0; 248 size_t recv_ret = 0;
237 ssize_t byte_offset = 0; 249 char *version_control_string = NULL;
238 250 size_t byte_offset = 0;
239 while ((version_control_string == NULL) && (recv_ret = recv(sd, output+byte_offset, BUFF_SZ - byte_offset, 0) > 0)) { 251 while ((version_control_string == NULL) &&
252 (recv_ret = recv(socket, output + byte_offset, (unsigned long)(BUFF_SZ - byte_offset), 0) > 0)) {
240 253
241 if (strchr(output, '\n')) { /* we've got at least one full line, start parsing*/ 254 if (strchr(output, '\n')) { /* we've got at least one full line, start parsing*/
242 byte_offset = 0; 255 byte_offset = 0;
243 256
244 char *index = NULL; 257 char *index = NULL;
245 while ((index = strchr(output+byte_offset, '\n')) != NULL) { 258 unsigned long len = 0;
259 while ((index = strchr(output + byte_offset, '\n')) != NULL) {
246 /*Partition the buffer so that this line is a separate string, 260 /*Partition the buffer so that this line is a separate string,
247 * by replacing the newline with NUL*/ 261 * by replacing the newline with NUL*/
248 output[(index - output)] = '\0'; 262 output[(index - output)] = '\0';
249 len = strlen(output + byte_offset); 263 len = strlen(output + byte_offset);
250 264
251 if ((len >= 4) && (strncmp (output+byte_offset, "SSH-", 4) == 0)) { 265 if ((len >= 4) && (strncmp(output + byte_offset, "SSH-", 4) == 0)) {
252 /*if the string starts with SSH-, this _should_ be a valid version control string*/ 266 /*if the string starts with SSH-, this _should_ be a valid version control string*/
253 version_control_string = output+byte_offset; 267 version_control_string = output + byte_offset;
254 break; 268 break;
255 } 269 }
256 270
257 /*the start of the next line (if one exists) will be after the current one (+ NUL)*/ 271 /*the start of the next line (if one exists) will be after the current one (+ NUL)*/
258 byte_offset += (len + 1); 272 byte_offset += (len + 1);
259 } 273 }
260 274
261 if(version_control_string == NULL) { 275 if (version_control_string == NULL) {
262 /* move unconsumed data to beginning of buffer, null rest */ 276 /* move unconsumed data to beginning of buffer, null rest */
263 memmove((void *)output, (void *)output+byte_offset+1, BUFF_SZ - len+1); 277 memmove((void *)output, (void *)(output + byte_offset + 1), BUFF_SZ - len + 1);
264 memset(output+byte_offset+1, 0, BUFF_SZ-byte_offset+1); 278 memset(output + byte_offset + 1, 0, BUFF_SZ - byte_offset + 1);
265 279
266 /*start reading from end of current line chunk on next recv*/ 280 /*start reading from end of current line chunk on next recv*/
267 byte_offset = strlen(output); 281 byte_offset = strlen(output);
@@ -272,14 +286,23 @@ ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol
272 } 286 }
273 287
274 if (recv_ret < 0) { 288 if (recv_ret < 0) {
275 printf("SSH CRITICAL - %s", strerror(errno)); 289 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL);
276 exit(STATE_CRITICAL); 290 xasprintf(&connection_sc.output, "%s", "SSH CRITICAL - %s", strerror(errno));
291 mp_add_subcheck_to_check(overall, connection_sc);
292 return OK;
277 } 293 }
278 294
279 if (version_control_string == NULL) { 295 if (version_control_string == NULL) {
280 printf("SSH CRITICAL - No version control string received"); 296 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL);
281 exit(STATE_CRITICAL); 297 xasprintf(&connection_sc.output, "%s", "SSH CRITICAL - No version control string received");
298 mp_add_subcheck_to_check(overall, connection_sc);
299 return OK;
282 } 300 }
301
302 connection_sc = mp_set_subcheck_state(connection_sc, STATE_OK);
303 xasprintf(&connection_sc.output, "%s", "Initial connection succeeded");
304 mp_add_subcheck_to_check(overall, connection_sc);
305
283 /* 306 /*
284 * "When the connection has been established, both sides MUST send an 307 * "When the connection has been established, both sides MUST send an
285 * identification string. This identification string MUST be 308 * identification string. This identification string MUST be
@@ -287,10 +310,12 @@ ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol
287 * SSH-protoversion-softwareversion SP comments CR LF" 310 * SSH-protoversion-softwareversion SP comments CR LF"
288 * - RFC 4253:4.2 311 * - RFC 4253:4.2
289 */ 312 */
290 strip (version_control_string); 313 strip(version_control_string);
291 if (verbose) 314 if (verbose) {
292 printf ("%s\n", version_control_string); 315 printf("%s\n", version_control_string);
293 ssh_proto = version_control_string + 4; 316 }
317
318 char *ssh_proto = version_control_string + 4;
294 319
295 /* 320 /*
296 * We assume the protoversion is of the form Major.Minor, although 321 * We assume the protoversion is of the form Major.Minor, although
@@ -308,7 +333,7 @@ ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol
308 * "1.x" (e.g., "1.5" or "1.3")." 333 * "1.x" (e.g., "1.5" or "1.3")."
309 * - RFC 4253:5 334 * - RFC 4253:5
310 */ 335 */
311 ssh_server = ssh_proto + strspn (ssh_proto, "0123456789.") + 1; /* (+1 for the '-' separating protoversion from softwareversion) */ 336 char *ssh_server = ssh_proto + strspn(ssh_proto, "0123456789.") + 1; /* (+1 for the '-' separating protoversion from softwareversion) */
312 337
313 /* If there's a space in the version string, whatever's after the space is a comment 338 /* If there's a space in the version string, whatever's after the space is a comment
314 * (which is NOT part of the server name/version)*/ 339 * (which is NOT part of the server name/version)*/
@@ -316,88 +341,99 @@ ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol
316 if (tmp) { 341 if (tmp) {
317 ssh_server[tmp - ssh_server] = '\0'; 342 ssh_server[tmp - ssh_server] = '\0';
318 } 343 }
344
345 mp_subcheck protocol_validity_sc = mp_subcheck_init();
319 if (strlen(ssh_proto) == 0 || strlen(ssh_server) == 0) { 346 if (strlen(ssh_proto) == 0 || strlen(ssh_server) == 0) {
320 printf(_("SSH CRITICAL - Invalid protocol version control string %s\n"), version_control_string); 347 protocol_validity_sc = mp_set_subcheck_state(protocol_validity_sc, STATE_CRITICAL);
321 exit (STATE_CRITICAL); 348 xasprintf(&protocol_validity_sc.output, "Invalid protocol version control string %s", version_control_string);
349 mp_add_subcheck_to_check(overall, protocol_validity_sc);
350 return OK;
322 } 351 }
323 ssh_proto[strspn (ssh_proto, "0123456789. ")] = 0; 352
324 353 protocol_validity_sc = mp_set_subcheck_state(protocol_validity_sc, STATE_OK);
325 xasprintf (&buffer, "SSH-%s-check_ssh_%s\r\n", ssh_proto, rev_no); 354 xasprintf(&protocol_validity_sc.output, "Valid protocol version control string %s", version_control_string);
326 send (sd, buffer, strlen (buffer), MSG_DONTWAIT); 355 mp_add_subcheck_to_check(overall, protocol_validity_sc);
327 if (verbose) 356
328 printf ("%s\n", buffer); 357 ssh_proto[strspn(ssh_proto, "0123456789. ")] = 0;
329 358
330 if (remote_version && strcmp(remote_version, ssh_server)) { 359 static char *rev_no = VERSION;
331 printf 360 xasprintf(&buffer, "SSH-%s-check_ssh_%s\r\n", ssh_proto, rev_no);
332 (_("SSH CRITICAL - %s (protocol %s) version mismatch, expected '%s'\n"), 361 send(socket, buffer, strlen(buffer), MSG_DONTWAIT);
333 ssh_server, ssh_proto, remote_version); 362 if (verbose) {
334 close(sd); 363 printf("%s\n", buffer);
335 exit (STATE_CRITICAL);
336 } 364 }
337 365
338 if (remote_protocol && strcmp(remote_protocol, ssh_proto)) { 366 if (desired_remote_version && strcmp(desired_remote_version, ssh_server)) {
339 printf 367 mp_subcheck remote_version_sc = mp_subcheck_init();
340 (_("SSH CRITICAL - %s (protocol %s) protocol version mismatch, expected '%s' | %s\n"), 368 remote_version_sc = mp_set_subcheck_state(remote_version_sc, STATE_CRITICAL);
341 ssh_server, ssh_proto, remote_protocol, fperfdata("time", elapsed_time, "s", 369 xasprintf(&remote_version_sc.output, _("%s (protocol %s) version mismatch, expected '%s'"), ssh_server, ssh_proto,
342 false, 0, false, 0, true, 0, true, (int)socket_timeout)); 370 desired_remote_version);
343 close(sd); 371 close(socket);
344 exit (STATE_CRITICAL); 372 mp_add_subcheck_to_check(overall, remote_version_sc);
373 return OK;
345 } 374 }
346 elapsed_time = (double)deltime(tv) / 1.0e6;
347
348 printf
349 (_("SSH OK - %s (protocol %s) | %s\n"),
350 ssh_server, ssh_proto, fperfdata("time", elapsed_time, "s",
351 false, 0, false, 0, true, 0, true, (int)socket_timeout));
352 close(sd);
353 exit (STATE_OK);
354}
355 375
376 double elapsed_time = (double)deltime(tv) / 1.0e6;
377 mp_perfdata time_pd = perfdata_init();
378 time_pd.value = mp_create_pd_value(elapsed_time);
379 time_pd.label = "time";
380 time_pd.max_present = true;
381 time_pd.max = mp_create_pd_value(socket_timeout);
382
383 mp_subcheck protocol_version_sc = mp_subcheck_init();
384 mp_add_perfdata_to_subcheck(&protocol_version_sc, time_pd);
385
386 if (desired_remote_protocol && strcmp(desired_remote_protocol, ssh_proto)) {
387 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,
389 desired_remote_protocol);
390 } else {
391 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);
393 }
356 394
395 mp_add_subcheck_to_check(overall, protocol_version_sc);
396 close(socket);
397 return OK;
398}
357 399
358void 400void print_help(void) {
359print_help (void)
360{
361 char *myport; 401 char *myport;
362 xasprintf (&myport, "%d", SSH_DFL_PORT); 402 xasprintf(&myport, "%d", default_ssh_port);
363 403
364 print_revision (progname, NP_VERSION); 404 print_revision(progname, NP_VERSION);
365 405
366 printf ("Copyright (c) 1999 Remi Paulmier <remi@sinfomic.fr>\n"); 406 printf("Copyright (c) 1999 Remi Paulmier <remi@sinfomic.fr>\n");
367 printf (COPYRIGHT, copyright, email); 407 printf(COPYRIGHT, copyright, email);
368 408
369 printf ("%s\n", _("Try to connect to an SSH server at specified server and port")); 409 printf("%s\n", _("Try to connect to an SSH server at specified server and port"));
370 410
371 printf ("\n\n"); 411 printf("\n\n");
372 412
373 print_usage (); 413 print_usage();
374 414
375 printf (UT_HELP_VRSN); 415 printf(UT_HELP_VRSN);
376 printf (UT_EXTRA_OPTS); 416 printf(UT_EXTRA_OPTS);
377 417
378 printf (UT_HOST_PORT, 'p', myport); 418 printf(UT_HOST_PORT, 'p', myport);
379 419
380 printf (UT_IPv46); 420 printf(UT_IPv46);
381 421
382 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 422 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
383 423
384 printf (" %s\n", "-r, --remote-version=STRING"); 424 printf(" %s\n", "-r, --remote-version=STRING");
385 printf (" %s\n", _("Alert if string doesn't match expected server version (ex: OpenSSH_3.9p1)")); 425 printf(" %s\n", _("Alert if string doesn't match expected server version (ex: OpenSSH_3.9p1)"));
386 426
387 printf (" %s\n", "-P, --remote-protocol=STRING"); 427 printf(" %s\n", "-P, --remote-protocol=STRING");
388 printf (" %s\n", _("Alert if protocol doesn't match expected protocol version (ex: 2.0)")); 428 printf(" %s\n", _("Alert if protocol doesn't match expected protocol version (ex: 2.0)"));
429 printf(UT_OUTPUT_FORMAT);
389 430
390 printf (UT_VERBOSE); 431 printf(UT_VERBOSE);
391 432
392 printf (UT_SUPPORT); 433 printf(UT_SUPPORT);
393} 434}
394 435
395 436void print_usage(void) {
396 437 printf("%s\n", _("Usage:"));
397void 438 printf("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] --hostname <host>\n", progname);
398print_usage (void)
399{
400 printf ("%s\n", _("Usage:"));
401 printf ("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] <host>\n", progname);
402} 439}
403
diff --git a/plugins/check_ssh.d/config.h b/plugins/check_ssh.d/config.h
new file mode 100644
index 00000000..c150fd30
--- /dev/null
+++ b/plugins/check_ssh.d/config.h
@@ -0,0 +1,29 @@
1#pragma once
2
3#include <stddef.h>
4#include "../../lib/monitoringplug.h"
5
6const int default_ssh_port = 22;
7
8typedef struct check_ssh_config {
9 int port;
10 char *server_name;
11 char *remote_version;
12 char *remote_protocol;
13
14 bool output_format_is_set;
15 mp_output_format output_format;
16} check_ssh_config;
17
18check_ssh_config check_ssh_config_init(void) {
19 check_ssh_config tmp = {
20 .port = default_ssh_port,
21 .server_name = NULL,
22 .remote_version = NULL,
23 .remote_protocol = NULL,
24
25 .output_format_is_set = false,
26 };
27
28 return tmp;
29}
diff --git a/plugins/check_swap.c b/plugins/check_swap.c
index e7ee785d..435a104e 100644
--- a/plugins/check_swap.c
+++ b/plugins/check_swap.c
@@ -1,607 +1,408 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_swap plugin 3 * Monitoring check_swap plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000 Karl DeBisschop (kdebisschop@users.sourceforge.net) 6 * Copyright (c) 2000 Karl DeBisschop (kdebisschop@users.sourceforge.net)
7* Copyright (c) 2000-2024 Monitoring Plugins Development Team 7 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains the check_swap plugin 11 * This file contains the check_swap plugin
12* 12 *
13* 13 *
14* This program is free software: you can redistribute it and/or modify 14 * This program is free software: you can redistribute it and/or modify
15* it under the terms of the GNU General Public License as published by 15 * it under the terms of the GNU General Public License as published by
16* the Free Software Foundation, either version 3 of the License, or 16 * the Free Software Foundation, either version 3 of the License, or
17* (at your option) any later version. 17 * (at your option) any later version.
18* 18 *
19* This program is distributed in the hope that it will be useful, 19 * This program is distributed in the hope that it will be useful,
20* but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22* GNU General Public License for more details. 22 * GNU General Public License for more details.
23* 23 *
24* You should have received a copy of the GNU General Public License 24 * You should have received a copy of the GNU General Public License
25* along with this program. If not, see <http://www.gnu.org/licenses/>. 25 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26* 26 *
27* 27 *
28*****************************************************************************/ 28 *****************************************************************************/
29
30const char *progname = "check_swap";
31const char *copyright = "2000-2024";
32const char *email = "devel@monitoring-plugins.org";
33 29
34#include "common.h" 30#include "common.h"
35#include "popen.h" 31#include "output.h"
36#include "utils.h" 32#include "states.h"
37 33#include <limits.h>
38#ifdef HAVE_DECL_SWAPCTL 34#ifdef HAVE_DECL_SWAPCTL
39# ifdef HAVE_SYS_PARAM_H 35# ifdef HAVE_SYS_PARAM_H
40# include <sys/param.h> 36# include <sys/param.h>
41# endif 37# endif
42# ifdef HAVE_SYS_SWAP_H 38# ifdef HAVE_SYS_SWAP_H
43# include <sys/swap.h> 39# include <sys/swap.h>
44# endif 40# endif
45# ifdef HAVE_SYS_STAT_H 41# ifdef HAVE_SYS_STAT_H
46# include <sys/stat.h> 42# include <sys/stat.h>
47# endif 43# endif
48#endif 44#endif
49 45
50#ifndef SWAP_CONVERSION 46#include <stdint.h>
51# define SWAP_CONVERSION 1 47#include "./check_swap.d/check_swap.h"
52#endif 48#include "./utils.h"
53 49
54typedef struct { 50typedef struct {
55 bool is_percentage; 51 int errorcode;
56 uint64_t value; 52 swap_config config;
57} threshold; 53} swap_config_wrapper;
58 54
59int check_swap (float free_swap_mb, float total_swap_mb); 55static swap_config_wrapper process_arguments(int argc, char **argv);
60int process_arguments (int argc, char **argv); 56void print_usage(void);
61int validate_arguments (void); 57static void print_help(swap_config /*config*/);
62void print_usage (void); 58
63void print_help (void);
64
65threshold warn;
66threshold crit;
67int verbose; 59int verbose;
68bool allswaps = false;
69int no_swap_state = STATE_CRITICAL;
70
71int
72main (int argc, char **argv)
73{
74 unsigned int percent_used, percent;
75 uint64_t total_swap_mb = 0, used_swap_mb = 0, free_swap_mb = 0;
76 uint64_t dsktotal_mb = 0, dskused_mb = 0, dskfree_mb = 0;
77 uint64_t tmp_KB = 0;
78 int result = STATE_UNKNOWN;
79 char input_buffer[MAX_INPUT_BUFFER];
80#ifdef HAVE_PROC_MEMINFO
81 FILE *fp;
82#else
83 int conv_factor = SWAP_CONVERSION;
84# ifdef HAVE_SWAP
85 char *temp_buffer;
86 char *swap_command;
87 char *swap_format;
88# else
89# ifdef HAVE_DECL_SWAPCTL
90 int i=0, nswaps=0, swapctl_res=0;
91# ifdef CHECK_SWAP_SWAPCTL_SVR4
92 swaptbl_t *tbl=NULL;
93 swapent_t *ent=NULL;
94# else
95# ifdef CHECK_SWAP_SWAPCTL_BSD
96 struct swapent *ent;
97# endif /* CHECK_SWAP_SWAPCTL_BSD */
98# endif /* CHECK_SWAP_SWAPCTL_SVR4 */
99# endif /* HAVE_DECL_SWAPCTL */
100# endif
101#endif
102 char str[32];
103 char *status;
104 60
105 setlocale (LC_ALL, ""); 61#define HUNDRED_PERCENT 100
106 bindtextdomain (PACKAGE, LOCALEDIR); 62
107 textdomain (PACKAGE); 63#define BYTES_TO_KiB(number) (number / 1024)
64#define BYTES_TO_MiB(number) (BYTES_TO_KiB(number) / 1024)
65
66const char *progname = "check_swap";
67const char *copyright = "2000-2024";
68const char *email = "devel@monitoring-plugins.org";
108 69
109 status = strdup (""); 70int main(int argc, char **argv) {
71 setlocale(LC_ALL, "");
72 bindtextdomain(PACKAGE, LOCALEDIR);
73 textdomain(PACKAGE);
110 74
111 /* Parse extra opts if any */ 75 /* Parse extra opts if any */
112 argv=np_extra_opts (&argc, argv, progname); 76 argv = np_extra_opts(&argc, argv, progname);
113 77
114 if (process_arguments (argc, argv) == ERROR) 78 swap_config_wrapper tmp = process_arguments(argc, argv);
115 usage4 (_("Could not parse arguments"));
116 79
117#ifdef HAVE_PROC_MEMINFO 80 if (tmp.errorcode != OK) {
118 if (verbose >= 3) { 81 usage4(_("Could not parse arguments"));
119 printf("Reading PROC_MEMINFO at %s\n", PROC_MEMINFO);
120 } 82 }
121 fp = fopen (PROC_MEMINFO, "r");
122 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
123 /*
124 * The following sscanf call looks for a line looking like: "Swap: 123 123 123"
125 * On which kind of system this format exists, I can not say, but I wanted to
126 * document this for people who are not adapt with sscanf anymore, like me
127 */
128 if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%*[:] %lu %lu %lu", &dsktotal_mb, &dskused_mb, &dskfree_mb) == 3) {
129 dsktotal_mb = dsktotal_mb / (1024 * 1024); /* Apply conversion */
130 dskused_mb = dskused_mb / (1024 * 1024);
131 dskfree_mb = dskfree_mb / (1024 * 1024);
132 total_swap_mb += dsktotal_mb;
133 used_swap_mb += dskused_mb;
134 free_swap_mb += dskfree_mb;
135 if (allswaps) {
136 if (dsktotal_mb == 0)
137 percent=100.0;
138 else
139 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
140 result = max_state (result, check_swap (dskfree_mb, dsktotal_mb));
141 if (verbose)
142 xasprintf (&status, "%s [%lu (%d%%)]", status, dskfree_mb, 100 - percent);
143 }
144 }
145 83
146 /* 84 swap_config config = tmp.config;
147 * The following sscanf call looks for lines looking like: "SwapTotal: 123" and "SwapFree: 123"
148 * This format exists at least on Debian Linux with a 5.* kernel
149 */
150 else if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%[TotalFreCchd]%*[:] %lu %*[k]%*[B]", str, &tmp_KB)) {
151 if (verbose >= 3) {
152 printf("Got %s with %lu\n", str, tmp_KB);
153 }
154 /* I think this part is always in Kb, so convert to mb */
155 if (strcmp ("Total", str) == 0) {
156 dsktotal_mb = tmp_KB / 1024;
157 }
158 else if (strcmp ("Free", str) == 0) {
159 dskfree_mb = dskfree_mb + tmp_KB / 1024;
160 }
161 else if (strcmp ("Cached", str) == 0) {
162 dskfree_mb = dskfree_mb + tmp_KB / 1024;
163 }
164 }
165 }
166 fclose(fp);
167 dskused_mb = dsktotal_mb - dskfree_mb;
168 total_swap_mb = dsktotal_mb;
169 used_swap_mb = dskused_mb;
170 free_swap_mb = dskfree_mb;
171#else
172# ifdef HAVE_SWAP
173 xasprintf(&swap_command, "%s", SWAP_COMMAND);
174 xasprintf(&swap_format, "%s", SWAP_FORMAT);
175
176/* These override the command used if a summary (and thus ! allswaps) is required */
177/* The summary flag returns more accurate information about swap usage on these OSes */
178# ifdef _AIX
179 if (!allswaps) {
180 xasprintf(&swap_command, "%s", "/usr/sbin/lsps -s");
181 xasprintf(&swap_format, "%s", "%lu%*s %lu");
182 conv_factor = 1;
183 }
184# endif
185 85
186 if (verbose >= 2) 86 swap_result data = get_swap_data(config);
187 printf (_("Command: %s\n"), swap_command);
188 if (verbose >= 3)
189 printf (_("Format: %s\n"), swap_format);
190 87
191 child_process = spopen (swap_command); 88 if (data.errorcode != STATE_OK) {
192 if (child_process == NULL) { 89 puts("SWAP UNKNOWN - Failed to retrieve Swap usage");
193 printf (_("Could not open pipe: %s\n"), swap_command); 90 exit(STATE_UNKNOWN);
194 return STATE_UNKNOWN;
195 } 91 }
196 92
197 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); 93 if (verbose) {
198 if (child_stderr == NULL) 94 printf("Swap retrieval result:\n"
199 printf (_("Could not open stderr for %s\n"), swap_command); 95 "\tFree: %llu\n"
200 96 "\tUsed: %llu\n"
201 sprintf (str, "%s", ""); 97 "\tTotal: %llu\n",
202 /* read 1st line */ 98 data.metrics.free, data.metrics.used, data.metrics.total);
203 fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
204 if (strcmp (swap_format, "") == 0) {
205 temp_buffer = strtok (input_buffer, " \n");
206 while (temp_buffer) {
207 if (strstr (temp_buffer, "blocks"))
208 sprintf (str, "%s %s", str, "%lu");
209 else if (strstr (temp_buffer, "dskfree"))
210 sprintf (str, "%s %s", str, "%lu");
211 else
212 sprintf (str, "%s %s", str, "%*s");
213 temp_buffer = strtok (NULL, " \n");
214 }
215 } 99 }
216 100
217/* If different swap command is used for summary switch, need to read format differently */ 101 double percent_used;
218# ifdef _AIX 102 mp_check overall = mp_check_init();
219 if (!allswaps) { 103 if (config.output_format_is_set) {
220 fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process); /* Ignore first line */ 104 mp_set_format(config.output_format);
221 sscanf (input_buffer, swap_format, &total_swap_mb, &used_swap_mb);
222 free_swap_mb = total_swap_mb * (100 - used_swap_mb) /100;
223 used_swap_mb = total_swap_mb - free_swap_mb;
224 if (verbose >= 3)
225 printf (_("total=%.0f, used=%.0f, free=%.0f\n"), total_swap_mb, used_swap_mb, free_swap_mb);
226 } else {
227# endif
228 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
229 sscanf (input_buffer, swap_format, &dsktotal_mb, &dskfree_mb);
230
231 dsktotal_mb = dsktotal_mb / conv_factor;
232 /* AIX lists percent used, so this converts to dskfree in MBs */
233# ifdef _AIX
234 dskfree_mb = dsktotal_mb * (100 - dskfree_mb) / 100;
235# else
236 dskfree_mb = dskfree_mb / conv_factor;
237# endif
238 if (verbose >= 3)
239 printf (_("total=%.0f, free=%.0f\n"), dsktotal_mb, dskfree_mb);
240
241 dskused_mb = dsktotal_mb - dskfree_mb;
242 total_swap_mb += dsktotal_mb;
243 used_swap_mb += dskused_mb;
244 free_swap_mb += dskfree_mb;
245 if (allswaps) {
246 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
247 result = max_state (result, check_swap (dskfree_mb, dsktotal_mb));
248 if (verbose)
249 xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
250 }
251 }
252# ifdef _AIX
253 } 105 }
254# endif 106 mp_subcheck sc1 = mp_subcheck_init();
255 107 sc1 = mp_set_subcheck_default_state(sc1, STATE_OK);
256 /* If we get anything on STDERR, at least set warning */
257 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr))
258 result = max_state (result, STATE_WARNING);
259
260 /* close stderr */
261 (void) fclose (child_stderr);
262 108
263 /* close the pipe */ 109 /* if total_swap_mb == 0, let's not divide by 0 */
264 if (spclose (child_process)) 110 if (data.metrics.total != 0) {
265 result = max_state (result, STATE_WARNING); 111 percent_used = HUNDRED_PERCENT * ((double)data.metrics.used) / ((double)data.metrics.total);
266# else 112 } else {
267# ifdef CHECK_SWAP_SWAPCTL_SVR4 113 sc1 = mp_set_subcheck_state(sc1, config.no_swap_state);
114 sc1.output = (char *)_("Swap is either disabled, not present, or of zero size.");
268 115
269 /* get the number of active swap devices */ 116 mp_add_subcheck_to_check(&overall, sc1);
270 if((nswaps=swapctl(SC_GETNSWP, NULL))== -1) 117 mp_exit(overall);
271 die(STATE_UNKNOWN, _("Error getting swap devices\n") ); 118 }
272 119
273 if(nswaps == 0) 120 if (verbose) {
274 die(STATE_OK, _("SWAP OK: No swap devices defined\n")); 121 printf("Computed usage percentage: %g\n", percent_used);
122 }
275 123
276 if(verbose >= 3) 124 mp_perfdata pd = perfdata_init();
277 printf("Found %d swap device(s)\n", nswaps); 125 pd.label = "swap";
126 pd = mp_set_pd_value(pd, data.metrics.free);
127 pd.uom = "B";
278 128
279 /* initialize swap table + entries */ 129 if (config.warn_is_set) {
280 tbl=(swaptbl_t*)malloc(sizeof(swaptbl_t)+(sizeof(swapent_t)*nswaps)); 130 uint64_t warn_print = config.warn.value;
131 if (config.warn.is_percentage) {
132 warn_print = config.warn.value * (data.metrics.total / HUNDRED_PERCENT);
133 }
281 134
282 if(tbl==NULL) 135 mp_perfdata_value warn_pd = mp_create_pd_value(warn_print);
283 die(STATE_UNKNOWN, _("malloc() failed!\n"));
284 136
285 memset(tbl, 0, sizeof(swaptbl_t)+(sizeof(swapent_t)*nswaps)); 137 mp_range warn_range = mp_range_init();
286 tbl->swt_n=nswaps; 138 warn_range.end_infinity = false;
287 for(i=0;i<nswaps;i++){ 139 warn_range.end = warn_pd;
288 if((tbl->swt_ent[i].ste_path=(char*)malloc(sizeof(char)*MAXPATHLEN)) == NULL)
289 die(STATE_UNKNOWN, _("malloc() failed!\n"));
290 }
291 140
292 /* and now, tally 'em up */ 141 pd.warn = warn_range;
293 swapctl_res=swapctl(SC_LIST, tbl); 142 pd.warn_present = true;
294 if(swapctl_res < 0){
295 perror(_("swapctl failed: "));
296 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
297 } 143 }
298 144
299 for(i=0;i<nswaps;i++){ 145 if (config.crit_is_set) {
300 dsktotal_mb = (float) tbl->swt_ent[i].ste_pages / SWAP_CONVERSION; 146 uint64_t crit_print = config.crit.value;
301 dskfree_mb = (float) tbl->swt_ent[i].ste_free / SWAP_CONVERSION; 147 if (config.crit.is_percentage) {
302 dskused_mb = ( dsktotal_mb - dskfree_mb ); 148 crit_print = config.crit.value * (data.metrics.total / HUNDRED_PERCENT);
303
304 if (verbose >= 3)
305 printf ("dsktotal_mb=%.0f dskfree_mb=%.0f dskused_mb=%.0f\n", dsktotal_mb, dskfree_mb, dskused_mb);
306
307 if(allswaps && dsktotal_mb > 0){
308 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
309 result = max_state (result, check_swap (dskfree_mb, dsktotal_mb));
310 if (verbose) {
311 xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
312 }
313 } 149 }
314 150
315 total_swap_mb += dsktotal_mb; 151 mp_perfdata_value crit_pd = mp_create_pd_value(crit_print);
316 free_swap_mb += dskfree_mb;
317 used_swap_mb += dskused_mb;
318 }
319 152
320 /* and clean up after ourselves */ 153 mp_range crit_range = mp_range_init();
321 for(i=0;i<nswaps;i++){ 154 crit_range.end_infinity = false;
322 free(tbl->swt_ent[i].ste_path); 155 crit_range.end = crit_pd;
156
157 pd.crit = crit_range;
158 pd.crit_present = true;
323 } 159 }
324 free(tbl);
325# else
326# ifdef CHECK_SWAP_SWAPCTL_BSD
327 160
328 /* get the number of active swap devices */ 161 mp_perfdata_value max = mp_create_pd_value(data.metrics.total);
329 nswaps=swapctl(SWAP_NSWAP, NULL, 0); 162 pd.max = max;
163 pd.max_present = true;
330 164
331 /* initialize swap table + entries */ 165 mp_perfdata_value min = mp_create_pd_value(0);
332 ent=(struct swapent*)malloc(sizeof(struct swapent)*nswaps); 166 pd.min = min;
167 pd.min_present = true;
333 168
334 /* and now, tally 'em up */ 169 mp_add_perfdata_to_subcheck(&sc1, pd);
335 swapctl_res=swapctl(SWAP_STATS, ent, nswaps); 170 if (verbose > 1) {
336 if(swapctl_res < 0){ 171 printf("Warn threshold value: %" PRIu64 "\n", config.warn.value);
337 perror(_("swapctl failed: "));
338 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
339 } 172 }
340 173
341 for(i=0;i<nswaps;i++){ 174 if (config.warn_is_set) {
342 dsktotal_mb = (float) ent[i].se_nblks / conv_factor; 175 if ((config.warn.is_percentage && (percent_used >= (100 - (double)config.warn.value))) || config.warn.value >= data.metrics.free) {
343 dskused_mb = (float) ent[i].se_inuse / conv_factor; 176 sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
344 dskfree_mb = ( dsktotal_mb - dskused_mb );
345
346 if(allswaps && dsktotal_mb > 0){
347 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
348 result = max_state (result, check_swap(dskfree_mb, dsktotal_mb));
349 if (verbose) {
350 xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
351 }
352 } 177 }
353
354 total_swap_mb += dsktotal_mb;
355 free_swap_mb += dskfree_mb;
356 used_swap_mb += dskused_mb;
357 } 178 }
358 179
359 /* and clean up after ourselves */ 180 if (verbose > 1) {
360 free(ent); 181 printf("Crit threshold value: %" PRIu64 "\n", config.crit.value);
361
362# endif /* CHECK_SWAP_SWAPCTL_BSD */
363# endif /* CHECK_SWAP_SWAPCTL_SVR4 */
364# endif /* HAVE_SWAP */
365#endif /* HAVE_PROC_MEMINFO */
366
367 /* if total_swap_mb == 0, let's not divide by 0 */
368 if(total_swap_mb) {
369 percent_used = 100 * ((double) used_swap_mb) / ((double) total_swap_mb);
370 } else {
371 percent_used = 100;
372 status = "- Swap is either disabled, not present, or of zero size. ";
373 } 182 }
374 183
375 result = max_state (result, check_swap(free_swap_mb, total_swap_mb)); 184 if (config.crit_is_set) {
376 printf (_("SWAP %s - %d%% free (%dMB out of %dMB) %s|"), 185 if ((config.crit.is_percentage && (percent_used >= (100 - (double)config.crit.value))) || config.crit.value >= data.metrics.free) {
377 state_text (result), 186 sc1 = mp_set_subcheck_state(sc1, STATE_CRITICAL);
378 (100 - percent_used), (int) free_swap_mb, (int) total_swap_mb, status); 187 }
188 }
379 189
380 uint64_t warn_print = warn.value; 190 xasprintf(&sc1.output, _("%g%% free (%lluMiB out of %lluMiB)"), (100 - percent_used), data.metrics.free >> 20,
381 if (warn.is_percentage) warn_print = warn.value * (total_swap_mb *1024 *1024/100); 191 data.metrics.total >> 20);
382 uint64_t crit_print = crit.value;
383 if (crit.is_percentage) crit_print = crit.value * (total_swap_mb *1024 *1024/100);
384 192
385 puts (perfdata_uint64 ("swap", free_swap_mb *1024 *1024, "B", 193 overall.summary = "Swap";
386 true, warn_print, 194 mp_add_subcheck_to_check(&overall, sc1);
387 true, crit_print,
388 true, 0,
389 true, (long) total_swap_mb * 1024 * 1024));
390 195
391 return result; 196 mp_exit(overall);
392} 197}
393 198
199int check_swap(float free_swap_mb, float total_swap_mb, swap_config config) {
200 if (total_swap_mb == 0) {
201 return config.no_swap_state;
202 }
394 203
395int 204 uint64_t free_swap = (uint64_t)(free_swap_mb * (1024 * 1024)); /* Convert back to bytes as warn and crit specified in bytes */
396check_swap(float free_swap_mb, float total_swap_mb)
397{
398
399 if (!total_swap_mb) return no_swap_state;
400 205
401 uint64_t free_swap = free_swap_mb * (1024 * 1024); /* Convert back to bytes as warn and crit specified in bytes */ 206 if (!config.crit.is_percentage && config.crit.value >= free_swap) {
402 uint64_t usage_percentage = ((total_swap_mb - free_swap_mb) / total_swap_mb) * 100; 207 return STATE_CRITICAL;
208 }
209 if (!config.warn.is_percentage && config.warn.value >= free_swap) {
210 return STATE_WARNING;
211 }
403 212
404 if (warn.value || crit.value) { /* Thresholds defined */ 213 uint64_t usage_percentage = (uint64_t)((total_swap_mb - free_swap_mb) / total_swap_mb) * HUNDRED_PERCENT;
405 if (!crit.is_percentage && crit.value >= free_swap) return STATE_CRITICAL;
406 if (!warn.is_percentage && warn.value >= free_swap) return STATE_WARNING;
407 214
408 if (crit.is_percentage && 215 if (config.crit.is_percentage && config.crit.value != 0 && usage_percentage >= (HUNDRED_PERCENT - config.crit.value)) {
409 crit.value != 0 && 216 return STATE_CRITICAL;
410 usage_percentage >= (100 - crit.value)) 217 }
411 {
412 return STATE_CRITICAL;
413 }
414 218
415 if (warn.is_percentage && 219 if (config.warn.is_percentage && config.warn.value != 0 && usage_percentage >= (HUNDRED_PERCENT - config.warn.value)) {
416 warn.value != 0 && 220 return STATE_WARNING;
417 usage_percentage >= (100 - warn.value)) 221 }
418 {
419 return STATE_WARNING;
420 }
421 222
422 return STATE_OK; 223 return STATE_OK;
423 } else { /* Without thresholds */
424 return STATE_OK;
425 }
426} 224}
427 225
428 226#define output_format_index CHAR_MAX + 1
429 227
430/* process command-line arguments */ 228/* process command-line arguments */
431int 229swap_config_wrapper process_arguments(int argc, char **argv) {
432process_arguments (int argc, char **argv) 230 swap_config_wrapper conf_wrapper = {.errorcode = OK};
433{ 231 conf_wrapper.config = swap_config_init();
434 int c = 0; /* option character */ 232
435 233 static struct option longopts[] = {{"warning", required_argument, 0, 'w'},
436 int option = 0; 234 {"critical", required_argument, 0, 'c'},
437 static struct option longopts[] = { 235 {"allswaps", no_argument, 0, 'a'},
438 {"warning", required_argument, 0, 'w'}, 236 {"no-swap", required_argument, 0, 'n'},
439 {"critical", required_argument, 0, 'c'}, 237 {"verbose", no_argument, 0, 'v'},
440 {"allswaps", no_argument, 0, 'a'}, 238 {"version", no_argument, 0, 'V'},
441 {"no-swap", required_argument, 0, 'n'}, 239 {"help", no_argument, 0, 'h'},
442 {"verbose", no_argument, 0, 'v'}, 240 {"output-format", required_argument, 0, output_format_index},
443 {"version", no_argument, 0, 'V'}, 241 {0, 0, 0, 0}};
444 {"help", no_argument, 0, 'h'}, 242
445 {0, 0, 0, 0} 243 while (true) {
446 }; 244 int option = 0;
447 245 int option_char = getopt_long(argc, argv, "+?Vvhac:w:n:", longopts, &option);
448 while (1) { 246
449 c = getopt_long (argc, argv, "+?Vvhac:w:n:", longopts, &option); 247 if (option_char == -1 || option_char == EOF) {
450
451 if (c == -1 || c == EOF)
452 break; 248 break;
249 }
453 250
454 switch (c) { 251 switch (option_char) {
455 case 'w': /* warning size threshold */ 252 case 'w': /* warning size threshold */
456 { 253 {
457 /* 254 /*
458 * We expect either a positive integer value without a unit, which means 255 * We expect either a positive integer value without a unit, which
459 * the unit is Bytes or a positive integer value and a percentage sign (%), 256 * means the unit is Bytes or a positive integer value and a
460 * which means the value must be with 0 and 100 and is relative to the total swap 257 * percentage sign (%), which means the value must be with 0 and 100
461 */ 258 * and is relative to the total swap
462 size_t length; 259 */
463 length = strlen(optarg); 260 size_t length;
464 261 length = strlen(optarg);
465 if (optarg[length - 1] == '%') { 262 conf_wrapper.config.warn_is_set = true;
466 /* It's percentage */ 263
467 warn.is_percentage = true; 264 if (optarg[length - 1] == '%') {
468 optarg[length - 1] = '\0'; 265 /* It's percentage */
469 if (is_uint64(optarg, &warn.value)) { 266 conf_wrapper.config.warn.is_percentage = true;
470 if (warn.value > 100) { 267 optarg[length - 1] = '\0';
471 usage4 (_("Warning threshold percentage must be <= 100!")); 268 if (is_uint64(optarg, &conf_wrapper.config.warn.value)) {
472 } 269 if (conf_wrapper.config.warn.value > HUNDRED_PERCENT) {
473 } 270 usage4(_("Warning threshold percentage must be <= 100!"));
474 break;
475 } else {
476 /* It's Bytes */
477 warn.is_percentage = false;
478 if (is_uint64(optarg, &warn.value)) {
479 break;
480 } else {
481 usage4 (_("Warning threshold be positive integer or percentage!"));
482 } 271 }
483 } 272 }
273 break;
274 } /* It's Bytes */
275 conf_wrapper.config.warn.is_percentage = false;
276 if (is_uint64(optarg, &conf_wrapper.config.warn.value)) {
277 break;
484 } 278 }
279 usage4(_("Warning threshold be positive integer or "
280 "percentage!"));
281 }
485 case 'c': /* critical size threshold */ 282 case 'c': /* critical size threshold */
486 { 283 {
487 /* 284 /*
488 * We expect either a positive integer value without a unit, which means 285 * We expect either a positive integer value without a unit, which
489 * the unit is Bytes or a positive integer value and a percentage sign (%), 286 * means the unit is Bytes or a positive integer value and a
490 * which means the value must be with 0 and 100 and is relative to the total swap 287 * percentage sign (%), which means the value must be with 0 and 100
491 */ 288 * and is relative to the total swap
492 size_t length; 289 */
493 length = strlen(optarg); 290 size_t length;
494 291 length = strlen(optarg);
495 if (optarg[length - 1] == '%') { 292 conf_wrapper.config.crit_is_set = true;
496 /* It's percentage */ 293
497 crit.is_percentage = true; 294 if (optarg[length - 1] == '%') {
498 optarg[length - 1] = '\0'; 295 /* It's percentage */
499 if (is_uint64(optarg, &crit.value)) { 296 conf_wrapper.config.crit.is_percentage = true;
500 if (crit.value> 100) { 297 optarg[length - 1] = '\0';
501 usage4 (_("Critical threshold percentage must be <= 100!")); 298 if (is_uint64(optarg, &conf_wrapper.config.crit.value)) {
502 } 299 if (conf_wrapper.config.crit.value > HUNDRED_PERCENT) {
503 } 300 usage4(_("Critical threshold percentage must be <= 100!"));
504 break;
505 } else {
506 /* It's Bytes */
507 crit.is_percentage = false;
508 if (is_uint64(optarg, &crit.value)) {
509 break;
510 } else {
511 usage4 (_("Critical threshold be positive integer or percentage!"));
512 } 301 }
513 } 302 }
514 } 303 break;
515 case 'a': /* all swap */ 304 } /* It's Bytes */
516 allswaps = true; 305 conf_wrapper.config.crit.is_percentage = false;
306 if (is_uint64(optarg, &conf_wrapper.config.crit.value)) {
307 break;
308 }
309 usage4(_("Critical threshold be positive integer or "
310 "percentage!"));
311 }
312 case 'a': /* all swap */
313 conf_wrapper.config.allswaps = true;
517 break; 314 break;
518 case 'n': 315 case 'n':
519 if ((no_swap_state = mp_translate_state(optarg)) == ERROR) { 316 if ((conf_wrapper.config.no_swap_state = mp_translate_state(optarg)) == ERROR) {
520 usage4 (_("no-swap result must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 317 usage4(_("no-swap result must be a valid state name (OK, "
318 "WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
521 } 319 }
522 break; 320 break;
523 case 'v': /* verbose */ 321 case 'v': /* verbose */
524 verbose++; 322 verbose++;
525 break; 323 break;
526 case 'V': /* version */ 324 case output_format_index: {
527 print_revision (progname, NP_VERSION); 325 parsed_output_format parser = mp_parse_output_format(optarg);
528 exit (STATE_UNKNOWN); 326 if (!parser.parsing_success) {
529 case 'h': /* help */ 327 // TODO List all available formats here, maybe add anothoer usage function
530 print_help (); 328 printf("Invalid output format: %s\n", optarg);
531 exit (STATE_UNKNOWN); 329 exit(STATE_UNKNOWN);
532 case '?': /* error */ 330 }
533 usage5 (); 331
332 conf_wrapper.config.output_format_is_set = true;
333 conf_wrapper.config.output_format = parser.output_format;
334 break;
335 }
336 case 'V': /* version */
337 print_revision(progname, NP_VERSION);
338 exit(STATE_UNKNOWN);
339 case 'h': /* help */
340 print_help(conf_wrapper.config);
341 exit(STATE_UNKNOWN);
342 case '?': /* error */
343 usage5();
534 } 344 }
535 } 345 }
536 346
537 c = optind; 347 if ((conf_wrapper.config.warn.is_percentage == conf_wrapper.config.crit.is_percentage) &&
538 if (c == argc) 348 (conf_wrapper.config.warn.value < conf_wrapper.config.crit.value)) {
539 return validate_arguments (); 349 /* This is NOT triggered if warn and crit are different units, e.g warn
540 350 * is percentage and crit is absolute. We cannot determine the condition
541 return validate_arguments (); 351 * at this point since we dont know the value of total swap yet
542}
543
544
545
546int
547validate_arguments (void)
548{
549 if ((warn.is_percentage == crit.is_percentage) && (warn.value < crit.value)) {
550 /* This is NOT triggered if warn and crit are different units, e.g warn is percentage
551 * and crit is absolute. We cannot determine the condition at this point since we
552 * dont know the value of total swap yet
553 */ 352 */
554 usage4(_("Warning should be more than critical")); 353 usage4(_("Warning should be more than critical"));
555 } 354 }
556 return OK;
557}
558
559 355
560 356 return conf_wrapper;
561void
562print_help (void)
563{
564 print_revision (progname, NP_VERSION);
565
566 printf (_(COPYRIGHT), copyright, email);
567
568 printf ("%s\n", _("Check swap space on local machine."));
569
570 printf ("\n\n");
571
572 print_usage ();
573
574 printf (UT_HELP_VRSN);
575 printf (UT_EXTRA_OPTS);
576
577 printf (" %s\n", "-w, --warning=INTEGER");
578 printf (" %s\n", _("Exit with WARNING status if less than INTEGER bytes of swap space are free"));
579 printf (" %s\n", "-w, --warning=PERCENT%");
580 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of swap space is free"));
581 printf (" %s\n", "-c, --critical=INTEGER");
582 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER bytes of swap space are free"));
583 printf (" %s\n", "-c, --critical=PERCENT%");
584 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of swap space is free"));
585 printf (" %s\n", "-a, --allswaps");
586 printf (" %s\n", _("Conduct comparisons for all swap partitions, one by one"));
587 printf (" %s\n", "-n, --no-swap=<ok|warning|critical|unknown>");
588 printf (" %s %s\n", _("Resulting state when there is no swap regardless of thresholds. Default:"), state_text(no_swap_state));
589 printf (UT_VERBOSE);
590
591 printf ("\n");
592 printf ("%s\n", _("Notes:"));
593 printf (" %s\n", _("Both INTEGER and PERCENT thresholds can be specified, they are all checked."));
594 printf (" %s\n", _("Without thresholds, the plugin shows free swap space and performance data, but always returns OK."));
595 printf (" %s\n", _("On AIX, if -a is specified, uses lsps -a, otherwise uses lsps -s."));
596
597 printf (UT_SUPPORT);
598} 357}
599 358
359void print_help(swap_config config) {
360 print_revision(progname, NP_VERSION);
361
362 printf(_(COPYRIGHT), copyright, email);
363
364 printf("%s\n", _("Check swap space on local machine."));
365
366 printf("\n\n");
367
368 print_usage();
369
370 printf(UT_HELP_VRSN);
371 printf(UT_EXTRA_OPTS);
372
373 printf(" %s\n", "-w, --warning=INTEGER");
374 printf(" %s\n", _("Exit with WARNING status if less than INTEGER bytes "
375 "of swap space are free"));
376 printf(" %s\n", "-w, --warning=PERCENT%");
377 printf(" %s\n", _("Exit with WARNING status if less than PERCENT of "
378 "swap space is free"));
379 printf(" %s\n", "-c, --critical=INTEGER");
380 printf(" %s\n", _("Exit with CRITICAL status if less than INTEGER bytes "
381 "of swap space are free"));
382 printf(" %s\n", "-c, --critical=PERCENT%");
383 printf(" %s\n", _("Exit with CRITICAL status if less than PERCENT of "
384 "swap space is free"));
385 printf(" %s\n", "-a, --allswaps");
386 printf(" %s\n", _("Conduct comparisons for all swap partitions, one by one"));
387 printf(" %s\n", "-n, --no-swap=<ok|warning|critical|unknown>");
388 printf(" %s %s\n",
389 _("Resulting state when there is no swap regardless of thresholds. "
390 "Default:"),
391 state_text(config.no_swap_state));
392 printf(UT_OUTPUT_FORMAT);
393 printf(UT_VERBOSE);
394
395 printf("\n");
396 printf("%s\n", _("Notes:"));
397 printf(" %s\n", _("Both INTEGER and PERCENT thresholds can be specified, "
398 "they are all checked."));
399 printf(" %s\n", _("On AIX, if -a is specified, uses lsps -a, otherwise uses lsps -s."));
400
401 printf(UT_SUPPORT);
402}
600 403
601void 404void print_usage(void) {
602print_usage (void) 405 printf("%s\n", _("Usage:"));
603{ 406 printf(" %s [-av] -w <percent_free>%% -c <percent_free>%%\n", progname);
604 printf ("%s\n", _("Usage:")); 407 printf(" -w <bytes_free> -c <bytes_free> [-n <state>]\n");
605 printf (" %s [-av] [-w <percent_free>%%] [-c <percent_free>%%]\n",progname);
606 printf (" [-w <bytes_free>] [-c <bytes_free>] [-n <state>]\n");
607} 408}
diff --git a/plugins/check_swap.d/check_swap.h b/plugins/check_swap.d/check_swap.h
new file mode 100644
index 00000000..da08d65a
--- /dev/null
+++ b/plugins/check_swap.d/check_swap.h
@@ -0,0 +1,48 @@
1#pragma once
2
3#include "../common.h"
4#include "../../lib/output.h"
5#include "../../lib/states.h"
6
7#ifndef SWAP_CONVERSION
8# define SWAP_CONVERSION 1
9#endif
10
11typedef struct {
12 bool is_percentage;
13 uint64_t value;
14} check_swap_threshold;
15
16typedef struct {
17 unsigned long long free; // Free swap in Bytes!
18 unsigned long long used; // Used swap in Bytes!
19 unsigned long long total; // Total swap size, you guessed it, in Bytes!
20} swap_metrics;
21
22typedef struct {
23 int errorcode;
24 int statusCode;
25 swap_metrics metrics;
26} swap_result;
27
28typedef struct {
29 bool allswaps;
30 mp_state_enum no_swap_state;
31 bool warn_is_set;
32 check_swap_threshold warn;
33 bool crit_is_set;
34 check_swap_threshold crit;
35 bool on_aix;
36 int conversion_factor;
37
38 bool output_format_is_set;
39 mp_output_format output_format;
40} swap_config;
41
42swap_config swap_config_init(void);
43
44swap_result get_swap_data(swap_config config);
45swap_result getSwapFromProcMeminfo(char path_to_proc_meminfo[]);
46swap_result getSwapFromSwapCommand(swap_config config, const char swap_command[], const char swap_format[]);
47swap_result getSwapFromSwapctl_BSD(swap_config config);
48swap_result getSwapFromSwap_SRV4(swap_config config);
diff --git a/plugins/check_swap.d/swap.c b/plugins/check_swap.d/swap.c
new file mode 100644
index 00000000..634f80d9
--- /dev/null
+++ b/plugins/check_swap.d/swap.c
@@ -0,0 +1,465 @@
1#include "./check_swap.d/check_swap.h"
2#include "../popen.h"
3#include "../utils.h"
4#include "common.h"
5
6extern int verbose;
7
8swap_config swap_config_init(void) {
9 swap_config tmp = {0};
10 tmp.allswaps = false;
11 tmp.no_swap_state = STATE_CRITICAL;
12 tmp.conversion_factor = SWAP_CONVERSION;
13
14 tmp.warn_is_set = false;
15 tmp.crit_is_set = false;
16
17 tmp.output_format_is_set = false;
18
19#ifdef _AIX
20 tmp.on_aix = true;
21#else
22 tmp.on_aix = false;
23#endif
24
25 return tmp;
26}
27
28swap_result get_swap_data(swap_config config) {
29#ifdef HAVE_PROC_MEMINFO
30 if (verbose >= 3) {
31 printf("Reading PROC_MEMINFO at %s\n", PROC_MEMINFO);
32 }
33
34 return getSwapFromProcMeminfo(PROC_MEMINFO);
35#else // HAVE_PROC_MEMINFO
36# ifdef HAVE_SWAP
37 if (verbose >= 3) {
38 printf("Using swap command %s with format: %s\n", SWAP_COMMAND, SWAP_FORMAT);
39 }
40
41 /* These override the command used if a summary (and thus ! allswaps) is
42 * required
43 * The summary flag returns more accurate information about swap usage on these
44 * OSes */
45 if (config.on_aix && !config.allswaps) {
46
47 config.conversion_factor = 1;
48
49 return getSwapFromSwapCommand(config, "/usr/sbin/lsps -s", "%lu%*s %lu");
50 } else {
51 return getSwapFromSwapCommand(config, SWAP_COMMAND, SWAP_FORMAT);
52 }
53# else // HAVE_SWAP
54# ifdef CHECK_SWAP_SWAPCTL_SVR4
55 return getSwapFromSwapctl_SRV4();
56# else // CHECK_SWAP_SWAPCTL_SVR4
57# ifdef CHECK_SWAP_SWAPCTL_BSD
58 return getSwapFromSwapctl_BSD();
59# else // CHECK_SWAP_SWAPCTL_BSD
60# error No way found to retrieve swap
61# endif /* CHECK_SWAP_SWAPCTL_BSD */
62# endif /* CHECK_SWAP_SWAPCTL_SVR4 */
63# endif /* HAVE_SWAP */
64#endif /* HAVE_PROC_MEMINFO */
65}
66
67swap_result getSwapFromProcMeminfo(char proc_meminfo[]) {
68 FILE *meminfo_file_ptr;
69 meminfo_file_ptr = fopen(proc_meminfo, "r");
70
71 swap_result result = {};
72 result.errorcode = STATE_UNKNOWN;
73
74 if (meminfo_file_ptr == NULL) {
75 // failed to open meminfo file
76 // errno should contain an error
77 result.errorcode = STATE_UNKNOWN;
78 return result;
79 }
80
81 unsigned long swap_total = 0;
82 unsigned long swap_used = 0;
83 unsigned long swap_free = 0;
84
85 bool found_total = false;
86 bool found_free = false;
87
88 char input_buffer[MAX_INPUT_BUFFER];
89 char str[32];
90
91 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, meminfo_file_ptr)) {
92
93 /*
94 * The following sscanf call looks for a line looking like: "Swap: 123
95 * 123 123" which exists on NetBSD (at least),
96 * The unit should be Bytes
97 */
98 if (sscanf(input_buffer, "%*[S]%*[w]%*[a]%*[p]%*[:] %lu %lu %lu", &swap_total, &swap_used, &swap_free) == 3) {
99 found_total = true;
100 found_free = true;
101 // Set error
102 result.errorcode = STATE_OK;
103 // Break out of fgets here, since both scanf expressions might match (NetBSD for example)
104 break;
105 }
106
107 /*
108 * The following sscanf call looks for lines looking like:
109 * "SwapTotal: 123" and "SwapFree: 123" This format exists at least
110 * on Debian Linux with a 5.* kernel
111 */
112 unsigned long tmp_KB = 0;
113 int sscanf_result = sscanf(input_buffer,
114 "%*[S]%*[w]%*[a]%*[p]%[TotalFreCchd]%*[:] %lu "
115 "%*[k]%*[B]",
116 str, &tmp_KB);
117
118 if (sscanf_result == 2) {
119
120 if (verbose >= 3) {
121 printf("Got %s with %lu\n", str, tmp_KB);
122 }
123
124 /* I think this part is always in Kb, so convert to bytes */
125 if (strcmp("Total", str) == 0) {
126 swap_total = tmp_KB * 1000;
127 found_total = true;
128 } else if (strcmp("Free", str) == 0) {
129 swap_free += tmp_KB * 1000;
130 found_free = true;
131 } else if (strcmp("Cached", str) == 0) {
132 swap_free += tmp_KB * 1000;
133 }
134
135 result.errorcode = STATE_OK;
136 }
137 }
138
139 fclose(meminfo_file_ptr);
140
141 result.metrics.total = swap_total;
142 result.metrics.free = swap_free;
143 result.metrics.used = swap_total - swap_free;
144
145 if (!found_free || !found_total) {
146 result.errorcode = STATE_UNKNOWN;
147 }
148
149 return result;
150}
151
152swap_result getSwapFromSwapCommand(swap_config config, const char swap_command[], const char swap_format[]) {
153 swap_result result = {0};
154
155 char *temp_buffer;
156
157 if (verbose >= 2) {
158 printf(_("Command: %s\n"), swap_command);
159 }
160 if (verbose >= 3) {
161 printf(_("Format: %s\n"), swap_format);
162 }
163
164 child_process = spopen(swap_command);
165 if (child_process == NULL) {
166 printf(_("Could not open pipe: %s\n"), swap_command);
167 swap_result tmp = {
168 .errorcode = STATE_UNKNOWN,
169 };
170 return tmp;
171 }
172
173 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
174 if (child_stderr == NULL) {
175 printf(_("Could not open stderr for %s\n"), swap_command);
176 }
177
178 char str[32] = {0};
179 char input_buffer[MAX_INPUT_BUFFER];
180
181 /* read 1st line */
182 fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process);
183 if (strcmp(swap_format, "") == 0) {
184 temp_buffer = strtok(input_buffer, " \n");
185 while (temp_buffer) {
186 if (strstr(temp_buffer, "blocks")) {
187 sprintf(str, "%s %s", str, "%lu");
188 } else if (strstr(temp_buffer, "dskfree")) {
189 sprintf(str, "%s %s", str, "%lu");
190 } else {
191 sprintf(str, "%s %s", str, "%*s");
192 }
193 temp_buffer = strtok(NULL, " \n");
194 }
195 }
196
197 double total_swap_mb = 0;
198 double free_swap_mb = 0;
199 double used_swap_mb = 0;
200 double dsktotal_mb = 0;
201 double dskused_mb = 0;
202 double dskfree_mb = 0;
203
204 /*
205 * If different swap command is used for summary switch, need to read format
206 * differently
207 */
208 if (config.on_aix && !config.allswaps) {
209 fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process); /* Ignore first line */
210 sscanf(input_buffer, swap_format, &total_swap_mb, &used_swap_mb);
211 free_swap_mb = total_swap_mb * (100 - used_swap_mb) / 100;
212 used_swap_mb = total_swap_mb - free_swap_mb;
213
214 if (verbose >= 3) {
215 printf(_("total=%.0f, used=%.0f, free=%.0f\n"), total_swap_mb, used_swap_mb, free_swap_mb);
216 }
217 } else {
218 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
219 sscanf(input_buffer, swap_format, &dsktotal_mb, &dskfree_mb);
220
221 dsktotal_mb = dsktotal_mb / config.conversion_factor;
222 /* AIX lists percent used, so this converts to dskfree in MBs */
223
224 if (config.on_aix) {
225 dskfree_mb = dsktotal_mb * (100 - dskfree_mb) / 100;
226 } else {
227 dskfree_mb = dskfree_mb / config.conversion_factor;
228 }
229
230 if (verbose >= 3) {
231 printf(_("total=%.0f, free=%.0f\n"), dsktotal_mb, dskfree_mb);
232 }
233
234 dskused_mb = dsktotal_mb - dskfree_mb;
235 total_swap_mb += dsktotal_mb;
236 used_swap_mb += dskused_mb;
237 free_swap_mb += dskfree_mb;
238 }
239 }
240
241 result.metrics.free = free_swap_mb * 1024 * 1024;
242 result.metrics.used = used_swap_mb * 1024 * 1024;
243 result.metrics.total = free_swap_mb * 1024 * 1024;
244
245 /* If we get anything on STDERR, at least set warning */
246 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
247 result.statusCode = max_state(result.statusCode, STATE_WARNING);
248 // TODO Set error here
249 }
250
251 /* close stderr */
252 (void)fclose(child_stderr);
253
254 /* close the pipe */
255 if (spclose(child_process)) {
256 result.statusCode = max_state(result.statusCode, STATE_WARNING);
257 // TODO set error here
258 }
259
260 return result;
261}
262
263#ifndef CHECK_SWAP_SWAPCTL_BSD
264# define CHECK_SWAP_SWAPCTL_BSD
265
266// Stub functionality for BSD stuff, so the compiler always sees the following BSD code
267
268# define SWAP_NSWAP 0
269# define SWAP_STATS 1
270
271int bsd_swapctl(int cmd, const void *arg, int misc) {
272 (void)cmd;
273 (void)arg;
274 (void)misc;
275 return 512;
276}
277
278struct swapent {
279 dev_t se_dev; /* device id */
280 int se_flags; /* entry flags */
281 int se_nblks; /* total blocks */
282 int se_inuse; /* blocks in use */
283 int se_priority; /* priority */
284 char se_path[PATH_MAX]; /* path to entry */
285};
286
287#else
288
289// Includes for NetBSD
290# include <unistd.h>
291# include <sys/swap.h>
292
293# define bsd_swapctl swapctl
294
295#endif // CHECK_SWAP_SWAPCTL_BSD
296
297swap_result getSwapFromSwapctl_BSD(swap_config config) {
298 /* get the number of active swap devices */
299 int nswaps = bsd_swapctl(SWAP_NSWAP, NULL, 0);
300
301 /* initialize swap table + entries */
302 struct swapent *ent = (struct swapent *)malloc(sizeof(struct swapent) * (unsigned long)nswaps);
303
304 /* and now, tally 'em up */
305 int swapctl_res = bsd_swapctl(SWAP_STATS, ent, nswaps);
306 if (swapctl_res < 0) {
307 perror(_("swapctl failed: "));
308 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
309 }
310
311 double dsktotal_mb = 0.0;
312 double dskfree_mb = 0.0;
313 double dskused_mb = 0.0;
314 unsigned long long total_swap_mb = 0;
315 unsigned long long free_swap_mb = 0;
316 unsigned long long used_swap_mb = 0;
317
318 for (int i = 0; i < nswaps; i++) {
319 dsktotal_mb = (double)ent[i].se_nblks / (double)config.conversion_factor;
320 dskused_mb = (double)ent[i].se_inuse / (double)config.conversion_factor;
321 dskfree_mb = (dsktotal_mb - dskused_mb);
322
323 if (config.allswaps && dsktotal_mb > 0) {
324 double percent = 100 * (((double)dskused_mb) / ((double)dsktotal_mb));
325
326 if (verbose) {
327 printf("[%.0f (%g%%)]", dskfree_mb, 100 - percent);
328 }
329 }
330
331 total_swap_mb += (unsigned long long)dsktotal_mb;
332 free_swap_mb += (unsigned long long)dskfree_mb;
333 used_swap_mb += (unsigned long long)dskused_mb;
334 }
335
336 /* and clean up after ourselves */
337 free(ent);
338
339 swap_result result = {0};
340
341 result.statusCode = OK;
342 result.errorcode = OK;
343
344 result.metrics.total = total_swap_mb * 1024 * 1024;
345 result.metrics.free = free_swap_mb * 1024 * 1024;
346 result.metrics.used = used_swap_mb * 1024 * 1024;
347
348 return result;
349}
350
351#ifndef CHECK_SWAP_SWAPCTL_SVR4
352int srv4_swapctl(int cmd, void *arg) {
353 (void)cmd;
354 (void)arg;
355 return 512;
356}
357
358typedef struct srv4_swapent {
359 char *ste_path; /* name of the swap file */
360 off_t ste_start; /* starting block for swapping */
361 off_t ste_length; /* length of swap area */
362 long ste_pages; /* number of pages for swapping */
363 long ste_free; /* number of ste_pages free */
364 long ste_flags; /* ST_INDEL bit set if swap file */
365 /* is now being deleted */
366} swapent_t;
367
368typedef struct swaptbl {
369 int swt_n; /* number of swapents following */
370 struct srv4_swapent swt_ent[]; /* array of swt_n swapents */
371} swaptbl_t;
372
373# define SC_LIST 2
374# define SC_GETNSWP 3
375
376# ifndef MAXPATHLEN
377# define MAXPATHLEN 2048
378# endif
379
380#else
381# define srv4_swapctl swapctl
382#endif
383
384swap_result getSwapFromSwap_SRV4(swap_config config) {
385 int nswaps = 0;
386
387 /* get the number of active swap devices */
388 if ((nswaps = srv4_swapctl(SC_GETNSWP, NULL)) == -1) {
389 die(STATE_UNKNOWN, _("Error getting swap devices\n"));
390 }
391
392 if (nswaps == 0) {
393 die(STATE_OK, _("SWAP OK: No swap devices defined\n"));
394 }
395
396 if (verbose >= 3) {
397 printf("Found %d swap device(s)\n", nswaps);
398 }
399
400 /* initialize swap table + entries */
401 swaptbl_t *tbl = (swaptbl_t *)malloc(sizeof(swaptbl_t) + (sizeof(swapent_t) * (unsigned long)nswaps));
402
403 if (tbl == NULL) {
404 die(STATE_UNKNOWN, _("malloc() failed!\n"));
405 }
406
407 memset(tbl, 0, sizeof(swaptbl_t) + (sizeof(swapent_t) * (unsigned long)nswaps));
408 tbl->swt_n = nswaps;
409
410 for (int i = 0; i < nswaps; i++) {
411 if ((tbl->swt_ent[i].ste_path = (char *)malloc(sizeof(char) * MAXPATHLEN)) == NULL) {
412 die(STATE_UNKNOWN, _("malloc() failed!\n"));
413 }
414 }
415
416 /* and now, tally 'em up */
417 int swapctl_res = srv4_swapctl(SC_LIST, tbl);
418 if (swapctl_res < 0) {
419 perror(_("swapctl failed: "));
420 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
421 }
422
423 double dsktotal_mb = 0.0;
424 double dskfree_mb = 0.0;
425 double dskused_mb = 0.0;
426 unsigned long long total_swap_mb = 0;
427 unsigned long long free_swap_mb = 0;
428 unsigned long long used_swap_mb = 0;
429
430 for (int i = 0; i < nswaps; i++) {
431 dsktotal_mb = (float)tbl->swt_ent[i].ste_pages / SWAP_CONVERSION;
432 dskfree_mb = (float)tbl->swt_ent[i].ste_free / SWAP_CONVERSION;
433 dskused_mb = (dsktotal_mb - dskfree_mb);
434
435 if (verbose >= 3) {
436 printf("dsktotal_mb=%.0f dskfree_mb=%.0f dskused_mb=%.0f\n", dsktotal_mb, dskfree_mb, dskused_mb);
437 }
438
439 if (config.allswaps && dsktotal_mb > 0) {
440 double percent = 100 * (((double)dskused_mb) / ((double)dsktotal_mb));
441
442 if (verbose) {
443 printf("[%.0f (%g%%)]", dskfree_mb, 100 - percent);
444 }
445 }
446
447 total_swap_mb += (unsigned long long)dsktotal_mb;
448 free_swap_mb += (unsigned long long)dskfree_mb;
449 used_swap_mb += (unsigned long long)dskused_mb;
450 }
451
452 /* and clean up after ourselves */
453 for (int i = 0; i < nswaps; i++) {
454 free(tbl->swt_ent[i].ste_path);
455 }
456 free(tbl);
457
458 swap_result result = {0};
459 result.errorcode = OK;
460 result.metrics.total = total_swap_mb * 1024 * 1024;
461 result.metrics.free = free_swap_mb * 1024 * 1024;
462 result.metrics.used = used_swap_mb * 1024 * 1024;
463
464 return result;
465}
diff --git a/plugins/check_tcp.c b/plugins/check_tcp.c
index 01dd35eb..22dcc74e 100644
--- a/plugins/check_tcp.c
+++ b/plugins/check_tcp.c
@@ -1,714 +1,797 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_tcp plugin 3 * Monitoring check_tcp plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2013 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2025 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_tcp plugin 10 * This file contains the check_tcp plugin
11* 11 *
12* 12 *
13* This program is free software: you can redistribute it and/or modify 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 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 15 * the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16 * (at your option) any later version.
17* 17 *
18* This program is distributed in the hope that it will be useful, 18 * This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21 * GNU General Public License for more details.
22* 22 *
23* You should have received a copy of the GNU General Public License 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/>. 24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25 *
26* $Id$ 26 * $Id$
27* 27 *
28*****************************************************************************/ 28 *****************************************************************************/
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-2008"; 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))
48#else
49# define my_recv(buf, len) read(sd, buf, len)
50# define my_send(buf, len) send(sd, buf, len, 0)
51#endif 51#endif
52 return read(socket_descriptor, buf, len);
53}
52 54
53/* int my_recv(char *, size_t); */ 55ssize_t my_send(int socket_descriptor, char *buf, size_t len, bool use_tls) {
54static int process_arguments (int, char **);
55void print_help (void);
56void print_usage (void);
57
58#define EXPECT server_expect[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
89#ifdef HAVE_SSL 56#ifdef HAVE_SSL
90static char *sni = NULL; 57 if (use_tls) {
91static bool sni_specified = false; 58 return np_net_ssl_write(buf, (int)len);
59 }
92#endif 60#endif
61 return write(socket_descriptor, buf, len);
62}
93 63
94#define FLAG_SSL 0x01 64typedef struct {
95#define FLAG_VERBOSE 0x02 65 int errorcode;
96#define FLAG_TIME_WARN 0x04 66 check_tcp_config config;
97#define FLAG_TIME_CRIT 0x08 67} check_tcp_config_wrapper;
98#define FLAG_HIDE_OUTPUT 0x10 68static check_tcp_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/, check_tcp_config /*config*/);
99static size_t flags; 69void print_help(const char *service);
100 70void print_usage(void);
101int 71
102main (int argc, char **argv) 72int verbosity = 0;
103{ 73
104 int result = STATE_UNKNOWN; 74static const int READ_TIMEOUT = 2;
105 char *status = NULL; 75
106 struct timeval tv; 76const int MAXBUF = 1024;
107 struct timeval timeout; 77
108 int match = -1; 78const int DEFAULT_FTP_PORT = 21;
109 fd_set rfds; 79const int DEFAULT_POP_PORT = 110;
110 80const int DEFAULT_SPOP_PORT = 995;
111 FD_ZERO(&rfds); 81const int DEFAULT_SMTP_PORT = 25;
112 82const int DEFAULT_SSMTP_PORT = 465;
113 setlocale (LC_ALL, ""); 83const int DEFAULT_IMAP_PORT = 143;
114 bindtextdomain (PACKAGE, LOCALEDIR); 84const int DEFAULT_SIMAP_PORT = 993;
115 textdomain (PACKAGE); 85const int DEFAULT_XMPP_C2S_PORT = 5222;
86const int DEFAULT_NNTP_PORT = 119;
87const int DEFAULT_NNTPS_PORT = 563;
88const int DEFAULT_CLAMD_PORT = 3310;
89
90int main(int argc, char **argv) {
91 setlocale(LC_ALL, "");
92 bindtextdomain(PACKAGE, LOCALEDIR);
93 textdomain(PACKAGE);
116 94
117 /* determine program- and service-name quickly */ 95 /* determine program- and service-name quickly */
118 progname = strrchr(argv[0], '/'); 96 progname = strrchr(argv[0], '/');
119 if(progname != NULL) progname++; 97 if (progname != NULL) {
120 else progname = argv[0]; 98 progname++;
99 } else {
100 progname = argv[0];
101 }
102
103 // Initialize config here with values from above,
104 // might be changed by on disk config or cli commands
105 check_tcp_config config = check_tcp_config_init();
121 106
122 size_t prog_name_len = strlen(progname); 107 size_t prog_name_len = strlen(progname);
123 if(prog_name_len > 6 && !memcmp(progname, "check_", 6)) { 108 const size_t prefix_length = strlen("check_");
124 SERVICE = strdup(progname + 6); 109
125 for(size_t i = 0; i < prog_name_len - 6; i++) 110 if (prog_name_len <= prefix_length) {
126 SERVICE[i] = toupper(SERVICE[i]); 111 die(STATE_UNKNOWN, _("Weird progname"));
112 }
113
114 if (!memcmp(progname, "check_", prefix_length)) {
115 config.service = strdup(progname + prefix_length);
116 if (config.service == NULL) {
117 die(STATE_UNKNOWN, _("Allocation failed"));
118 }
119
120 for (size_t i = 0; i < prog_name_len - prefix_length; i++) {
121 config.service[i] = toupper(config.service[i]);
122 }
127 } 123 }
128 124
129 /* set up a reasonable buffer at first (will be realloc()'ed if 125 /* set up a reasonable buffer at first (will be realloc()'ed if
130 * user specifies other options) */ 126 * user specifies other options) */
131 server_expect = calloc(sizeof(char *), 2); 127 config.server_expect = calloc(2, sizeof(char *));
132 128
133 /* determine defaults for this service's protocol */ 129 if (config.server_expect == NULL) {
134 if (!strncmp(SERVICE, "UDP", 3)) { 130 die(STATE_UNKNOWN, _("Allocation failed"));
135 PROTOCOL = IPPROTO_UDP;
136 }
137 else if (!strncmp(SERVICE, "FTP", 3)) {
138 EXPECT = "220";
139 QUIT = "QUIT\r\n";
140 PORT = 21;
141 }
142 else if (!strncmp(SERVICE, "POP", 3) || !strncmp(SERVICE, "POP3", 4)) {
143 EXPECT = "+OK";
144 QUIT = "QUIT\r\n";
145 PORT = 110;
146 }
147 else if (!strncmp(SERVICE, "SMTP", 4)) {
148 EXPECT = "220";
149 QUIT = "QUIT\r\n";
150 PORT = 25;
151 } 131 }
152 else if (!strncmp(SERVICE, "IMAP", 4)) { 132
153 EXPECT = "* OK"; 133 /* determine defaults for this service's protocol */
154 QUIT = "a1 LOGOUT\r\n"; 134 if (!strncmp(config.service, "UDP", strlen("UDP"))) {
155 PORT = 143; 135 config.protocol = IPPROTO_UDP;
136 } else if (!strncmp(config.service, "FTP", strlen("FTP"))) {
137 config.server_expect[0] = "220";
138 config.quit = "QUIT\r\n";
139 config.server_port = DEFAULT_FTP_PORT;
140 } else if (!strncmp(config.service, "POP", strlen("POP")) || !strncmp(config.service, "POP3", strlen("POP3"))) {
141 config.server_expect[0] = "+OK";
142 config.quit = "QUIT\r\n";
143 config.server_port = DEFAULT_POP_PORT;
144 } else if (!strncmp(config.service, "SMTP", strlen("SMTP"))) {
145 config.server_expect[0] = "220";
146 config.quit = "QUIT\r\n";
147 config.server_port = DEFAULT_SMTP_PORT;
148 } else if (!strncmp(config.service, "IMAP", strlen("IMAP"))) {
149 config.server_expect[0] = "* OK";
150 config.quit = "a1 LOGOUT\r\n";
151 config.server_port = DEFAULT_IMAP_PORT;
156 } 152 }
157#ifdef HAVE_SSL 153#ifdef HAVE_SSL
158 else if (!strncmp(SERVICE, "SIMAP", 5)) { 154 else if (!strncmp(config.service, "SIMAP", strlen("SIMAP"))) {
159 EXPECT = "* OK"; 155 config.server_expect[0] = "* OK";
160 QUIT = "a1 LOGOUT\r\n"; 156 config.quit = "a1 LOGOUT\r\n";
161 flags |= FLAG_SSL; 157 config.use_tls = true;
162 PORT = 993; 158 config.server_port = DEFAULT_SIMAP_PORT;
163 } 159 } else if (!strncmp(config.service, "SPOP", strlen("SPOP"))) {
164 else if (!strncmp(SERVICE, "SPOP", 4)) { 160 config.server_expect[0] = "+OK";
165 EXPECT = "+OK"; 161 config.quit = "QUIT\r\n";
166 QUIT = "QUIT\r\n"; 162 config.use_tls = true;
167 flags |= FLAG_SSL; 163 config.server_port = DEFAULT_SPOP_PORT;
168 PORT = 995; 164 } else if (!strncmp(config.service, "SSMTP", strlen("SSMTP"))) {
169 } 165 config.server_expect[0] = "220";
170 else if (!strncmp(SERVICE, "SSMTP", 5)) { 166 config.quit = "QUIT\r\n";
171 EXPECT = "220"; 167 config.use_tls = true;
172 QUIT = "QUIT\r\n"; 168 config.server_port = DEFAULT_SSMTP_PORT;
173 flags |= FLAG_SSL; 169 } else if (!strncmp(config.service, "JABBER", strlen("JABBER"))) {
174 PORT = 465; 170 config.send = "<stream:stream to=\'host\' xmlns=\'jabber:client\' xmlns:stream=\'http://etherx.jabber.org/streams\'>\n";
175 } 171 config.server_expect[0] = "<?xml version=\'1.0\'";
176 else if (!strncmp(SERVICE, "JABBER", 6)) { 172 config.quit = "</stream:stream>\n";
177 SEND = "<stream:stream to=\'host\' xmlns=\'jabber:client\' xmlns:stream=\'http://etherx.jabber.org/streams\'>\n"; 173 config.hide_output = true;
178 EXPECT = "<?xml version=\'1.0\'"; 174 config.server_port = DEFAULT_XMPP_C2S_PORT;
179 QUIT = "</stream:stream>\n"; 175 } else if (!strncmp(config.service, "NNTPS", strlen("NNTPS"))) {
180 flags |= FLAG_HIDE_OUTPUT; 176 config.server_expect_count = 2;
181 PORT = 5222; 177 config.server_expect[0] = "200";
182 } 178 config.server_expect[1] = "201";
183 else if (!strncmp (SERVICE, "NNTPS", 5)) { 179 config.quit = "QUIT\r\n";
184 server_expect_count = 2; 180 config.use_tls = true;
185 server_expect[0] = "200"; 181 config.server_port = DEFAULT_NNTPS_PORT;
186 server_expect[1] = "201";
187 QUIT = "QUIT\r\n";
188 flags |= FLAG_SSL;
189 PORT = 563;
190 } 182 }
191#endif 183#endif
192 else if (!strncmp (SERVICE, "NNTP", 4)) { 184 else if (!strncmp(config.service, "NNTP", strlen("NNTP"))) {
193 server_expect_count = 2; 185 config.server_expect_count = 2;
194 server_expect = malloc(sizeof(char *) * server_expect_count); 186 char **tmp = realloc(config.server_expect, config.server_expect_count * sizeof(char *));
195 server_expect[0] = strdup("200"); 187 if (tmp == NULL) {
196 server_expect[1] = strdup("201"); 188 free(config.server_expect);
197 QUIT = "QUIT\r\n"; 189 die(STATE_UNKNOWN, _("Allocation failed"));
198 PORT = 119; 190 }
199 } 191 config.server_expect = tmp;
200 else if (!strncmp(SERVICE, "CLAMD", 5)) { 192
201 SEND = "PING"; 193 config.server_expect[0] = strdup("200");
202 EXPECT = "PONG"; 194 config.server_expect[1] = strdup("201");
203 QUIT = NULL; 195 config.quit = "QUIT\r\n";
204 PORT = 3310; 196 config.server_port = DEFAULT_NNTP_PORT;
197 } else if (!strncmp(config.service, "CLAMD", strlen("CLAMD"))) {
198 config.send = "PING";
199 config.server_expect[0] = "PONG";
200 config.quit = NULL;
201 config.server_port = DEFAULT_CLAMD_PORT;
205 } 202 }
206 /* fallthrough check, so it's supposed to use reverse matching */ 203 /* fallthrough check, so it's supposed to use reverse matching */
207 else if (strcmp (SERVICE, "TCP")) 204 else if (strcmp(config.service, "TCP")) {
208 usage (_("CRITICAL - Generic check_tcp called with unknown service\n")); 205 usage(_("CRITICAL - Generic check_tcp called with unknown service\n"));
209 206 }
210 server_address = "127.0.0.1";
211 server_port = PORT;
212 server_send = SEND;
213 server_quit = QUIT;
214 status = NULL;
215 207
216 /* Parse extra opts if any */ 208 /* Parse extra opts if any */
217 argv=np_extra_opts (&argc, argv, progname); 209 argv = np_extra_opts(&argc, argv, progname);
210
211 check_tcp_config_wrapper paw = process_arguments(argc, argv, config);
212 if (paw.errorcode == ERROR) {
213 usage4(_("Could not parse arguments"));
214 }
218 215
219 if (process_arguments (argc, argv) == ERROR) 216 config = paw.config;
220 usage4 (_("Could not parse arguments"));
221 217
222 if(flags & FLAG_VERBOSE) { 218 if (verbosity > 0) {
223 printf("Using service %s\n", SERVICE); 219 printf("Using service %s\n", config.service);
224 printf("Port: %d\n", server_port); 220 printf("Port: %d\n", config.server_port);
225 printf("flags: 0x%x\n", (int)flags);
226 } 221 }
227 222
228 if(EXPECT && !server_expect_count) 223 if ((config.server_expect_count == 0) && config.server_expect[0]) {
229 server_expect_count++; 224 config.server_expect_count++;
225 }
230 226
231 if(PROTOCOL==IPPROTO_UDP && !(server_expect_count && server_send)){ 227 if (config.protocol == IPPROTO_UDP && !(config.server_expect_count && config.send)) {
232 usage(_("With UDP checks, a send/expect string must be specified.")); 228 usage(_("With UDP checks, a send/expect string must be specified."));
233 } 229 }
234 230
231 // Initialize check stuff before setting timers
232 mp_check overall = mp_check_init();
233 if (config.output_format_set) {
234 mp_set_format(config.output_format);
235 }
236
235 /* set up the timer */ 237 /* set up the timer */
236 signal (SIGALRM, socket_timeout_alarm_handler); 238 signal(SIGALRM, socket_timeout_alarm_handler);
237 alarm (socket_timeout); 239 alarm(socket_timeout);
238 240
239 /* try to connect to the host at the given port number */ 241 /* try to connect to the host at the given port number */
240 gettimeofday (&tv, NULL); 242 struct timeval start_time;
241 243 gettimeofday(&start_time, NULL);
242 result = np_net_connect (server_address, server_port, &sd, PROTOCOL); 244
243 if (result == STATE_CRITICAL) return econn_refuse_state; 245 int socket_descriptor = 0;
246 mp_subcheck inital_connect_result = mp_subcheck_init();
247
248 // Try initial connection
249 if (np_net_connect(config.server_address, config.server_port, &socket_descriptor, config.protocol) == STATE_CRITICAL) {
250 // Early exit here, we got connection refused
251 inital_connect_result = mp_set_subcheck_state(inital_connect_result, config.econn_refuse_state);
252 xasprintf(&inital_connect_result.output, "Connection to %s on port %i was REFUSED", config.server_address, config.server_port);
253 mp_add_subcheck_to_check(&overall, inital_connect_result);
254 mp_exit(overall);
255 } else {
256 inital_connect_result = mp_set_subcheck_state(inital_connect_result, STATE_OK);
257 xasprintf(&inital_connect_result.output, "Connection to %s on port %i was a SUCCESS", config.server_address, config.server_port);
258 mp_add_subcheck_to_check(&overall, inital_connect_result);
259 }
244 260
245#ifdef HAVE_SSL 261#ifdef HAVE_SSL
246 if (flags & FLAG_SSL){ 262 if (config.use_tls) {
247 result = np_net_ssl_init_with_hostname(sd, (sni_specified ? sni : NULL)); 263 mp_subcheck tls_connection_result = mp_subcheck_init();
248 if (result == STATE_OK && check_cert) { 264 mp_state_enum result = np_net_ssl_init_with_hostname(socket_descriptor, (config.sni_specified ? config.sni : NULL));
249 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit); 265 tls_connection_result = mp_set_subcheck_default_state(tls_connection_result, result);
266
267 if (result == STATE_OK) {
268 xasprintf(&tls_connection_result.output, "TLS connection succeeded");
269
270 if (config.check_cert) {
271 result = np_net_ssl_check_cert(config.days_till_exp_warn, config.days_till_exp_crit);
272
273 mp_subcheck tls_certificate_lifetime_result = mp_subcheck_init();
274 tls_certificate_lifetime_result = mp_set_subcheck_state(tls_certificate_lifetime_result, result);
275
276 if (result == STATE_OK) {
277 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is within thresholds");
278 } else if (result == STATE_WARNING) {
279 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is violating warning threshold (%i)",
280 config.days_till_exp_warn);
281 } else if (result == STATE_CRITICAL) {
282 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is violating critical threshold (%i)",
283 config.days_till_exp_crit);
284 } else {
285 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is somehow unknown");
286 }
287
288 mp_add_subcheck_to_subcheck(&tls_connection_result, tls_certificate_lifetime_result);
289 }
290
291 mp_add_subcheck_to_check(&overall, tls_connection_result);
292 } else {
293 xasprintf(&tls_connection_result.output, "TLS connection failed");
294 mp_add_subcheck_to_check(&overall, tls_connection_result);
295
296 if (socket_descriptor) {
297 close(socket_descriptor);
298 }
299 np_net_ssl_cleanup();
300
301 mp_exit(overall);
250 } 302 }
251 } 303 }
252 if(result != STATE_OK){
253 if(sd) close(sd);
254 np_net_ssl_cleanup();
255 return result;
256 }
257#endif /* HAVE_SSL */ 304#endif /* HAVE_SSL */
258 305
259 if (server_send != NULL) { /* Something to send? */ 306 if (config.send != NULL) { /* Something to send? */
260 my_send(server_send, strlen(server_send)); 307 my_send(socket_descriptor, config.send, strlen(config.send), config.use_tls);
261 } 308 }
262 309
263 if (delay > 0) { 310 if (config.delay > 0) {
264 tv.tv_sec += delay; 311 start_time.tv_sec += config.delay;
265 sleep (delay); 312 sleep(config.delay);
266 } 313 }
267 314
268 if(flags & FLAG_VERBOSE) { 315 if (verbosity > 0) {
269 if (server_send) { 316 if (config.send) {
270 printf("Send string: %s\n", server_send); 317 printf("Send string: %s\n", config.send);
318 }
319 if (config.quit) {
320 printf("Quit string: %s\n", config.quit);
271 } 321 }
272 if (server_quit) { 322 printf("server_expect_count: %d\n", (int)config.server_expect_count);
273 printf("Quit string: %s\n", server_quit); 323 for (size_t i = 0; i < config.server_expect_count; i++) {
324 printf("\t%zd: %s\n", i, config.server_expect[i]);
274 } 325 }
275 printf("server_expect_count: %d\n", (int)server_expect_count);
276 for(size_t i = 0; i < server_expect_count; i++)
277 printf("\t%zd: %s\n", i, server_expect[i]);
278 } 326 }
279 327
280 /* if(len) later on, we know we have a non-NULL response */ 328 /* if(len) later on, we know we have a non-NULL response */
281 ssize_t len = 0; 329 ssize_t len = 0;
330 char *received_buffer = NULL;
331 enum np_match_result match = NP_MATCH_NONE;
332 mp_subcheck expected_data_result = mp_subcheck_init();
282 333
283 if (server_expect_count) { 334 if (config.server_expect_count) {
284 ssize_t received = 0; 335 ssize_t received = 0;
336 char buffer[MAXBUF];
285 337
286 /* watch for the expect string */ 338 /* watch for the expect string */
287 while ((received = my_recv(buffer, sizeof(buffer))) > 0) { 339 while ((received = my_recv(socket_descriptor, buffer, sizeof(buffer), config.use_tls)) > 0) {
288 status = realloc(status, len + received + 1); 340 received_buffer = realloc(received_buffer, len + received + 1);
289 memcpy(&status[len], buffer, received); 341
342 if (received_buffer == NULL) {
343 die(STATE_UNKNOWN, _("Allocation failed"));
344 }
345
346 memcpy(&received_buffer[len], buffer, received);
290 len += received; 347 len += received;
291 status[len] = '\0'; 348 received_buffer[len] = '\0';
292 349
293 /* stop reading if user-forced */ 350 /* stop reading if user-forced */
294 if (maxbytes && len >= maxbytes) 351 if (config.maxbytes && len >= config.maxbytes) {
295 break; 352 break;
353 }
296 354
297 if ((match = np_expect_match(status, 355 if ((match = np_expect_match(received_buffer, config.server_expect, config.server_expect_count, config.match_flags)) !=
298 server_expect, 356 NP_MATCH_RETRY) {
299 server_expect_count,
300 match_flags)) != NP_MATCH_RETRY)
301 break; 357 break;
358 }
359
360 fd_set rfds;
361 FD_ZERO(&rfds);
362 FD_SET(socket_descriptor, &rfds);
302 363
303 /* some protocols wait for further input, so make sure we don't wait forever */ 364 /* some protocols wait for further input, so make sure we don't wait forever */
304 FD_SET(sd, &rfds); 365 struct timeval timeout;
305 timeout.tv_sec = READ_TIMEOUT; 366 timeout.tv_sec = READ_TIMEOUT;
306 timeout.tv_usec = 0; 367 timeout.tv_usec = 0;
307 if(select(sd + 1, &rfds, NULL, NULL, &timeout) <= 0) 368
369 if (select(socket_descriptor + 1, &rfds, NULL, NULL, &timeout) <= 0) {
308 break; 370 break;
371 }
309 } 372 }
310 373
311 if (match == NP_MATCH_RETRY) 374 if (match == NP_MATCH_RETRY) {
312 match = NP_MATCH_FAILURE; 375 match = NP_MATCH_FAILURE;
376 }
313 377
314 /* no data when expected, so return critical */ 378 /* no data when expected, so return critical */
315 if (len == 0) 379 if (len == 0) {
316 die (STATE_CRITICAL, _("No data received from host\n")); 380 xasprintf(&expected_data_result.output, "Received no data when some was expected");
381 expected_data_result = mp_set_subcheck_state(expected_data_result, STATE_CRITICAL);
382 mp_add_subcheck_to_check(&overall, expected_data_result);
383 mp_exit(overall);
384 }
317 385
318 /* print raw output if we're debugging */ 386 /* print raw output if we're debugging */
319 if(flags & FLAG_VERBOSE) 387 if (verbosity > 0) {
320 printf("received %d bytes from host\n#-raw-recv-------#\n%s\n#-raw-recv-------#\n", 388 printf("received %d bytes from host\n#-raw-recv-------#\n%s\n#-raw-recv-------#\n", (int)len + 1, received_buffer);
321 (int)len + 1, status); 389 }
322 /* strip whitespace from end of output */ 390 /* strip whitespace from end of output */
323 while(--len > 0 && isspace(status[len])) 391 while (--len > 0 && isspace(received_buffer[len])) {
324 status[len] = '\0'; 392 received_buffer[len] = '\0';
393 }
394 }
395
396 if (config.quit != NULL) {
397 my_send(socket_descriptor, config.quit, strlen(config.quit), config.use_tls);
325 } 398 }
326 399
327 if (server_quit != NULL) { 400 if (socket_descriptor) {
328 my_send(server_quit, strlen(server_quit)); 401 close(socket_descriptor);
329 } 402 }
330 if (sd) close (sd);
331#ifdef HAVE_SSL 403#ifdef HAVE_SSL
332 np_net_ssl_cleanup(); 404 np_net_ssl_cleanup();
333#endif 405#endif
334 406
335 microsec = deltime (tv); 407 long microsec = deltime(start_time);
336 elapsed_time = (double)microsec / 1.0e6; 408 double elapsed_time = (double)microsec / 1.0e6;
337 409
338 if (flags & FLAG_TIME_CRIT && elapsed_time > critical_time) 410 mp_subcheck elapsed_time_result = mp_subcheck_init();
339 result = STATE_CRITICAL;
340 else if (flags & FLAG_TIME_WARN && elapsed_time > warning_time)
341 result = STATE_WARNING;
342 411
343 /* did we get the response we hoped? */ 412 mp_perfdata time_pd = perfdata_init();
344 if(match == NP_MATCH_FAILURE && result != STATE_CRITICAL) 413 time_pd = mp_set_pd_value(time_pd, elapsed_time);
345 result = expect_mismatch_state; 414 time_pd.label = "time";
415 time_pd.uom = "s";
346 416
347 /* reset the alarm */ 417 if (config.critical_time_set && elapsed_time > config.critical_time) {
348 alarm (0); 418 xasprintf(&elapsed_time_result.output, "Connection time %fs exceeded critical threshold (%f)", elapsed_time, config.critical_time);
349 419
350 /* this is a bit stupid, because we don't want to print the 420 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_CRITICAL);
351 * response time (which can look ok to the user) if we didn't get 421 time_pd.crit_present = true;
352 * the response we were looking for. if-else */ 422 mp_range crit_val = mp_range_init();
353 printf("%s %s - ", SERVICE, state_text(result)); 423
354 424 crit_val.end = mp_create_pd_value(config.critical_time);
355 if(match == NP_MATCH_FAILURE && len && !(flags & FLAG_HIDE_OUTPUT)) 425 crit_val.end_infinity = false;
356 printf("Unexpected response from host/socket: %s", status); 426
357 else { 427 time_pd.crit = crit_val;
358 if(match == NP_MATCH_FAILURE) 428 } else if (config.warning_time_set && elapsed_time > config.warning_time) {
359 printf("Unexpected response from host/socket on "); 429 xasprintf(&elapsed_time_result.output, "Connection time %fs exceeded warning threshold (%f)", elapsed_time, config.critical_time);
360 else 430
361 printf("%.3f second response time on ", elapsed_time); 431 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_WARNING);
362 if(server_address[0] != '/') { 432 time_pd.warn_present = true;
363 if (host_specified) 433 mp_range warn_val = mp_range_init();
364 printf("%s port %d", 434 warn_val.end = mp_create_pd_value(config.critical_time);
365 server_address, server_port); 435 warn_val.end_infinity = false;
366 else 436
367 printf("port %d", server_port); 437 time_pd.warn = warn_val;
368 } 438 } else {
369 else 439 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_OK);
370 printf("socket %s", server_address); 440 xasprintf(&elapsed_time_result.output, "Connection time %fs is within thresholds", elapsed_time);
371 } 441 }
372 442
373 if (match != NP_MATCH_FAILURE && !(flags & FLAG_HIDE_OUTPUT) && len) 443 mp_add_perfdata_to_subcheck(&elapsed_time_result, time_pd);
374 printf (" [%s]", status); 444 mp_add_subcheck_to_check(&overall, elapsed_time_result);
375
376 /* perf-data doesn't apply when server doesn't talk properly,
377 * so print all zeroes on warn and crit. Use fperfdata since
378 * localisation settings can make different outputs */
379 if(match == NP_MATCH_FAILURE)
380 printf ("|%s",
381 fperfdata ("time", elapsed_time, "s",
382 (flags & FLAG_TIME_WARN ? true : false), 0,
383 (flags & FLAG_TIME_CRIT ? true : false), 0,
384 true, 0,
385 true, socket_timeout)
386 );
387 else
388 printf("|%s",
389 fperfdata ("time", elapsed_time, "s",
390 (flags & FLAG_TIME_WARN ? true : false), warning_time,
391 (flags & FLAG_TIME_CRIT ? true : false), critical_time,
392 true, 0,
393 true, socket_timeout)
394 );
395
396 putchar('\n');
397 return result;
398}
399 445
446 /* did we get the response we hoped? */
447 if (match == NP_MATCH_FAILURE) {
448 expected_data_result = mp_set_subcheck_state(expected_data_result, config.expect_mismatch_state);
449 xasprintf(&expected_data_result.output, "Answer failed to match expectation");
450 mp_add_subcheck_to_check(&overall, expected_data_result);
451 } else if (match == NP_MATCH_SUCCESS) {
452 expected_data_result = mp_set_subcheck_state(expected_data_result, STATE_OK);
453 xasprintf(&expected_data_result.output, "The answer of the server matched the expectation");
454 mp_add_subcheck_to_check(&overall, expected_data_result);
455 }
400 456
457 /* reset the alarm */
458 alarm(0);
401 459
402/* process command-line arguments */ 460 mp_exit(overall);
403static int process_arguments (int argc, char **argv) { 461}
404 int c;
405 bool escape = false;
406 char *temp;
407 462
463/* process command-line arguments */
464static check_tcp_config_wrapper process_arguments(int argc, char **argv, check_tcp_config config) {
408 enum { 465 enum {
409 SNI_OPTION = CHAR_MAX + 1 466 SNI_OPTION = CHAR_MAX + 1,
467 output_format_index,
410 }; 468 };
411 469
412 int option = 0; 470 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
413 static struct option longopts[] = { 471 {"critical", required_argument, 0, 'c'},
414 {"hostname", required_argument, 0, 'H'}, 472 {"warning", required_argument, 0, 'w'},
415 {"critical", required_argument, 0, 'c'}, 473 {"critical-codes", required_argument, 0, 'C'},
416 {"warning", required_argument, 0, 'w'}, 474 {"warning-codes", required_argument, 0, 'W'},
417 {"critical-codes", required_argument, 0, 'C'}, 475 {"timeout", required_argument, 0, 't'},
418 {"warning-codes", required_argument, 0, 'W'}, 476 {"protocol", required_argument, 0, 'P'}, /* FIXME: Unhandled */
419 {"timeout", required_argument, 0, 't'}, 477 {"port", required_argument, 0, 'p'},
420 {"protocol", required_argument, 0, 'P'}, /* FIXME: Unhandled */ 478 {"escape", no_argument, 0, 'E'},
421 {"port", required_argument, 0, 'p'}, 479 {"all", no_argument, 0, 'A'},
422 {"escape", no_argument, 0, 'E'}, 480 {"send", required_argument, 0, 's'},
423 {"all", no_argument, 0, 'A'}, 481 {"expect", required_argument, 0, 'e'},
424 {"send", required_argument, 0, 's'}, 482 {"maxbytes", required_argument, 0, 'm'},
425 {"expect", required_argument, 0, 'e'}, 483 {"quit", required_argument, 0, 'q'},
426 {"maxbytes", required_argument, 0, 'm'}, 484 {"jail", no_argument, 0, 'j'},
427 {"quit", required_argument, 0, 'q'}, 485 {"delay", required_argument, 0, 'd'},
428 {"jail", no_argument, 0, 'j'}, 486 {"refuse", required_argument, 0, 'r'},
429 {"delay", required_argument, 0, 'd'}, 487 {"mismatch", required_argument, 0, 'M'},
430 {"refuse", required_argument, 0, 'r'}, 488 {"use-ipv4", no_argument, 0, '4'},
431 {"mismatch", required_argument, 0, 'M'}, 489 {"use-ipv6", no_argument, 0, '6'},
432 {"use-ipv4", no_argument, 0, '4'}, 490 {"verbose", no_argument, 0, 'v'},
433 {"use-ipv6", no_argument, 0, '6'}, 491 {"version", no_argument, 0, 'V'},
434 {"verbose", no_argument, 0, 'v'}, 492 {"help", no_argument, 0, 'h'},
435 {"version", no_argument, 0, 'V'}, 493 {"ssl", no_argument, 0, 'S'},
436 {"help", no_argument, 0, 'h'}, 494 {"sni", required_argument, 0, SNI_OPTION},
437 {"ssl", no_argument, 0, 'S'}, 495 {"certificate", required_argument, 0, 'D'},
438 {"sni", required_argument, 0, SNI_OPTION}, 496 {"output-format", required_argument, 0, output_format_index},
439 {"certificate", required_argument, 0, 'D'}, 497 {0, 0, 0, 0}};
440 {0, 0, 0, 0} 498
441 }; 499 if (argc < 2) {
442 500 usage4(_("No arguments found"));
443 if (argc < 2) 501 }
444 usage4 (_("No arguments found"));
445 502
446 /* backwards compatibility */ 503 /* backwards compatibility */
447 for (c = 1; c < argc; c++) { 504 for (int i = 1; i < argc; i++) {
448 if (strcmp ("-to", argv[c]) == 0) 505 if (strcmp("-to", argv[i]) == 0) {
449 strcpy (argv[c], "-t"); 506 strcpy(argv[i], "-t");
450 else if (strcmp ("-wt", argv[c]) == 0) 507 } else if (strcmp("-wt", argv[i]) == 0) {
451 strcpy (argv[c], "-w"); 508 strcpy(argv[i], "-w");
452 else if (strcmp ("-ct", argv[c]) == 0) 509 } else if (strcmp("-ct", argv[i]) == 0) {
453 strcpy (argv[c], "-c"); 510 strcpy(argv[i], "-c");
511 }
454 } 512 }
455 513
456 if (!is_option (argv[1])) { 514 if (!is_option(argv[1])) {
457 server_address = argv[1]; 515 config.server_address = argv[1];
458 argv[1] = argv[0]; 516 argv[1] = argv[0];
459 argv = &argv[1]; 517 argv = &argv[1];
460 argc--; 518 argc--;
461 } 519 }
462 520
463 while (1) { 521 bool escape = false;
464 c = getopt_long (argc, argv, "+hVv46EAH:s:e:q:m:c:w:t:p:C:W:d:Sr:jD:M:", 522
465 longopts, &option); 523 while (true) {
524 int option = 0;
525 int option_index = getopt_long(argc, argv, "+hVv46EAH:s:e:q:m:c:w:t:p:C:W:d:Sr:jD:M:", longopts, &option);
466 526
467 if (c == -1 || c == EOF || c == 1) 527 if (option_index == -1 || option_index == EOF || option_index == 1) {
468 break; 528 break;
529 }
469 530
470 switch (c) { 531 switch (option_index) {
471 case '?': /* print short usage statement if args not parsable */ 532 case '?': /* print short usage statement if args not parsable */
472 usage5 (); 533 usage5();
473 case 'h': /* help */ 534 case 'h': /* help */
474 print_help (); 535 print_help(config.service);
475 exit (STATE_UNKNOWN); 536 exit(STATE_UNKNOWN);
476 case 'V': /* version */ 537 case 'V': /* version */
477 print_revision (progname, NP_VERSION); 538 print_revision(progname, NP_VERSION);
478 exit (STATE_UNKNOWN); 539 exit(STATE_UNKNOWN);
479 case 'v': /* verbose mode */ 540 case 'v': /* verbose mode */
480 flags |= FLAG_VERBOSE; 541 verbosity++;
481 match_flags |= NP_MATCH_VERBOSE; 542 config.match_flags |= NP_MATCH_VERBOSE;
482 break; 543 break;
483 case '4': 544 case '4': // Apparently unused TODO
484 address_family = AF_INET; 545 address_family = AF_INET;
485 break; 546 break;
486 case '6': 547 case '6': // Apparently unused TODO
487#ifdef USE_IPV6 548#ifdef USE_IPV6
488 address_family = AF_INET6; 549 address_family = AF_INET6;
489#else 550#else
490 usage4 (_("IPv6 support not available")); 551 usage4(_("IPv6 support not available"));
491#endif 552#endif
492 break; 553 break;
493 case 'H': /* hostname */ 554 case 'H': /* hostname */
494 host_specified = true; 555 config.host_specified = true;
495 server_address = optarg; 556 config.server_address = optarg;
496 break;
497 case 'c': /* critical */
498 critical_time = strtod (optarg, NULL);
499 flags |= FLAG_TIME_CRIT;
500 break; 557 break;
501 case 'j': /* hide output */ 558 case 'c': /* critical */
502 flags |= FLAG_HIDE_OUTPUT; 559 config.critical_time = strtod(optarg, NULL);
560 config.critical_time_set = true;
503 break; 561 break;
504 case 'w': /* warning */ 562 case 'j': /* hide output */
505 warning_time = strtod (optarg, NULL); 563 config.hide_output = true;
506 flags |= FLAG_TIME_WARN;
507 break; 564 break;
508 case 'C': 565 case 'w': /* warning */
509 crit_codes = realloc (crit_codes, ++crit_codes_count); 566 config.warning_time = strtod(optarg, NULL);
510 crit_codes[crit_codes_count - 1] = optarg; 567 config.warning_time_set = true;
511 break; 568 break;
512 case 'W': 569 case 't': /* timeout */
513 warn_codes = realloc (warn_codes, ++warn_codes_count); 570 if (!is_intpos(optarg)) {
514 warn_codes[warn_codes_count - 1] = optarg; 571 usage4(_("Timeout interval must be a positive integer"));
515 break; 572 } else {
516 case 't': /* timeout */ 573 socket_timeout = atoi(optarg);
517 if (!is_intpos (optarg)) 574 }
518 usage4 (_("Timeout interval must be a positive integer"));
519 else
520 socket_timeout = atoi (optarg);
521 break; 575 break;
522 case 'p': /* port */ 576 case 'p': /* port */
523 if (!is_intpos (optarg)) 577 if (!is_intpos(optarg)) {
524 usage4 (_("Port must be a positive integer")); 578 usage4(_("Port must be a positive integer"));
525 else 579 } else {
526 server_port = atoi (optarg); 580 config.server_port = atoi(optarg);
581 }
527 break; 582 break;
528 case 'E': 583 case 'E':
529 escape = true; 584 escape = true;
530 break; 585 break;
531 case 's': 586 case 's':
532 if (escape) 587 if (escape) {
533 server_send = np_escaped_string(optarg); 588 config.send = np_escaped_string(optarg);
534 else 589 } else {
535 xasprintf(&server_send, "%s", optarg); 590 xasprintf(&config.send, "%s", optarg);
591 }
536 break; 592 break;
537 case 'e': /* expect string (may be repeated) */ 593 case 'e': /* expect string (may be repeated) */
538 match_flags &= ~NP_MATCH_EXACT; 594 config.match_flags &= ~NP_MATCH_EXACT;
539 if (server_expect_count == 0) 595 if (config.server_expect_count == 0) {
540 server_expect = malloc (sizeof (char *) * (++server_expect_count)); 596 config.server_expect = malloc(sizeof(char *) * (++config.server_expect_count));
541 else 597 } else {
542 server_expect = realloc (server_expect, sizeof (char *) * (++server_expect_count)); 598 config.server_expect = realloc(config.server_expect, sizeof(char *) * (++config.server_expect_count));
543 server_expect[server_expect_count - 1] = optarg; 599 }
600
601 if (config.server_expect == NULL) {
602 die(STATE_UNKNOWN, _("Allocation failed"));
603 }
604 config.server_expect[config.server_expect_count - 1] = optarg;
544 break; 605 break;
545 case 'm': 606 case 'm':
546 if (!is_intpos (optarg)) 607 if (!is_intpos(optarg)) {
547 usage4 (_("Maxbytes must be a positive integer")); 608 usage4(_("Maxbytes must be a positive integer"));
548 else 609 } else {
549 maxbytes = strtol (optarg, NULL, 0); 610 config.maxbytes = strtol(optarg, NULL, 0);
611 }
550 break; 612 break;
551 case 'q': 613 case 'q':
552 if (escape) 614 if (escape) {
553 server_quit = np_escaped_string(optarg); 615 config.quit = np_escaped_string(optarg);
554 else 616 } else {
555 xasprintf(&server_quit, "%s\r\n", optarg); 617 xasprintf(&config.quit, "%s\r\n", optarg);
618 }
556 break; 619 break;
557 case 'r': 620 case 'r':
558 if (!strncmp(optarg,"ok",2)) 621 if (!strncmp(optarg, "ok", 2)) {
559 econn_refuse_state = STATE_OK; 622 config.econn_refuse_state = STATE_OK;
560 else if (!strncmp(optarg,"warn",4)) 623 } else if (!strncmp(optarg, "warn", 4)) {
561 econn_refuse_state = STATE_WARNING; 624 config.econn_refuse_state = STATE_WARNING;
562 else if (!strncmp(optarg,"crit",4)) 625 } else if (!strncmp(optarg, "crit", 4)) {
563 econn_refuse_state = STATE_CRITICAL; 626 config.econn_refuse_state = STATE_CRITICAL;
564 else 627 } else {
565 usage4 (_("Refuse must be one of ok, warn, crit")); 628 usage4(_("Refuse must be one of ok, warn, crit"));
629 }
566 break; 630 break;
567 case 'M': 631 case 'M':
568 if (!strncmp(optarg,"ok",2)) 632 if (!strncmp(optarg, "ok", 2)) {
569 expect_mismatch_state = STATE_OK; 633 config.expect_mismatch_state = STATE_OK;
570 else if (!strncmp(optarg,"warn",4)) 634 } else if (!strncmp(optarg, "warn", 4)) {
571 expect_mismatch_state = STATE_WARNING; 635 config.expect_mismatch_state = STATE_WARNING;
572 else if (!strncmp(optarg,"crit",4)) 636 } else if (!strncmp(optarg, "crit", 4)) {
573 expect_mismatch_state = STATE_CRITICAL; 637 config.expect_mismatch_state = STATE_CRITICAL;
574 else 638 } else {
575 usage4 (_("Mismatch must be one of ok, warn, crit")); 639 usage4(_("Mismatch must be one of ok, warn, crit"));
640 }
576 break; 641 break;
577 case 'd': 642 case 'd':
578 if (is_intpos (optarg)) 643 if (is_intpos(optarg)) {
579 delay = atoi (optarg); 644 config.delay = atoi(optarg);
580 else 645 } else {
581 usage4 (_("Delay must be a positive integer")); 646 usage4(_("Delay must be a positive integer"));
647 }
582 break; 648 break;
583 case 'D': /* Check SSL cert validity - days 'til certificate expiration */ 649 case 'D': /* Check SSL cert validity - days 'til certificate expiration */
584#ifdef HAVE_SSL 650#ifdef HAVE_SSL
585# ifdef USE_OPENSSL /* XXX */ 651# ifdef USE_OPENSSL /* XXX */
586 if ((temp=strchr(optarg,','))!=NULL) { 652 {
587 *temp='\0'; 653 char *temp;
588 if (!is_intnonneg (optarg)) 654 if ((temp = strchr(optarg, ',')) != NULL) {
589 usage2 (_("Invalid certificate expiration period"), optarg); 655 *temp = '\0';
590 days_till_exp_warn = atoi (optarg); 656 if (!is_intnonneg(optarg)) {
591 *temp=','; 657 usage2(_("Invalid certificate expiration period"), optarg);
592 temp++; 658 }
593 if (!is_intnonneg (temp)) 659 config.days_till_exp_warn = atoi(optarg);
594 usage2 (_("Invalid certificate expiration period"), temp); 660 *temp = ',';
595 days_till_exp_crit = atoi (temp); 661 temp++;
596 } 662 if (!is_intnonneg(temp)) {
597 else { 663 usage2(_("Invalid certificate expiration period"), temp);
598 days_till_exp_crit=0; 664 }
599 if (!is_intnonneg (optarg)) 665 config.days_till_exp_crit = atoi(temp);
600 usage2 (_("Invalid certificate expiration period"), optarg); 666 } else {
601 days_till_exp_warn = atoi (optarg); 667 config.days_till_exp_crit = 0;
668 if (!is_intnonneg(optarg)) {
669 usage2(_("Invalid certificate expiration period"), optarg);
670 }
671 config.days_till_exp_warn = atoi(optarg);
602 } 672 }
603 check_cert = true; 673 config.check_cert = true;
604 flags |= FLAG_SSL; 674 config.use_tls = true;
605 break; 675 } break;
606# endif /* USE_OPENSSL */ 676# endif /* USE_OPENSSL */
607#endif 677#endif
608 /* fallthrough if we don't have ssl */ 678 /* fallthrough if we don't have ssl */
609 case 'S': 679 case 'S':
610#ifdef HAVE_SSL 680#ifdef HAVE_SSL
611 flags |= FLAG_SSL; 681 config.use_tls = true;
612#else 682#else
613 die (STATE_UNKNOWN, _("Invalid option - SSL is not available")); 683 die(STATE_UNKNOWN, _("Invalid option - SSL is not available"));
614#endif 684#endif
615 break; 685 break;
616 case SNI_OPTION: 686 case SNI_OPTION:
617#ifdef HAVE_SSL 687#ifdef HAVE_SSL
618 flags |= FLAG_SSL; 688 config.use_tls = true;
619 sni_specified = true; 689 config.sni_specified = true;
620 sni = optarg; 690 config.sni = optarg;
621#else 691#else
622 die (STATE_UNKNOWN, _("Invalid option - SSL is not available")); 692 die(STATE_UNKNOWN, _("Invalid option - SSL is not available"));
623#endif 693#endif
624 break; 694 break;
625 case 'A': 695 case 'A':
626 match_flags |= NP_MATCH_ALL; 696 config.match_flags |= NP_MATCH_ALL;
627 break; 697 break;
698 case output_format_index: {
699 parsed_output_format parser = mp_parse_output_format(optarg);
700 if (!parser.parsing_success) {
701 // TODO List all available formats here, maybe add anothoer usage function
702 printf("Invalid output format: %s\n", optarg);
703 exit(STATE_UNKNOWN);
704 }
705
706 config.output_format_set = true;
707 config.output_format = parser.output_format;
708 break;
709 }
628 } 710 }
629 } 711 }
630 712
631 c = optind; 713 int index = optind;
632 if(!host_specified && c < argc) 714 if (!config.host_specified && index < argc) {
633 server_address = strdup (argv[c++]); 715 config.server_address = strdup(argv[index++]);
716 }
634 717
635 if (server_address == NULL) 718 if (config.server_address == NULL) {
636 usage4 (_("You must provide a server address")); 719 usage4(_("You must provide a server address"));
637 else if (server_address[0] != '/' && !is_host(server_address)) 720 } else if (config.server_address[0] != '/' && !is_host(config.server_address)) {
638 die (STATE_CRITICAL, "%s %s - %s: %s\n", SERVICE, state_text(STATE_CRITICAL), _("Invalid hostname, address or socket"), server_address); 721 die(STATE_CRITICAL, "%s %s - %s: %s\n", config.service, state_text(STATE_CRITICAL), _("Invalid hostname, address or socket"),
722 config.server_address);
723 }
639 724
640 return OK; 725 check_tcp_config_wrapper result = {
726 .config = config,
727 .errorcode = OK,
728 };
729 return result;
641} 730}
642 731
643 732void print_help(const char *service) {
644void 733 print_revision(progname, NP_VERSION);
645print_help (void) 734
646{ 735 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
647 print_revision (progname, NP_VERSION); 736 printf(COPYRIGHT, copyright, email);
648 737
649 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 738 printf(_("This plugin tests %s connections with the specified host (or unix socket).\n\n"), service);
650 printf (COPYRIGHT, copyright, email); 739
651 740 print_usage();
652 printf (_("This plugin tests %s connections with the specified host (or unix socket).\n\n"), 741
653 SERVICE); 742 printf(UT_HELP_VRSN);
654 743 printf(UT_EXTRA_OPTS);
655 print_usage (); 744
656 745 printf(UT_HOST_PORT, 'p', "none");
657 printf (UT_HELP_VRSN); 746
658 printf (UT_EXTRA_OPTS); 747 printf(UT_IPv46);
659 748
660 printf (UT_HOST_PORT, 'p', "none"); 749 printf(" %s\n", "-E, --escape");
661 750 printf(" %s\n", _("Can use \\n, \\r, \\t or \\\\ in send or quit string. Must come before send or quit option"));
662 printf (UT_IPv46); 751 printf(" %s\n", _("Default: nothing added to send, \\r\\n added to end of quit"));
663 752 printf(" %s\n", "-s, --send=STRING");
664 printf (" %s\n", "-E, --escape"); 753 printf(" %s\n", _("String to send to the server"));
665 printf (" %s\n", _("Can use \\n, \\r, \\t or \\\\ in send or quit string. Must come before send or quit option")); 754 printf(" %s\n", "-e, --expect=STRING");
666 printf (" %s\n", _("Default: nothing added to send, \\r\\n added to end of quit")); 755 printf(" %s %s\n", _("String to expect in server response"), _("(may be repeated)"));
667 printf (" %s\n", "-s, --send=STRING"); 756 printf(" %s\n", "-A, --all");
668 printf (" %s\n", _("String to send to the server")); 757 printf(" %s\n", _("All expect strings need to occur in server response. Default is any"));
669 printf (" %s\n", "-e, --expect=STRING"); 758 printf(" %s\n", "-q, --quit=STRING");
670 printf (" %s %s\n", _("String to expect in server response"), _("(may be repeated)")); 759 printf(" %s\n", _("String to send server to initiate a clean close of the connection"));
671 printf (" %s\n", "-A, --all"); 760 printf(" %s\n", "-r, --refuse=ok|warn|crit");
672 printf (" %s\n", _("All expect strings need to occur in server response. Default is any")); 761 printf(" %s\n", _("Accept TCP refusals with states ok, warn, crit (default: crit)"));
673 printf (" %s\n", "-q, --quit=STRING"); 762 printf(" %s\n", "-M, --mismatch=ok|warn|crit");
674 printf (" %s\n", _("String to send server to initiate a clean close of the connection")); 763 printf(" %s\n", _("Accept expected string mismatches with states ok, warn, crit (default: warn)"));
675 printf (" %s\n", "-r, --refuse=ok|warn|crit"); 764 printf(" %s\n", "-j, --jail");
676 printf (" %s\n", _("Accept TCP refusals with states ok, warn, crit (default: crit)")); 765 printf(" %s\n", _("Hide output from TCP socket"));
677 printf (" %s\n", "-M, --mismatch=ok|warn|crit"); 766 printf(" %s\n", "-m, --maxbytes=INTEGER");
678 printf (" %s\n", _("Accept expected string mismatches with states ok, warn, crit (default: warn)")); 767 printf(" %s\n", _("Close connection once more than this number of bytes are received"));
679 printf (" %s\n", "-j, --jail"); 768 printf(" %s\n", "-d, --delay=INTEGER");
680 printf (" %s\n", _("Hide output from TCP socket")); 769 printf(" %s\n", _("Seconds to wait between sending string and polling for response"));
681 printf (" %s\n", "-m, --maxbytes=INTEGER");
682 printf (" %s\n", _("Close connection once more than this number of bytes are received"));
683 printf (" %s\n", "-d, --delay=INTEGER");
684 printf (" %s\n", _("Seconds to wait between sending string and polling for response"));
685 770
686#ifdef HAVE_SSL 771#ifdef HAVE_SSL
687 printf (" %s\n", "-D, --certificate=INTEGER[,INTEGER]"); 772 printf(" %s\n", "-D, --certificate=INTEGER[,INTEGER]");
688 printf (" %s\n", _("Minimum number of days a certificate has to be valid.")); 773 printf(" %s\n", _("Minimum number of days a certificate has to be valid."));
689 printf (" %s\n", _("1st is #days for warning, 2nd is critical (if not specified - 0).")); 774 printf(" %s\n", _("1st is #days for warning, 2nd is critical (if not specified - 0)."));
690 printf (" %s\n", "-S, --ssl"); 775 printf(" %s\n", "-S, --ssl");
691 printf (" %s\n", _("Use SSL for the connection.")); 776 printf(" %s\n", _("Use SSL for the connection."));
692 printf (" %s\n", "--sni=STRING"); 777 printf(" %s\n", "--sni=STRING");
693 printf (" %s\n", _("SSL server_name")); 778 printf(" %s\n", _("SSL server_name"));
694#endif 779#endif
695 780
696 printf (UT_WARN_CRIT); 781 printf(UT_WARN_CRIT);
697 782
698 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 783 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
699 784
700 printf (UT_VERBOSE); 785 printf(UT_OUTPUT_FORMAT);
786 printf(UT_VERBOSE);
701 787
702 printf (UT_SUPPORT); 788 printf(UT_SUPPORT);
703} 789}
704 790
705 791void print_usage(void) {
706void 792 printf("%s\n", _("Usage:"));
707print_usage (void) 793 printf("%s -H host -p port [-w <warning time>] [-c <critical time>] [-s <send string>]\n", progname);
708{ 794 printf("[-e <expect string>] [-q <quit string>][-m <maximum bytes>] [-d <delay>]\n");
709 printf ("%s\n", _("Usage:")); 795 printf("[-t <timeout seconds>] [-r <refuse state>] [-M <mismatch state>] [-v] [-4|-6] [-j]\n");
710 printf ("%s -H host -p port [-w <warning time>] [-c <critical time>] [-s <send string>]\n",progname); 796 printf("[-D <warn days cert expire>[,<crit days cert expire>]] [-S <use SSL>] [-E]\n");
711 printf ("[-e <expect string>] [-q <quit string>][-m <maximum bytes>] [-d <delay>]\n");
712 printf ("[-t <timeout seconds>] [-r <refuse state>] [-M <mismatch state>] [-v] [-4|-6] [-j]\n");
713 printf ("[-D <warn days cert expire>[,<crit days cert expire>]] [-S <use SSL>] [-E]\n");
714} 797}
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 f50ea427..debf59f3 100644
--- a/plugins/check_time.c
+++ b/plugins/check_time.c
@@ -1,374 +1,348 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_time plugin 3 * Monitoring check_time plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2007 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_time plugin 10 * This file contains the check_time plugin
11* 11 *
12* This plugin will check the time difference with the specified host. 12 * This plugin will check the time difference with the specified host.
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#include "states.h"
31const char *progname = "check_time"; 32const char *progname = "check_time";
32const char *copyright = "1999-2007"; 33const char *copyright = "1999-2024";
33const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
34 35
35#include "common.h" 36#include "common.h"
36#include "netutils.h" 37#include "netutils.h"
37#include "utils.h" 38#include "utils.h"
39#include "check_time.d/config.h"
40
41#define UNIX_EPOCH 2208988800UL
42
43typedef struct {
44 int errorcode;
45 check_time_config config;
46} check_time_config_wrapper;
47static check_time_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
48static void print_help(void);
49void print_usage(void);
38 50
39enum { 51int main(int argc, char **argv) {
40 TIME_PORT = 37 52 setlocale(LC_ALL, "");
41}; 53 bindtextdomain(PACKAGE, LOCALEDIR);
42 54 textdomain(PACKAGE);
43#define UNIX_EPOCH 2208988800UL
44
45uint32_t raw_server_time;
46unsigned long server_time, diff_time;
47int warning_time = 0;
48bool check_warning_time = false;
49int critical_time = 0;
50bool check_critical_time = false;
51unsigned long warning_diff = 0;
52bool check_warning_diff = false;
53unsigned long critical_diff = 0;
54bool check_critical_diff = false;
55int server_port = TIME_PORT;
56char *server_address = NULL;
57bool use_udp = false;
58
59int process_arguments (int, char **);
60void print_help (void);
61void print_usage (void);
62
63int
64main (int argc, char **argv)
65{
66 int sd;
67 int result = STATE_UNKNOWN;
68 time_t conntime;
69
70 setlocale (LC_ALL, "");
71 bindtextdomain (PACKAGE, LOCALEDIR);
72 textdomain (PACKAGE);
73 55
74 /* Parse extra opts if any */ 56 /* Parse extra opts if any */
75 argv=np_extra_opts (&argc, argv, progname); 57 argv = np_extra_opts(&argc, argv, progname);
58
59 check_time_config_wrapper tmp_config = process_arguments(argc, argv);
60 if (tmp_config.errorcode == ERROR) {
61 usage4(_("Could not parse arguments"));
62 }
76 63
77 if (process_arguments (argc, argv) == ERROR) 64 const check_time_config config = tmp_config.config;
78 usage4 (_("Could not parse arguments"));
79 65
80 /* initialize alarm signal handling */ 66 /* initialize alarm signal handling */
81 signal (SIGALRM, socket_timeout_alarm_handler); 67 signal(SIGALRM, socket_timeout_alarm_handler);
82 68
83 /* set socket timeout */ 69 /* set socket timeout */
84 alarm (socket_timeout); 70 alarm(socket_timeout);
85 time (&start_time); 71 time(&start_time);
86 72
73 int socket;
74 mp_state_enum result = STATE_UNKNOWN;
87 /* try to connect to the host at the given port number */ 75 /* try to connect to the host at the given port number */
88 if (use_udp) { 76 if (config.use_udp) {
89 result = my_udp_connect (server_address, server_port, &sd); 77 result = my_udp_connect(config.server_address, config.server_port, &socket);
90 } else { 78 } else {
91 result = my_tcp_connect (server_address, server_port, &sd); 79 result = my_tcp_connect(config.server_address, config.server_port, &socket);
92 } 80 }
93 81
94 if (result != STATE_OK) { 82 if (result != STATE_OK) {
95 if (check_critical_time) 83 if (config.check_critical_time) {
96 result = STATE_CRITICAL; 84 result = STATE_CRITICAL;
97 else if (check_warning_time) 85 } else if (config.check_warning_time) {
98 result = STATE_WARNING; 86 result = STATE_WARNING;
99 else 87 } else {
100 result = STATE_UNKNOWN; 88 result = STATE_UNKNOWN;
101 die (result, 89 }
102 _("TIME UNKNOWN - could not connect to server %s, port %d\n"), 90 die(result, _("TIME UNKNOWN - could not connect to server %s, port %d\n"), config.server_address, config.server_port);
103 server_address, server_port);
104 } 91 }
105 92
106 if (use_udp) { 93 if (config.use_udp) {
107 if (send (sd, "", 0, 0) < 0) { 94 if (send(socket, "", 0, 0) < 0) {
108 if (check_critical_time) 95 if (config.check_critical_time) {
109 result = STATE_CRITICAL; 96 result = STATE_CRITICAL;
110 else if (check_warning_time) 97 } else if (config.check_warning_time) {
111 result = STATE_WARNING; 98 result = STATE_WARNING;
112 else 99 } else {
113 result = STATE_UNKNOWN; 100 result = STATE_UNKNOWN;
114 die (result, 101 }
115 _("TIME UNKNOWN - could not send UDP request to server %s, port %d\n"), 102 die(result, _("TIME UNKNOWN - could not send UDP request to server %s, port %d\n"), config.server_address, config.server_port);
116 server_address, server_port);
117 } 103 }
118 } 104 }
119 105
120 /* watch for the connection string */ 106 /* watch for the connection string */
121 result = recv (sd, (void *)&raw_server_time, sizeof (raw_server_time), 0); 107 uint32_t raw_server_time;
108 result = recv(socket, (void *)&raw_server_time, sizeof(raw_server_time), 0);
122 109
123 /* close the connection */ 110 /* close the connection */
124 close (sd); 111 close(socket);
125 112
126 /* reset the alarm */ 113 /* reset the alarm */
127 time (&end_time); 114 time(&end_time);
128 alarm (0); 115 alarm(0);
129 116
130 /* return a WARNING status if we couldn't read any data */ 117 /* return a WARNING status if we couldn't read any data */
131 if (result <= 0) { 118 if (result <= 0) {
132 if (check_critical_time) 119 if (config.check_critical_time) {
133 result = STATE_CRITICAL; 120 result = STATE_CRITICAL;
134 else if (check_warning_time) 121 } else if (config.check_warning_time) {
135 result = STATE_WARNING; 122 result = STATE_WARNING;
136 else 123 } else {
137 result = STATE_UNKNOWN; 124 result = STATE_UNKNOWN;
138 die (result, 125 }
139 _("TIME UNKNOWN - no data received from server %s, port %d\n"), 126 die(result, _("TIME UNKNOWN - no data received from server %s, port %d\n"), config.server_address, config.server_port);
140 server_address, server_port);
141 } 127 }
142 128
143 result = STATE_OK; 129 result = STATE_OK;
144 130
145 conntime = (end_time - start_time); 131 time_t conntime = (end_time - start_time);
146 if (check_critical_time&& conntime > critical_time) 132 if (config.check_critical_time && conntime > config.critical_time) {
147 result = STATE_CRITICAL; 133 result = STATE_CRITICAL;
148 else if (check_warning_time && conntime > warning_time) 134 } else if (config.check_warning_time && conntime > config.warning_time) {
149 result = STATE_WARNING; 135 result = STATE_WARNING;
136 }
150 137
151 if (result != STATE_OK) 138 if (result != STATE_OK) {
152 die (result, _("TIME %s - %d second response time|%s\n"), 139 die(result, _("TIME %s - %d second response time|%s\n"), state_text(result), (int)conntime,
153 state_text (result), (int)conntime, 140 perfdata("time", (long)conntime, "s", config.check_warning_time, (long)config.warning_time, config.check_critical_time,
154 perfdata ("time", (long)conntime, "s", 141 (long)config.critical_time, true, 0, false, 0));
155 check_warning_time, (long)warning_time, 142 }
156 check_critical_time, (long)critical_time,
157 true, 0, false, 0));
158 143
159 server_time = ntohl (raw_server_time) - UNIX_EPOCH; 144 unsigned long server_time;
160 if (server_time > (unsigned long)end_time) 145 unsigned long diff_time;
146 server_time = ntohl(raw_server_time) - UNIX_EPOCH;
147 if (server_time > (unsigned long)end_time) {
161 diff_time = server_time - (unsigned long)end_time; 148 diff_time = server_time - (unsigned long)end_time;
162 else 149 } else {
163 diff_time = (unsigned long)end_time - server_time; 150 diff_time = (unsigned long)end_time - server_time;
151 }
164 152
165 if (check_critical_diff&& diff_time > critical_diff) 153 if (config.check_critical_diff && diff_time > config.critical_diff) {
166 result = STATE_CRITICAL; 154 result = STATE_CRITICAL;
167 else if (check_warning_diff&& diff_time > warning_diff) 155 } else if (config.check_warning_diff && diff_time > config.warning_diff) {
168 result = STATE_WARNING; 156 result = STATE_WARNING;
157 }
169 158
170 printf (_("TIME %s - %lu second time difference|%s %s\n"), 159 printf(_("TIME %s - %lu second time difference|%s %s\n"), state_text(result), diff_time,
171 state_text (result), diff_time, 160 perfdata("time", (long)conntime, "s", config.check_warning_time, (long)config.warning_time, config.check_critical_time,
172 perfdata ("time", (long)conntime, "s", 161 (long)config.critical_time, true, 0, false, 0),
173 check_warning_time, (long)warning_time, 162 perfdata("offset", diff_time, "s", config.check_warning_diff, config.warning_diff, config.check_critical_diff,
174 check_critical_time, (long)critical_time, 163 config.critical_diff, true, 0, false, 0));
175 true, 0, false, 0),
176 perfdata ("offset", diff_time, "s",
177 check_warning_diff, warning_diff,
178 check_critical_diff, critical_diff,
179 true, 0, false, 0));
180 return result; 164 return result;
181} 165}
182 166
183
184
185/* process command-line arguments */ 167/* process command-line arguments */
186int 168check_time_config_wrapper process_arguments(int argc, char **argv) {
187process_arguments (int argc, char **argv) 169 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
188{ 170 {"warning-variance", required_argument, 0, 'w'},
189 int c; 171 {"critical-variance", required_argument, 0, 'c'},
190 172 {"warning-connect", required_argument, 0, 'W'},
191 int option = 0; 173 {"critical-connect", required_argument, 0, 'C'},
192 static struct option longopts[] = { 174 {"port", required_argument, 0, 'p'},
193 {"hostname", required_argument, 0, 'H'}, 175 {"udp", no_argument, 0, 'u'},
194 {"warning-variance", required_argument, 0, 'w'}, 176 {"timeout", required_argument, 0, 't'},
195 {"critical-variance", required_argument, 0, 'c'}, 177 {"version", no_argument, 0, 'V'},
196 {"warning-connect", required_argument, 0, 'W'}, 178 {"help", no_argument, 0, 'h'},
197 {"critical-connect", required_argument, 0, 'C'}, 179 {0, 0, 0, 0}};
198 {"port", required_argument, 0, 'p'}, 180
199 {"udp", no_argument, 0, 'u'}, 181 if (argc < 2) {
200 {"timeout", required_argument, 0, 't'}, 182 usage("\n");
201 {"version", no_argument, 0, 'V'}, 183 }
202 {"help", no_argument, 0, 'h'},
203 {0, 0, 0, 0}
204 };
205 184
206 if (argc < 2) 185 for (int i = 1; i < argc; i++) {
207 usage ("\n"); 186 if (strcmp("-to", argv[i]) == 0) {
208 187 strcpy(argv[i], "-t");
209 for (c = 1; c < argc; c++) { 188 } else if (strcmp("-wd", argv[i]) == 0) {
210 if (strcmp ("-to", argv[c]) == 0) 189 strcpy(argv[i], "-w");
211 strcpy (argv[c], "-t"); 190 } else if (strcmp("-cd", argv[i]) == 0) {
212 else if (strcmp ("-wd", argv[c]) == 0) 191 strcpy(argv[i], "-c");
213 strcpy (argv[c], "-w"); 192 } else if (strcmp("-wt", argv[i]) == 0) {
214 else if (strcmp ("-cd", argv[c]) == 0) 193 strcpy(argv[i], "-W");
215 strcpy (argv[c], "-c"); 194 } else if (strcmp("-ct", argv[i]) == 0) {
216 else if (strcmp ("-wt", argv[c]) == 0) 195 strcpy(argv[i], "-C");
217 strcpy (argv[c], "-W"); 196 }
218 else if (strcmp ("-ct", argv[c]) == 0)
219 strcpy (argv[c], "-C");
220 } 197 }
221 198
199 check_time_config_wrapper result = {
200 .errorcode = OK,
201 .config = check_time_config_init(),
202 };
203
204 int option_char;
222 while (true) { 205 while (true) {
223 c = getopt_long (argc, argv, "hVH:w:c:W:C:p:t:u", longopts, 206 int option = 0;
224 &option); 207 option_char = getopt_long(argc, argv, "hVH:w:c:W:C:p:t:u", longopts, &option);
225 208
226 if (c == -1 || c == EOF) 209 if (option_char == -1 || option_char == EOF) {
227 break; 210 break;
211 }
228 212
229 switch (c) { 213 switch (option_char) {
230 case '?': /* print short usage statement if args not parsable */ 214 case '?': /* print short usage statement if args not parsable */
231 usage5 (); 215 usage5();
232 case 'h': /* help */ 216 case 'h': /* help */
233 print_help (); 217 print_help();
234 exit (STATE_UNKNOWN); 218 exit(STATE_UNKNOWN);
235 case 'V': /* version */ 219 case 'V': /* version */
236 print_revision (progname, NP_VERSION); 220 print_revision(progname, NP_VERSION);
237 exit (STATE_UNKNOWN); 221 exit(STATE_UNKNOWN);
238 case 'H': /* hostname */ 222 case 'H': /* hostname */
239 if (!is_host (optarg)) 223 if (!is_host(optarg)) {
240 usage2 (_("Invalid hostname/address"), optarg); 224 usage2(_("Invalid hostname/address"), optarg);
241 server_address = optarg;
242 break;
243 case 'w': /* warning-variance */
244 if (is_intnonneg (optarg)) {
245 warning_diff = strtoul (optarg, NULL, 10);
246 check_warning_diff = true;
247 } 225 }
248 else if (strspn (optarg, "0123456789:,") > 0) { 226 result.config.server_address = optarg;
249 if (sscanf (optarg, "%lu%*[:,]%d", &warning_diff, &warning_time) == 2) { 227 break;
250 check_warning_diff = true; 228 case 'w': /* warning-variance */
251 check_warning_time = true; 229 if (is_intnonneg(optarg)) {
252 } 230 result.config.warning_diff = strtoul(optarg, NULL, 10);
253 else { 231 result.config.check_warning_diff = true;
254 usage4 (_("Warning thresholds must be a positive integer")); 232 } else if (strspn(optarg, "0123456789:,") > 0) {
233 if (sscanf(optarg, "%lu%*[:,]%d", &result.config.warning_diff, &result.config.warning_time) == 2) {
234 result.config.check_warning_diff = true;
235 result.config.check_warning_time = true;
236 } else {
237 usage4(_("Warning thresholds must be a positive integer"));
255 } 238 }
256 } 239 } else {
257 else { 240 usage4(_("Warning threshold must be a positive integer"));
258 usage4 (_("Warning threshold must be a positive integer"));
259 } 241 }
260 break; 242 break;
261 case 'c': /* critical-variance */ 243 case 'c': /* critical-variance */
262 if (is_intnonneg (optarg)) { 244 if (is_intnonneg(optarg)) {
263 critical_diff = strtoul (optarg, NULL, 10); 245 result.config.critical_diff = strtoul(optarg, NULL, 10);
264 check_critical_diff = true; 246 result.config.check_critical_diff = true;
265 } 247 } else if (strspn(optarg, "0123456789:,") > 0) {
266 else if (strspn (optarg, "0123456789:,") > 0) { 248 if (sscanf(optarg, "%lu%*[:,]%d", &result.config.critical_diff, &result.config.critical_time) == 2) {
267 if (sscanf (optarg, "%lu%*[:,]%d", &critical_diff, &critical_time) == 249 result.config.check_critical_diff = true;
268 2) { 250 result.config.check_critical_time = true;
269 check_critical_diff = true; 251 } else {
270 check_critical_time = true; 252 usage4(_("Critical thresholds must be a positive integer"));
271 }
272 else {
273 usage4 (_("Critical thresholds must be a positive integer"));
274 } 253 }
275 } 254 } else {
276 else { 255 usage4(_("Critical threshold must be a positive integer"));
277 usage4 (_("Critical threshold must be a positive integer"));
278 } 256 }
279 break; 257 break;
280 case 'W': /* warning-connect */ 258 case 'W': /* warning-connect */
281 if (!is_intnonneg (optarg)) 259 if (!is_intnonneg(optarg)) {
282 usage4 (_("Warning threshold must be a positive integer")); 260 usage4(_("Warning threshold must be a positive integer"));
283 else 261 } else {
284 warning_time = atoi (optarg); 262 result.config.warning_time = atoi(optarg);
285 check_warning_time = true; 263 }
264 result.config.check_warning_time = true;
286 break; 265 break;
287 case 'C': /* critical-connect */ 266 case 'C': /* critical-connect */
288 if (!is_intnonneg (optarg)) 267 if (!is_intnonneg(optarg)) {
289 usage4 (_("Critical threshold must be a positive integer")); 268 usage4(_("Critical threshold must be a positive integer"));
290 else 269 } else {
291 critical_time = atoi (optarg); 270 result.config.critical_time = atoi(optarg);
292 check_critical_time = true; 271 }
272 result.config.check_critical_time = true;
293 break; 273 break;
294 case 'p': /* port */ 274 case 'p': /* port */
295 if (!is_intnonneg (optarg)) 275 if (!is_intnonneg(optarg)) {
296 usage4 (_("Port must be a positive integer")); 276 usage4(_("Port must be a positive integer"));
297 else 277 } else {
298 server_port = atoi (optarg); 278 result.config.server_port = atoi(optarg);
279 }
299 break; 280 break;
300 case 't': /* timeout */ 281 case 't': /* timeout */
301 if (!is_intnonneg (optarg)) 282 if (!is_intnonneg(optarg)) {
302 usage2 (_("Timeout interval must be a positive integer"), optarg); 283 usage2(_("Timeout interval must be a positive integer"), optarg);
303 else 284 } else {
304 socket_timeout = atoi (optarg); 285 socket_timeout = atoi(optarg);
286 }
305 break; 287 break;
306 case 'u': /* udp */ 288 case 'u': /* udp */
307 use_udp = true; 289 result.config.use_udp = true;
308 } 290 }
309 } 291 }
310 292
311 c = optind; 293 option_char = optind;
312 if (server_address == NULL) { 294 if (result.config.server_address == NULL) {
313 if (argc > c) { 295 if (argc > option_char) {
314 if (!is_host (argv[c])) 296 if (!is_host(argv[option_char])) {
315 usage2 (_("Invalid hostname/address"), optarg); 297 usage2(_("Invalid hostname/address"), optarg);
316 server_address = argv[c]; 298 }
317 } 299 result.config.server_address = argv[option_char];
318 else { 300 } else {
319 usage4 (_("Hostname was not supplied")); 301 usage4(_("Hostname was not supplied"));
320 } 302 }
321 } 303 }
322 304
323 return OK; 305 return result;
324} 306}
325 307
326 308void print_help(void) {
327
328void
329print_help (void)
330{
331 char *myport; 309 char *myport;
332 xasprintf (&myport, "%d", TIME_PORT); 310 xasprintf(&myport, "%d", TIME_PORT);
333 311
334 print_revision (progname, NP_VERSION); 312 print_revision(progname, NP_VERSION);
335 313
336 printf ("Copyright (c) 1999 Ethan Galstad\n"); 314 printf("Copyright (c) 1999 Ethan Galstad\n");
337 printf (COPYRIGHT, copyright, email); 315 printf(COPYRIGHT, copyright, email);
338 316
339 printf ("%s\n", _("This plugin will check the time on the specified host.")); 317 printf("%s\n", _("This plugin will check the time on the specified host."));
340 318
341 printf ("\n\n"); 319 printf("\n\n");
342 320
343 print_usage (); 321 print_usage();
344 322
345 printf (UT_HELP_VRSN); 323 printf(UT_HELP_VRSN);
346 printf (UT_EXTRA_OPTS); 324 printf(UT_EXTRA_OPTS);
347 325
348 printf (UT_HOST_PORT, 'p', myport); 326 printf(UT_HOST_PORT, 'p', myport);
349 327
350 printf (" %s\n", "-u, --udp"); 328 printf(" %s\n", "-u, --udp");
351 printf (" %s\n", _("Use UDP to connect, not TCP")); 329 printf(" %s\n", _("Use UDP to connect, not TCP"));
352 printf (" %s\n", "-w, --warning-variance=INTEGER"); 330 printf(" %s\n", "-w, --warning-variance=INTEGER");
353 printf (" %s\n", _("Time difference (sec.) necessary to result in a warning status")); 331 printf(" %s\n", _("Time difference (sec.) necessary to result in a warning status"));
354 printf (" %s\n", "-c, --critical-variance=INTEGER"); 332 printf(" %s\n", "-c, --critical-variance=INTEGER");
355 printf (" %s\n", _("Time difference (sec.) necessary to result in a critical status")); 333 printf(" %s\n", _("Time difference (sec.) necessary to result in a critical status"));
356 printf (" %s\n", "-W, --warning-connect=INTEGER"); 334 printf(" %s\n", "-W, --warning-connect=INTEGER");
357 printf (" %s\n", _("Response time (sec.) necessary to result in warning status")); 335 printf(" %s\n", _("Response time (sec.) necessary to result in warning status"));
358 printf (" %s\n", "-C, --critical-connect=INTEGER"); 336 printf(" %s\n", "-C, --critical-connect=INTEGER");
359 printf (" %s\n", _("Response time (sec.) necessary to result in critical status")); 337 printf(" %s\n", _("Response time (sec.) necessary to result in critical status"));
360 338
361 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 339 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
362 340
363 printf (UT_SUPPORT); 341 printf(UT_SUPPORT);
364} 342}
365 343
366 344void print_usage(void) {
367 345 printf("%s\n", _("Usage:"));
368void 346 printf("%s -H <host_address> [-p port] [-u] [-w variance] [-c variance]\n", progname);
369print_usage (void) 347 printf(" [-W connect_time] [-C connect_time] [-t timeout]\n");
370{
371 printf ("%s\n", _("Usage:"));
372 printf ("%s -H <host_address> [-p port] [-u] [-w variance] [-c variance]\n",progname);
373 printf (" [-W connect_time] [-C connect_time] [-t timeout]\n");
374} 348}
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 380ff3bc..ecc0760f 100644
--- a/plugins/check_ups.c
+++ b/plugins/check_ups.c
@@ -6,7 +6,7 @@
6 * Copyright (c) 2000 Tom Shields 6 * Copyright (c) 2000 Tom Shields
7 * 2004 Alain Richard <alain.richard@equation.fr> 7 * 2004 Alain Richard <alain.richard@equation.fr>
8 * 2004 Arnaud Quette <arnaud.quette@mgeups.com> 8 * 2004 Arnaud Quette <arnaud.quette@mgeups.com>
9 * Copyright (c) 2002-2023 Monitoring Plugins Development Team 9 * Copyright (c) 2002-2024 Monitoring Plugins Development Team
10 * 10 *
11 * Description: 11 * Description:
12 * 12 *
@@ -33,100 +33,52 @@
33 *****************************************************************************/ 33 *****************************************************************************/
34 34
35const char *progname = "check_ups"; 35const char *progname = "check_ups";
36const char *copyright = "2000-2023"; 36const char *copyright = "2000-2024";
37const char *email = "devel@monitoring-plugins.org"; 37const char *email = "devel@monitoring-plugins.org";
38 38
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#include "check_ups.d/config.h"
43#include "states.h"
42 44
43enum { PORT = 3493 }; 45enum {
44 46 NOSUCHVAR = ERROR - 1
45#define UPS_NONE 0 /* no supported options */ 47};
46#define UPS_UTILITY 1 /* supports utility line */
47#define UPS_BATTPCT 2 /* supports percent battery remaining */
48#define UPS_STATUS 4 /* supports UPS status */
49#define UPS_TEMP 8 /* supports UPS temperature */
50#define UPS_LOADPCT 16 /* supports load percent */
51#define UPS_REALPOWER 32 /* supports real power */
52
53#define UPSSTATUS_NONE 0
54#define UPSSTATUS_OFF 1
55#define UPSSTATUS_OL 2
56#define UPSSTATUS_OB 4
57#define UPSSTATUS_LB 8
58#define UPSSTATUS_CAL 16
59#define UPSSTATUS_RB 32 /*Replace Battery */
60#define UPSSTATUS_BYPASS 64
61#define UPSSTATUS_OVER 128
62#define UPSSTATUS_TRIM 256
63#define UPSSTATUS_BOOST 512
64#define UPSSTATUS_CHRG 1024
65#define UPSSTATUS_DISCHRG 2048
66#define UPSSTATUS_UNKNOWN 4096
67#define UPSSTATUS_ALARM 8192
68
69enum { NOSUCHVAR = ERROR - 1 };
70
71typedef struct ups_config {
72 unsigned int server_port;
73 char *server_address;
74 char *ups_name;
75 double warning_value;
76 double critical_value;
77 bool check_warn;
78 bool check_crit;
79 int check_variable;
80 int status;
81 bool temp_output_c;
82} ups_config;
83
84ups_config ups_config_init(void) {
85 ups_config tmp = {0};
86 tmp.server_port = PORT;
87 tmp.server_address = NULL;
88 tmp.ups_name = NULL;
89 tmp.check_variable = UPS_NONE;
90 tmp.status = UPSSTATUS_NONE;
91
92 return tmp;
93}
94 48
95// Forward declarations 49// Forward declarations
96int determine_status(ups_config *, int *supported_options); 50typedef struct {
97int get_ups_variable(const char *, char *, const ups_config config); 51 int errorcode;
98 52 int ups_status;
99int process_arguments(int, char **, ups_config *); 53 int supported_options;
100int validate_arguments(ups_config); 54} determine_status_result;
101void print_help(void); 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*/);
64
65static void print_help(void);
102void print_usage(void); 66void print_usage(void);
103 67
104int main(int argc, char **argv) { 68int main(int argc, char **argv) {
105 setlocale(LC_ALL, ""); 69 setlocale(LC_ALL, "");
106 bindtextdomain(PACKAGE, LOCALEDIR); 70 bindtextdomain(PACKAGE, LOCALEDIR);
107 textdomain(PACKAGE); 71 textdomain(PACKAGE);
108
109 char *ups_status;
110 ups_status = strdup("N/A");
111
112 char *data;
113 data = strdup("");
114
115 char *message;
116 message = strdup("");
117
118 // Exit result
119 int result = STATE_UNKNOWN;
120
121 /* Parse extra opts if any */ 72 /* Parse extra opts if any */
122 argv = np_extra_opts(&argc, argv, progname); 73 argv = np_extra_opts(&argc, argv, progname);
123 74
124 // Config from commandline 75 check_ups_config_wrapper tmp_config = process_arguments(argc, argv);
125 ups_config config = ups_config_init();
126 76
127 if (process_arguments(argc, argv, &config) == ERROR) { 77 if (tmp_config.errorcode == ERROR) {
128 usage4(_("Could not parse arguments")); 78 usage4(_("Could not parse arguments"));
129 } 79 }
80 // Config from commandline
81 check_ups_config config = tmp_config.config;
130 82
131 /* initialize alarm signal handling */ 83 /* initialize alarm signal handling */
132 signal(SIGALRM, socket_timeout_alarm_handler); 84 signal(SIGALRM, socket_timeout_alarm_handler);
@@ -134,74 +86,75 @@ int main(int argc, char **argv) {
134 /* set socket timeout */ 86 /* set socket timeout */
135 alarm(socket_timeout); 87 alarm(socket_timeout);
136 88
137 int supported_options = UPS_NONE;
138
139 /* get the ups status if possible */ 89 /* get the ups status if possible */
140 if (determine_status(&config, &supported_options) != OK) { 90 determine_status_result query_result = determine_status(config);
91 if (query_result.errorcode != OK) {
141 return STATE_CRITICAL; 92 return STATE_CRITICAL;
142 } 93 }
143 94
95 int ups_status_flags = query_result.ups_status;
96 int supported_options = query_result.supported_options;
144 97
145 if (supported_options & UPS_STATUS) { 98 // Exit result
146 99 mp_state_enum result = STATE_UNKNOWN;
147 ups_status = strdup(""); 100 char *message = NULL;
148 101
102 if (supported_options & UPS_STATUS) {
103 char *ups_status = strdup("");
149 result = STATE_OK; 104 result = STATE_OK;
150 105
151 if (config.status & UPSSTATUS_OFF) { 106 if (ups_status_flags & UPSSTATUS_OFF) {
152 xasprintf(&ups_status, "Off"); 107 xasprintf(&ups_status, "Off");
153 result = STATE_CRITICAL; 108 result = STATE_CRITICAL;
154 } else if ((config.status & (UPSSTATUS_OB | UPSSTATUS_LB)) == 109 } else if ((ups_status_flags & (UPSSTATUS_OB | UPSSTATUS_LB)) == (UPSSTATUS_OB | UPSSTATUS_LB)) {
155 (UPSSTATUS_OB | UPSSTATUS_LB)) {
156 xasprintf(&ups_status, _("On Battery, Low Battery")); 110 xasprintf(&ups_status, _("On Battery, Low Battery"));
157 result = STATE_CRITICAL; 111 result = STATE_CRITICAL;
158 } else { 112 } else {
159 if (config.status & UPSSTATUS_OL) { 113 if (ups_status_flags & UPSSTATUS_OL) {
160 xasprintf(&ups_status, "%s%s", ups_status, _("Online")); 114 xasprintf(&ups_status, "%s%s", ups_status, _("Online"));
161 } 115 }
162 if (config.status & UPSSTATUS_OB) { 116 if (ups_status_flags & UPSSTATUS_OB) {
163 xasprintf(&ups_status, "%s%s", ups_status, _("On Battery")); 117 xasprintf(&ups_status, "%s%s", ups_status, _("On Battery"));
164 result = max_state(result, STATE_WARNING); 118 result = max_state(result, STATE_WARNING);
165 } 119 }
166 if (config.status & UPSSTATUS_LB) { 120 if (ups_status_flags & UPSSTATUS_LB) {
167 xasprintf(&ups_status, "%s%s", ups_status, _(", Low Battery")); 121 xasprintf(&ups_status, "%s%s", ups_status, _(", Low Battery"));
168 result = max_state(result, STATE_WARNING); 122 result = max_state(result, STATE_WARNING);
169 } 123 }
170 if (config.status & UPSSTATUS_CAL) { 124 if (ups_status_flags & UPSSTATUS_CAL) {
171 xasprintf(&ups_status, "%s%s", ups_status, _(", Calibrating")); 125 xasprintf(&ups_status, "%s%s", ups_status, _(", Calibrating"));
172 } 126 }
173 if (config.status & UPSSTATUS_RB) { 127 if (ups_status_flags & UPSSTATUS_RB) {
174 xasprintf(&ups_status, "%s%s", ups_status, 128 xasprintf(&ups_status, "%s%s", ups_status, _(", Replace Battery"));
175 _(", Replace Battery"));
176 result = max_state(result, STATE_WARNING); 129 result = max_state(result, STATE_WARNING);
177 } 130 }
178 if (config.status & UPSSTATUS_BYPASS) { 131 if (ups_status_flags & UPSSTATUS_BYPASS) {
179 xasprintf(&ups_status, "%s%s", ups_status, _(", On Bypass")); 132 xasprintf(&ups_status, "%s%s", ups_status, _(", On Bypass"));
180 // Bypassing the battery is likely a bad thing 133 // Bypassing the battery is likely a bad thing
181 result = STATE_CRITICAL; 134 result = STATE_CRITICAL;
182 } 135 }
183 if (config.status & UPSSTATUS_OVER) { 136 if (ups_status_flags & UPSSTATUS_OVER) {
184 xasprintf(&ups_status, "%s%s", ups_status, _(", Overload")); 137 xasprintf(&ups_status, "%s%s", ups_status, _(", Overload"));
185 result = max_state(result, STATE_WARNING); 138 result = max_state(result, STATE_WARNING);
186 } 139 }
187 if (config.status & UPSSTATUS_TRIM) { 140 if (ups_status_flags & UPSSTATUS_TRIM) {
188 xasprintf(&ups_status, "%s%s", ups_status, _(", Trimming")); 141 xasprintf(&ups_status, "%s%s", ups_status, _(", Trimming"));
189 } 142 }
190 if (config.status & UPSSTATUS_BOOST) { 143 if (ups_status_flags & UPSSTATUS_BOOST) {
191 xasprintf(&ups_status, "%s%s", ups_status, _(", Boosting")); 144 xasprintf(&ups_status, "%s%s", ups_status, _(", Boosting"));
192 } 145 }
193 if (config.status & UPSSTATUS_CHRG) { 146 if (ups_status_flags & UPSSTATUS_CHRG) {
194 xasprintf(&ups_status, "%s%s", ups_status, _(", Charging")); 147 xasprintf(&ups_status, "%s%s", ups_status, _(", Charging"));
195 } 148 }
196 if (config.status & UPSSTATUS_DISCHRG) { 149 if (ups_status_flags & UPSSTATUS_DISCHRG) {
197 xasprintf(&ups_status, "%s%s", ups_status, _(", Discharging")); 150 xasprintf(&ups_status, "%s%s", ups_status, _(", Discharging"));
198 result = max_state(result, STATE_WARNING); 151 result = max_state(result, STATE_WARNING);
199 } 152 }
200 if (config.status & UPSSTATUS_ALARM) { 153 if (ups_status_flags & UPSSTATUS_ALARM) {
201 xasprintf(&ups_status, "%s%s", ups_status, _(", ALARM")); 154 xasprintf(&ups_status, "%s%s", ups_status, _(", ALARM"));
202 result = STATE_CRITICAL; 155 result = STATE_CRITICAL;
203 } 156 }
204 if (config.status & UPSSTATUS_UNKNOWN) { 157 if (ups_status_flags & UPSSTATUS_UNKNOWN) {
205 xasprintf(&ups_status, "%s%s", ups_status, _(", Unknown")); 158 xasprintf(&ups_status, "%s%s", ups_status, _(", Unknown"));
206 } 159 }
207 } 160 }
@@ -210,7 +163,7 @@ int main(int argc, char **argv) {
210 163
211 int res; 164 int res;
212 char temp_buffer[MAX_INPUT_BUFFER]; 165 char temp_buffer[MAX_INPUT_BUFFER];
213 166 char *performance_data = strdup("");
214 /* get the ups utility voltage if possible */ 167 /* get the ups utility voltage if possible */
215 res = get_ups_variable("input.voltage", temp_buffer, config); 168 res = get_ups_variable("input.voltage", temp_buffer, config);
216 if (res == NOSUCHVAR) { 169 if (res == NOSUCHVAR) {
@@ -233,24 +186,17 @@ int main(int argc, char **argv) {
233 } 186 }
234 187
235 if (config.check_variable == UPS_UTILITY) { 188 if (config.check_variable == UPS_UTILITY) {
236 if (config.check_crit && 189 if (config.check_crit && ups_utility_deviation >= config.critical_value) {
237 ups_utility_deviation >= config.critical_value) {
238 result = STATE_CRITICAL; 190 result = STATE_CRITICAL;
239 } else if (config.check_warn && 191 } else if (config.check_warn && ups_utility_deviation >= config.warning_value) {
240 ups_utility_deviation >= config.warning_value) {
241 result = max_state(result, STATE_WARNING); 192 result = max_state(result, STATE_WARNING);
242 } 193 }
243 xasprintf(&data, "%s", 194 xasprintf(&performance_data, "%s",
244 perfdata("voltage", (long)(1000 * ups_utility_voltage), 195 perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", config.check_warn, (long)(1000 * config.warning_value),
245 "mV", config.check_warn, 196 config.check_crit, (long)(1000 * config.critical_value), true, 0, false, 0));
246 (long)(1000 * config.warning_value),
247 config.check_crit,
248 (long)(1000 * config.critical_value), true, 0,
249 false, 0));
250 } else { 197 } else {
251 xasprintf(&data, "%s", 198 xasprintf(&performance_data, "%s",
252 perfdata("voltage", (long)(1000 * ups_utility_voltage), 199 perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", false, 0, false, 0, true, 0, false, 0));
253 "mV", false, 0, false, 0, true, 0, false, 0));
254 } 200 }
255 } 201 }
256 202
@@ -268,22 +214,17 @@ int main(int argc, char **argv) {
268 xasprintf(&message, "%sBatt=%3.1f%% ", message, ups_battery_percent); 214 xasprintf(&message, "%sBatt=%3.1f%% ", message, ups_battery_percent);
269 215
270 if (config.check_variable == UPS_BATTPCT) { 216 if (config.check_variable == UPS_BATTPCT) {
271 if (config.check_crit && 217 if (config.check_crit && ups_battery_percent <= config.critical_value) {
272 ups_battery_percent <= config.critical_value) {
273 result = STATE_CRITICAL; 218 result = STATE_CRITICAL;
274 } else if (config.check_warn && 219 } else if (config.check_warn && ups_battery_percent <= config.warning_value) {
275 ups_battery_percent <= config.warning_value) {
276 result = max_state(result, STATE_WARNING); 220 result = max_state(result, STATE_WARNING);
277 } 221 }
278 xasprintf(&data, "%s %s", data, 222 xasprintf(&performance_data, "%s %s", performance_data,
279 perfdata("battery", (long)ups_battery_percent, "%", 223 perfdata("battery", (long)ups_battery_percent, "%", config.check_warn, (long)(config.warning_value),
280 config.check_warn, (long)(config.warning_value), 224 config.check_crit, (long)(config.critical_value), true, 0, true, 100));
281 config.check_crit, (long)(config.critical_value),
282 true, 0, true, 100));
283 } else { 225 } else {
284 xasprintf(&data, "%s %s", data, 226 xasprintf(&performance_data, "%s %s", performance_data,
285 perfdata("battery", (long)ups_battery_percent, "%", false, 227 perfdata("battery", (long)ups_battery_percent, "%", false, 0, false, 0, true, 0, true, 100));
286 0, false, 0, true, 0, true, 100));
287 } 228 }
288 } 229 }
289 230
@@ -301,22 +242,17 @@ int main(int argc, char **argv) {
301 xasprintf(&message, "%sLoad=%3.1f%% ", message, ups_load_percent); 242 xasprintf(&message, "%sLoad=%3.1f%% ", message, ups_load_percent);
302 243
303 if (config.check_variable == UPS_LOADPCT) { 244 if (config.check_variable == UPS_LOADPCT) {
304 if (config.check_crit && 245 if (config.check_crit && ups_load_percent >= config.critical_value) {
305 ups_load_percent >= config.critical_value) {
306 result = STATE_CRITICAL; 246 result = STATE_CRITICAL;
307 } else if (config.check_warn && 247 } else if (config.check_warn && ups_load_percent >= config.warning_value) {
308 ups_load_percent >= config.warning_value) {
309 result = max_state(result, STATE_WARNING); 248 result = max_state(result, STATE_WARNING);
310 } 249 }
311 xasprintf(&data, "%s %s", data, 250 xasprintf(&performance_data, "%s %s", performance_data,
312 perfdata("load", (long)ups_load_percent, "%", 251 perfdata("load", (long)ups_load_percent, "%", config.check_warn, (long)(config.warning_value), config.check_crit,
313 config.check_warn, (long)(config.warning_value), 252 (long)(config.critical_value), true, 0, true, 100));
314 config.check_crit, (long)(config.critical_value),
315 true, 0, true, 100));
316 } else { 253 } else {
317 xasprintf(&data, "%s %s", data, 254 xasprintf(&performance_data, "%s %s", performance_data,
318 perfdata("load", (long)ups_load_percent, "%", false, 0, 255 perfdata("load", (long)ups_load_percent, "%", false, 0, false, 0, true, 0, true, 100));
319 false, 0, true, 0, true, 100));
320 } 256 }
321 } 257 }
322 258
@@ -345,19 +281,15 @@ int main(int argc, char **argv) {
345 if (config.check_variable == UPS_TEMP) { 281 if (config.check_variable == UPS_TEMP) {
346 if (config.check_crit && ups_temperature >= config.critical_value) { 282 if (config.check_crit && ups_temperature >= config.critical_value) {
347 result = STATE_CRITICAL; 283 result = STATE_CRITICAL;
348 } else if (config.check_warn && 284 } else if (config.check_warn && ups_temperature >= config.warning_value) {
349 ups_temperature >= config.warning_value) {
350 result = max_state(result, STATE_WARNING); 285 result = max_state(result, STATE_WARNING);
351 } 286 }
352 xasprintf(&data, "%s %s", data, 287 xasprintf(&performance_data, "%s %s", performance_data,
353 perfdata("temp", (long)ups_temperature, tunits, 288 perfdata("temp", (long)ups_temperature, tunits, config.check_warn, (long)(config.warning_value), config.check_crit,
354 config.check_warn, (long)(config.warning_value), 289 (long)(config.critical_value), true, 0, false, 0));
355 config.check_crit, (long)(config.critical_value),
356 true, 0, false, 0));
357 } else { 290 } else {
358 xasprintf(&data, "%s %s", data, 291 xasprintf(&performance_data, "%s %s", performance_data,
359 perfdata("temp", (long)ups_temperature, tunits, false, 0, 292 perfdata("temp", (long)ups_temperature, tunits, false, 0, false, 0, true, 0, false, 0));
360 false, 0, true, 0, false, 0));
361 } 293 }
362 } 294 }
363 295
@@ -376,19 +308,15 @@ int main(int argc, char **argv) {
376 if (config.check_variable == UPS_REALPOWER) { 308 if (config.check_variable == UPS_REALPOWER) {
377 if (config.check_crit && ups_realpower >= config.critical_value) { 309 if (config.check_crit && ups_realpower >= config.critical_value) {
378 result = STATE_CRITICAL; 310 result = STATE_CRITICAL;
379 } else if (config.check_warn && 311 } else if (config.check_warn && ups_realpower >= config.warning_value) {
380 ups_realpower >= config.warning_value) {
381 result = max_state(result, STATE_WARNING); 312 result = max_state(result, STATE_WARNING);
382 } 313 }
383 xasprintf(&data, "%s %s", data, 314 xasprintf(&performance_data, "%s %s", performance_data,
384 perfdata("realpower", (long)ups_realpower, "W", 315 perfdata("realpower", (long)ups_realpower, "W", config.check_warn, (long)(config.warning_value), config.check_crit,
385 config.check_warn, (long)(config.warning_value), 316 (long)(config.critical_value), true, 0, false, 0));
386 config.check_crit, (long)(config.critical_value),
387 true, 0, false, 0));
388 } else { 317 } else {
389 xasprintf(&data, "%s %s", data, 318 xasprintf(&performance_data, "%s %s", performance_data,
390 perfdata("realpower", (long)ups_realpower, "W", false, 0, 319 perfdata("realpower", (long)ups_realpower, "W", false, 0, false, 0, true, 0, false, 0));
391 false, 0, true, 0, false, 0));
392 } 320 }
393 } 321 }
394 322
@@ -402,73 +330,78 @@ int main(int argc, char **argv) {
402 /* reset timeout */ 330 /* reset timeout */
403 alarm(0); 331 alarm(0);
404 332
405 printf("UPS %s - %s|%s\n", state_text(result), message, data); 333 printf("UPS %s - %s|%s\n", state_text(result), message, performance_data);
406 return result; 334 exit(result);
407} 335}
408 336
409/* determines what options are supported by the UPS */ 337/* determines what options are supported by the UPS */
410int determine_status(ups_config *config, int *supported_options) { 338determine_status_result determine_status(const check_ups_config config) {
411 char recv_buffer[MAX_INPUT_BUFFER];
412 339
413 int res = get_ups_variable("ups.status", recv_buffer, *config); 340 determine_status_result result = {
341 .errorcode = OK,
342 .ups_status = UPSSTATUS_NONE,
343 .supported_options = 0,
344 };
345
346 char recv_buffer[MAX_INPUT_BUFFER];
347 int res = get_ups_variable("ups.status", recv_buffer, config);
414 if (res == NOSUCHVAR) { 348 if (res == NOSUCHVAR) {
415 return OK; 349 return result;
416 } 350 }
417 351
418 if (res != STATE_OK) { 352 if (res != STATE_OK) {
419 printf("%s\n", _("Invalid response received from host")); 353 printf("%s\n", _("Invalid response received from host"));
420 return ERROR; 354 result.errorcode = ERROR;
355 return result;
421 } 356 }
422 357
423 *supported_options |= UPS_STATUS; 358 result.supported_options |= UPS_STATUS;
424 359
425 char temp_buffer[MAX_INPUT_BUFFER]; 360 char temp_buffer[MAX_INPUT_BUFFER];
426 361
427 strcpy(temp_buffer, recv_buffer); 362 strcpy(temp_buffer, recv_buffer);
428 for (char *ptr = (char *)strtok(temp_buffer, " "); ptr != NULL; 363 for (char *ptr = strtok(temp_buffer, " "); ptr != NULL; ptr = strtok(NULL, " ")) {
429 ptr = (char *)strtok(NULL, " ")) {
430 if (!strcmp(ptr, "OFF")) { 364 if (!strcmp(ptr, "OFF")) {
431 config->status |= UPSSTATUS_OFF; 365 result.ups_status |= UPSSTATUS_OFF;
432 } else if (!strcmp(ptr, "OL")) { 366 } else if (!strcmp(ptr, "OL")) {
433 config->status |= UPSSTATUS_OL; 367 result.ups_status |= UPSSTATUS_OL;
434 } else if (!strcmp(ptr, "OB")) { 368 } else if (!strcmp(ptr, "OB")) {
435 config->status |= UPSSTATUS_OB; 369 result.ups_status |= UPSSTATUS_OB;
436 } else if (!strcmp(ptr, "LB")) { 370 } else if (!strcmp(ptr, "LB")) {
437 config->status |= UPSSTATUS_LB; 371 result.ups_status |= UPSSTATUS_LB;
438 } else if (!strcmp(ptr, "CAL")) { 372 } else if (!strcmp(ptr, "CAL")) {
439 config->status |= UPSSTATUS_CAL; 373 result.ups_status |= UPSSTATUS_CAL;
440 } else if (!strcmp(ptr, "RB")) { 374 } else if (!strcmp(ptr, "RB")) {
441 config->status |= UPSSTATUS_RB; 375 result.ups_status |= UPSSTATUS_RB;
442 } else if (!strcmp(ptr, "BYPASS")) { 376 } else if (!strcmp(ptr, "BYPASS")) {
443 config->status |= UPSSTATUS_BYPASS; 377 result.ups_status |= UPSSTATUS_BYPASS;
444 } else if (!strcmp(ptr, "OVER")) { 378 } else if (!strcmp(ptr, "OVER")) {
445 config->status |= UPSSTATUS_OVER; 379 result.ups_status |= UPSSTATUS_OVER;
446 } else if (!strcmp(ptr, "TRIM")) { 380 } else if (!strcmp(ptr, "TRIM")) {
447 config->status |= UPSSTATUS_TRIM; 381 result.ups_status |= UPSSTATUS_TRIM;
448 } else if (!strcmp(ptr, "BOOST")) { 382 } else if (!strcmp(ptr, "BOOST")) {
449 config->status |= UPSSTATUS_BOOST; 383 result.ups_status |= UPSSTATUS_BOOST;
450 } else if (!strcmp(ptr, "CHRG")) { 384 } else if (!strcmp(ptr, "CHRG")) {
451 config->status |= UPSSTATUS_CHRG; 385 result.ups_status |= UPSSTATUS_CHRG;
452 } else if (!strcmp(ptr, "DISCHRG")) { 386 } else if (!strcmp(ptr, "DISCHRG")) {
453 config->status |= UPSSTATUS_DISCHRG; 387 result.ups_status |= UPSSTATUS_DISCHRG;
454 } else if (!strcmp(ptr, "ALARM")) { 388 } else if (!strcmp(ptr, "ALARM")) {
455 config->status |= UPSSTATUS_ALARM; 389 result.ups_status |= UPSSTATUS_ALARM;
456 } else { 390 } else {
457 config->status |= UPSSTATUS_UNKNOWN; 391 result.ups_status |= UPSSTATUS_UNKNOWN;
458 } 392 }
459 } 393 }
460 394
461 return OK; 395 return result;
462} 396}
463 397
464/* gets a variable value for a specific UPS */ 398/* gets a variable value for a specific UPS */
465int get_ups_variable(const char *varname, char *buf, const ups_config config) { 399int get_ups_variable(const char *varname, char *buf, const check_ups_config config) {
466 char send_buffer[MAX_INPUT_BUFFER]; 400 char send_buffer[MAX_INPUT_BUFFER];
467 401
468 /* create the command string to send to the UPS daemon */ 402 /* create the command string to send to the UPS daemon */
469 /* Add LOGOUT to avoid read failure logs */ 403 /* Add LOGOUT to avoid read failure logs */
470 int res = snprintf(send_buffer, sizeof(send_buffer), 404 int res = snprintf(send_buffer, sizeof(send_buffer), "GET VAR %s %s\nLOGOUT\n", config.ups_name, varname);
471 "GET VAR %s %s\nLOGOUT\n", config.ups_name, varname);
472 if ((res > 0) && ((size_t)res >= sizeof(send_buffer))) { 405 if ((res > 0) && ((size_t)res >= sizeof(send_buffer))) {
473 printf("%s\n", _("UPS name to long for buffer")); 406 printf("%s\n", _("UPS name to long for buffer"));
474 return ERROR; 407 return ERROR;
@@ -477,9 +410,7 @@ int get_ups_variable(const char *varname, char *buf, const ups_config config) {
477 char temp_buffer[MAX_INPUT_BUFFER]; 410 char temp_buffer[MAX_INPUT_BUFFER];
478 411
479 /* send the command to the daemon and get a response back */ 412 /* send the command to the daemon and get a response back */
480 if (process_tcp_request(config.server_address, config.server_port, 413 if (process_tcp_request(config.server_address, config.server_port, send_buffer, temp_buffer, sizeof(temp_buffer)) != STATE_OK) {
481 send_buffer, temp_buffer,
482 sizeof(temp_buffer)) != STATE_OK) {
483 printf("%s\n", _("Invalid response received from host")); 414 printf("%s\n", _("Invalid response received from host"));
484 return ERROR; 415 return ERROR;
485 } 416 }
@@ -496,8 +427,7 @@ int get_ups_variable(const char *varname, char *buf, const ups_config config) {
496 ptr[len - 1] = 0; 427 ptr[len - 1] = 0;
497 } 428 }
498 if (strcmp(ptr, "ERR UNKNOWN-UPS") == 0) { 429 if (strcmp(ptr, "ERR UNKNOWN-UPS") == 0) {
499 printf(_("CRITICAL - no such UPS '%s' on that host\n"), 430 printf(_("CRITICAL - no such UPS '%s' on that host\n"), config.ups_name);
500 config.ups_name);
501 return ERROR; 431 return ERROR;
502 } 432 }
503 433
@@ -534,7 +464,7 @@ int get_ups_variable(const char *varname, char *buf, const ups_config config) {
534 [-wv warn_value] [-cv crit_value] [-to to_sec] */ 464 [-wv warn_value] [-cv crit_value] [-to to_sec] */
535 465
536/* process command-line arguments */ 466/* process command-line arguments */
537int process_arguments(int argc, char **argv, ups_config *config) { 467check_ups_config_wrapper process_arguments(int argc, char **argv) {
538 468
539 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 469 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
540 {"ups", required_argument, 0, 'u'}, 470 {"ups", required_argument, 0, 'u'},
@@ -548,8 +478,14 @@ int process_arguments(int argc, char **argv, ups_config *config) {
548 {"help", no_argument, 0, 'h'}, 478 {"help", no_argument, 0, 'h'},
549 {0, 0, 0, 0}}; 479 {0, 0, 0, 0}};
550 480
481 check_ups_config_wrapper result = {
482 .errorcode = OK,
483 .config = check_ups_config_init(),
484 };
485
551 if (argc < 2) { 486 if (argc < 2) {
552 return ERROR; 487 result.errorcode = ERROR;
488 return result;
553 } 489 }
554 490
555 int c; 491 int c;
@@ -576,52 +512,52 @@ int process_arguments(int argc, char **argv, ups_config *config) {
576 usage5(); 512 usage5();
577 case 'H': /* hostname */ 513 case 'H': /* hostname */
578 if (is_host(optarg)) { 514 if (is_host(optarg)) {
579 config->server_address = optarg; 515 result.config.server_address = optarg;
580 } else { 516 } else {
581 usage2(_("Invalid hostname/address"), optarg); 517 usage2(_("Invalid hostname/address"), optarg);
582 } 518 }
583 break; 519 break;
584 case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for 520 case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for
585 Fahrenheit) */ 521 Fahrenheit) */
586 config->temp_output_c = true; 522 result.config.temp_output_c = true;
587 break; 523 break;
588 case 'u': /* ups name */ 524 case 'u': /* ups name */
589 config->ups_name = optarg; 525 result.config.ups_name = optarg;
590 break; 526 break;
591 case 'p': /* port */ 527 case 'p': /* port */
592 if (is_intpos(optarg)) { 528 if (is_intpos(optarg)) {
593 config->server_port = atoi(optarg); 529 result.config.server_port = atoi(optarg);
594 } else { 530 } else {
595 usage2(_("Port must be a positive integer"), optarg); 531 usage2(_("Port must be a positive integer"), optarg);
596 } 532 }
597 break; 533 break;
598 case 'c': /* critical time threshold */ 534 case 'c': /* critical time threshold */
599 if (is_intnonneg(optarg)) { 535 if (is_intnonneg(optarg)) {
600 config->critical_value = atoi(optarg); 536 result.config.critical_value = atoi(optarg);
601 config->check_crit = true; 537 result.config.check_crit = true;
602 } else { 538 } else {
603 usage2(_("Critical time must be a positive integer"), optarg); 539 usage2(_("Critical time must be a positive integer"), optarg);
604 } 540 }
605 break; 541 break;
606 case 'w': /* warning time threshold */ 542 case 'w': /* warning time threshold */
607 if (is_intnonneg(optarg)) { 543 if (is_intnonneg(optarg)) {
608 config->warning_value = atoi(optarg); 544 result.config.warning_value = atoi(optarg);
609 config->check_warn = true; 545 result.config.check_warn = true;
610 } else { 546 } else {
611 usage2(_("Warning time must be a positive integer"), optarg); 547 usage2(_("Warning time must be a positive integer"), optarg);
612 } 548 }
613 break; 549 break;
614 case 'v': /* variable */ 550 case 'v': /* variable */
615 if (!strcmp(optarg, "LINE")) { 551 if (!strcmp(optarg, "LINE")) {
616 config->check_variable = UPS_UTILITY; 552 result.config.check_variable = UPS_UTILITY;
617 } else if (!strcmp(optarg, "TEMP")) { 553 } else if (!strcmp(optarg, "TEMP")) {
618 config->check_variable = UPS_TEMP; 554 result.config.check_variable = UPS_TEMP;
619 } else if (!strcmp(optarg, "BATTPCT")) { 555 } else if (!strcmp(optarg, "BATTPCT")) {
620 config->check_variable = UPS_BATTPCT; 556 result.config.check_variable = UPS_BATTPCT;
621 } else if (!strcmp(optarg, "LOADPCT")) { 557 } else if (!strcmp(optarg, "LOADPCT")) {
622 config->check_variable = UPS_LOADPCT; 558 result.config.check_variable = UPS_LOADPCT;
623 } else if (!strcmp(optarg, "REALPOWER")) { 559 } else if (!strcmp(optarg, "REALPOWER")) {
624 config->check_variable = UPS_REALPOWER; 560 result.config.check_variable = UPS_REALPOWER;
625 } else { 561 } else {
626 usage2(_("Unrecognized UPS variable"), optarg); 562 usage2(_("Unrecognized UPS variable"), optarg);
627 } 563 }
@@ -642,27 +578,27 @@ int process_arguments(int argc, char **argv, ups_config *config) {
642 } 578 }
643 } 579 }
644 580
645 if (config->server_address == NULL && argc > optind) { 581 if (result.config.server_address == NULL && argc > optind) {
646 if (is_host(argv[optind])) { 582 if (is_host(argv[optind])) {
647 config->server_address = argv[optind++]; 583 result.config.server_address = argv[optind++];
648 } else { 584 } else {
649 usage2(_("Invalid hostname/address"), optarg); 585 usage2(_("Invalid hostname/address"), optarg);
650 } 586 }
651 } 587 }
652 588
653 if (config->server_address == NULL) { 589 if (result.config.server_address == NULL) {
654 config->server_address = strdup("127.0.0.1"); 590 result.config.server_address = strdup("127.0.0.1");
655 } 591 }
656 592
657 return validate_arguments(*config); 593 return validate_arguments(result);
658} 594}
659 595
660int validate_arguments(ups_config config) { 596check_ups_config_wrapper validate_arguments(check_ups_config_wrapper config_wrapper) {
661 if (!config.ups_name) { 597 if (config_wrapper.config.ups_name) {
662 printf("%s\n", _("Error : no UPS indicated")); 598 printf("%s\n", _("Error : no UPS indicated"));
663 return ERROR; 599 config_wrapper.errorcode = ERROR;
664 } 600 }
665 return OK; 601 return config_wrapper;
666} 602}
667 603
668void print_help(void) { 604void print_help(void) {
@@ -694,8 +630,7 @@ void print_help(void) {
694 printf(" %s\n", "-T, --temperature"); 630 printf(" %s\n", "-T, --temperature");
695 printf(" %s\n", _("Output of temperatures in Celsius")); 631 printf(" %s\n", _("Output of temperatures in Celsius"));
696 printf(" %s\n", "-v, --variable=STRING"); 632 printf(" %s\n", "-v, --variable=STRING");
697 printf(" %s %s\n", _("Valid values for STRING are"), 633 printf(" %s %s\n", _("Valid values for STRING are"), "LINE, TEMP, BATTPCT, LOADPCT or REALPOWER");
698 "LINE, TEMP, BATTPCT, LOADPCT or REALPOWER");
699 634
700 printf(UT_WARN_CRIT); 635 printf(UT_WARN_CRIT);
701 636
@@ -731,8 +666,7 @@ void print_help(void) {
731 "with Russell Kroll's")); 666 "with Russell Kroll's"));
732 printf(" %s\n", _("Network UPS Tools be installed on the remote host. If " 667 printf(" %s\n", _("Network UPS Tools be installed on the remote host. If "
733 "you do not have the")); 668 "you do not have the"));
734 printf(" %s\n", 669 printf(" %s\n", _("package installed on your system, you can download it from"));
735 _("package installed on your system, you can download it from"));
736 printf(" %s\n", _("http://www.networkupstools.org")); 670 printf(" %s\n", _("http://www.networkupstools.org"));
737 671
738 printf(UT_SUPPORT); 672 printf(UT_SUPPORT);
diff --git a/plugins/check_ups.d/config.h b/plugins/check_ups.d/config.h
new file mode 100644
index 00000000..353104f2
--- /dev/null
+++ b/plugins/check_ups.d/config.h
@@ -0,0 +1,55 @@
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}
55
diff --git a/plugins/check_users.c b/plugins/check_users.c
index 89b95369..f1e1c39d 100644
--- a/plugins/check_users.c
+++ b/plugins/check_users.c
@@ -1,71 +1,69 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_users plugin 3 * Monitoring check_users plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2012 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_users plugin 10 * This file contains the check_users plugin
11* 11 *
12* This plugin checks the number of users currently logged in on the local 12 * This plugin checks the number of users currently logged in on the local
13* system and generates an error if the number exceeds the thresholds 13 * system and generates an error if the number exceeds the thresholds
14* specified. 14 * specified.
15* 15 *
16* 16 *
17* This program is free software: you can redistribute it and/or modify 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 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 19 * the Free Software Foundation, either version 3 of the License, or
20* (at your option) any later version. 20 * (at your option) any later version.
21* 21 *
22* This program is distributed in the hope that it will be useful, 22 * This program is distributed in the hope that it will be useful,
23* but WITHOUT ANY WARRANTY; without even the implied warranty of 23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25* GNU General Public License for more details. 25 * GNU General Public License for more details.
26* 26 *
27* You should have received a copy of the GNU General Public License 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/>. 28 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29* 29 *
30* 30 *
31*****************************************************************************/ 31 *****************************************************************************/
32 32
33const char *progname = "check_users"; 33const char *progname = "check_users";
34const char *copyright = "2000-2007"; 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 "common.h"
38#include "utils.h" 38#include "utils.h"
39 39
40#if HAVE_WTSAPI32_H 40#if HAVE_WTSAPI32_H
41# include <windows.h> 41# include <windows.h>
42# include <wtsapi32.h> 42# include <wtsapi32.h>
43# undef ERROR 43# undef ERROR
44# define ERROR -1 44# define ERROR -1
45#elif HAVE_UTMPX_H 45#elif HAVE_UTMPX_H
46# include <utmpx.h> 46# include <utmpx.h>
47#else 47#else
48# include "popen.h" 48# include "popen.h"
49#endif 49#endif
50 50
51#ifdef HAVE_LIBSYSTEMD 51#ifdef HAVE_LIBSYSTEMD
52#include <systemd/sd-daemon.h> 52# include <systemd/sd-daemon.h>
53#include <systemd/sd-login.h> 53# include <systemd/sd-login.h>
54#endif 54#endif
55 55
56#define possibly_set(a,b) ((a) == 0 ? (b) : 0) 56#define possibly_set(a, b) ((a) == 0 ? (b) : 0)
57 57
58int process_arguments (int, char **); 58static int process_arguments(int, char **);
59void print_help (void); 59static void print_help(void);
60void print_usage (void); 60void print_usage(void);
61 61
62char *warning_range = NULL; 62static char *warning_range = NULL;
63char *critical_range = NULL; 63static char *critical_range = NULL;
64thresholds *thlds = NULL; 64static thresholds *thlds = NULL;
65 65
66int 66int main(int argc, char **argv) {
67main (int argc, char **argv)
68{
69 int users = -1; 67 int users = -1;
70 int result = STATE_UNKNOWN; 68 int result = STATE_UNKNOWN;
71#if HAVE_WTSAPI32_H 69#if HAVE_WTSAPI32_H
@@ -78,74 +76,71 @@ main (int argc, char **argv)
78 char input_buffer[MAX_INPUT_BUFFER]; 76 char input_buffer[MAX_INPUT_BUFFER];
79#endif 77#endif
80 78
81 setlocale (LC_ALL, ""); 79 setlocale(LC_ALL, "");
82 bindtextdomain (PACKAGE, LOCALEDIR); 80 bindtextdomain(PACKAGE, LOCALEDIR);
83 textdomain (PACKAGE); 81 textdomain(PACKAGE);
84 82
85 /* Parse extra opts if any */ 83 /* Parse extra opts if any */
86 argv = np_extra_opts (&argc, argv, progname); 84 argv = np_extra_opts(&argc, argv, progname);
87 85
88 if (process_arguments (argc, argv) == ERROR) 86 if (process_arguments(argc, argv) == ERROR)
89 usage4 (_("Could not parse arguments")); 87 usage4(_("Could not parse arguments"));
90 88
91 users = 0; 89 users = 0;
92 90
93#ifdef HAVE_LIBSYSTEMD 91#ifdef HAVE_LIBSYSTEMD
94 if (sd_booted () > 0) 92 if (sd_booted() > 0)
95 users = sd_get_sessions (NULL); 93 users = sd_get_sessions(NULL);
96 else { 94 else {
97#endif 95#endif
98#if HAVE_WTSAPI32_H 96#if HAVE_WTSAPI32_H
99 if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 97 if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &wtsinfo, &wtscount)) {
100 0, 1, &wtsinfo, &wtscount)) { 98 printf(_("Could not enumerate RD sessions: %d\n"), GetLastError());
101 printf(_("Could not enumerate RD sessions: %d\n"), GetLastError()); 99 return STATE_UNKNOWN;
102 return STATE_UNKNOWN; 100 }
103 }
104 101
105 for (index = 0; index < wtscount; index++) { 102 for (index = 0; index < wtscount; index++) {
106 LPTSTR username; 103 LPTSTR username;
107 DWORD size; 104 DWORD size;
108 int len; 105 int len;
109 106
110 if (!WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, 107 if (!WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, wtsinfo[index].SessionId, WTSUserName, &username, &size))
111 wtsinfo[index].SessionId, WTSUserName, &username, &size)) 108 continue;
112 continue;
113 109
114 len = lstrlen(username); 110 len = lstrlen(username);
115 111
116 WTSFreeMemory(username); 112 WTSFreeMemory(username);
117 113
118 if (len == 0) 114 if (len == 0)
119 continue; 115 continue;
120 116
121 if (wtsinfo[index].State == WTSActive || 117 if (wtsinfo[index].State == WTSActive || wtsinfo[index].State == WTSDisconnected)
122 wtsinfo[index].State == WTSDisconnected) 118 users++;
123 users++; 119 }
124 }
125 120
126 WTSFreeMemory(wtsinfo); 121 WTSFreeMemory(wtsinfo);
127#elif HAVE_UTMPX_H 122#elif HAVE_UTMPX_H
128 /* get currently logged users from utmpx */ 123 /* get currently logged users from utmpx */
129 setutxent (); 124 setutxent();
130 125
131 while ((putmpx = getutxent ()) != NULL) 126 while ((putmpx = getutxent()) != NULL)
132 if (putmpx->ut_type == USER_PROCESS) 127 if (putmpx->ut_type == USER_PROCESS)
133 users++; 128 users++;
134 129
135 endutxent (); 130 endutxent();
136#else 131#else
137 /* run the command */ 132 /* run the command */
138 child_process = spopen (WHO_COMMAND); 133 child_process = spopen(WHO_COMMAND);
139 if (child_process == NULL) { 134 if (child_process == NULL) {
140 printf (_("Could not open pipe: %s\n"), WHO_COMMAND); 135 printf(_("Could not open pipe: %s\n"), WHO_COMMAND);
141 return STATE_UNKNOWN; 136 return STATE_UNKNOWN;
142 } 137 }
143 138
144 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); 139 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
145 if (child_stderr == NULL) 140 if (child_stderr == NULL)
146 printf (_("Could not open stderr for %s\n"), WHO_COMMAND); 141 printf(_("Could not open stderr for %s\n"), WHO_COMMAND);
147 142
148 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) { 143 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
149 /* increment 'users' on all lines except total user count */ 144 /* increment 'users' on all lines except total user count */
150 if (input_buffer[0] != '#') { 145 if (input_buffer[0] != '#') {
151 users++; 146 users++;
@@ -153,18 +148,18 @@ main (int argc, char **argv)
153 } 148 }
154 149
155 /* get total logged in users */ 150 /* get total logged in users */
156 if (sscanf (input_buffer, _("# users=%d"), &users) == 1) 151 if (sscanf(input_buffer, _("# users=%d"), &users) == 1)
157 break; 152 break;
158 } 153 }
159 154
160 /* check STDERR */ 155 /* check STDERR */
161 if (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) 156 if (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr))
162 result = possibly_set (result, STATE_UNKNOWN); 157 result = possibly_set(result, STATE_UNKNOWN);
163 (void) fclose (child_stderr); 158 (void)fclose(child_stderr);
164 159
165 /* close the pipe */ 160 /* close the pipe */
166 if (spclose (child_process)) 161 if (spclose(child_process))
167 result = possibly_set (result, STATE_UNKNOWN); 162 result = possibly_set(result, STATE_UNKNOWN);
168#endif 163#endif
169#ifdef HAVE_LIBSYSTEMD 164#ifdef HAVE_LIBSYSTEMD
170 } 165 }
@@ -174,109 +169,99 @@ main (int argc, char **argv)
174 result = get_status((double)users, thlds); 169 result = get_status((double)users, thlds);
175 170
176 if (result == STATE_UNKNOWN) 171 if (result == STATE_UNKNOWN)
177 printf ("%s\n", _("Unable to read output")); 172 printf("%s\n", _("Unable to read output"));
178 else { 173 else {
179 printf (_("USERS %s - %d users currently logged in |%s\n"), 174 printf(_("USERS %s - %d users currently logged in |%s\n"), state_text(result), users,
180 state_text(result), users, 175 sperfdata_int("users", users, "", warning_range, critical_range, true, 0, false, 0));
181 sperfdata_int("users", users, "", warning_range,
182 critical_range, true, 0, false, 0));
183 } 176 }
184 177
185 return result; 178 return result;
186} 179}
187 180
188/* process command-line arguments */ 181/* process command-line arguments */
189int 182int process_arguments(int argc, char **argv) {
190process_arguments (int argc, char **argv) 183 static struct option longopts[] = {{"critical", required_argument, 0, 'c'},
191{ 184 {"warning", required_argument, 0, 'w'},
192 int c; 185 {"version", no_argument, 0, 'V'},
193 int option = 0; 186 {"help", no_argument, 0, 'h'},
194 static struct option longopts[] = { 187 {0, 0, 0, 0}};
195 {"critical", required_argument, 0, 'c'},
196 {"warning", required_argument, 0, 'w'},
197 {"version", no_argument, 0, 'V'},
198 {"help", no_argument, 0, 'h'},
199 {0, 0, 0, 0}
200 };
201 188
202 if (argc < 2) 189 if (argc < 2)
203 usage ("\n"); 190 usage("\n");
204 191
192 int option_char;
205 while (true) { 193 while (true) {
206 c = getopt_long (argc, argv, "+hVvc:w:", longopts, &option); 194 int option = 0;
195 option_char = getopt_long(argc, argv, "+hVvc:w:", longopts, &option);
207 196
208 if (c == -1 || c == EOF || c == 1) 197 if (option_char == -1 || option_char == EOF || option_char == 1)
209 break; 198 break;
210 199
211 switch (c) { 200 switch (option_char) {
212 case '?': /* print short usage statement if args not parsable */ 201 case '?': /* print short usage statement if args not parsable */
213 usage5 (); 202 usage5();
214 case 'h': /* help */ 203 case 'h': /* help */
215 print_help (); 204 print_help();
216 exit (STATE_UNKNOWN); 205 exit(STATE_UNKNOWN);
217 case 'V': /* version */ 206 case 'V': /* version */
218 print_revision (progname, NP_VERSION); 207 print_revision(progname, NP_VERSION);
219 exit (STATE_UNKNOWN); 208 exit(STATE_UNKNOWN);
220 case 'c': /* critical */ 209 case 'c': /* critical */
221 critical_range = optarg; 210 critical_range = optarg;
222 break; 211 break;
223 case 'w': /* warning */ 212 case 'w': /* warning */
224 warning_range = optarg; 213 warning_range = optarg;
225 break; 214 break;
226 } 215 }
227 } 216 }
228 217
229 c = optind; 218 option_char = optind;
230 219
231 if (warning_range == NULL && argc > c) 220 if (warning_range == NULL && argc > option_char)
232 warning_range = argv[c++]; 221 warning_range = argv[option_char++];
233 222
234 if (critical_range == NULL && argc > c) 223 if (critical_range == NULL && argc > option_char)
235 critical_range = argv[c++]; 224 critical_range = argv[option_char++];
236 225
237 /* this will abort in case of invalid ranges */ 226 /* this will abort in case of invalid ranges */
238 set_thresholds (&thlds, warning_range, critical_range); 227 set_thresholds(&thlds, warning_range, critical_range);
239 228
240 if (!thlds->warning) { 229 if (!thlds->warning) {
241 usage4 (_("Warning threshold must be a valid range expression")); 230 usage4(_("Warning threshold must be a valid range expression"));
242 } 231 }
243 232
244 if (!thlds->critical) { 233 if (!thlds->critical) {
245 usage4 (_("Critical threshold must be a valid range expression")); 234 usage4(_("Critical threshold must be a valid range expression"));
246 } 235 }
247 236
248 return OK; 237 return OK;
249} 238}
250 239
251void 240void print_help(void) {
252print_help (void) 241 print_revision(progname, NP_VERSION);
253{
254 print_revision (progname, NP_VERSION);
255 242
256 printf ("Copyright (c) 1999 Ethan Galstad\n"); 243 printf("Copyright (c) 1999 Ethan Galstad\n");
257 printf (COPYRIGHT, copyright, email); 244 printf(COPYRIGHT, copyright, email);
258 245
259 printf ("%s\n", _("This plugin checks the number of users currently logged in on the local")); 246 printf("%s\n", _("This plugin checks the number of users currently logged in on the local"));
260 printf ("%s\n", _("system and generates an error if the number exceeds the thresholds specified.")); 247 printf("%s\n", _("system and generates an error if the number exceeds the thresholds specified."));
261 248
262 printf ("\n\n"); 249 printf("\n\n");
263 250
264 print_usage (); 251 print_usage();
265 252
266 printf (UT_HELP_VRSN); 253 printf(UT_HELP_VRSN);
267 printf (UT_EXTRA_OPTS); 254 printf(UT_EXTRA_OPTS);
268 255
269 printf (" %s\n", "-w, --warning=RANGE_EXPRESSION"); 256 printf(" %s\n", "-w, --warning=RANGE_EXPRESSION");
270 printf (" %s\n", _("Set WARNING status if number of logged in users violates RANGE_EXPRESSION")); 257 printf(" %s\n", _("Set WARNING status if number of logged in users violates RANGE_EXPRESSION"));
271 printf (" %s\n", "-c, --critical=RANGE_EXPRESSION"); 258 printf(" %s\n", "-c, --critical=RANGE_EXPRESSION");
272 printf (" %s\n", _("Set CRITICAL status if number of logged in users violates RANGE_EXPRESSION")); 259 printf(" %s\n", _("Set CRITICAL status if number of logged in users violates RANGE_EXPRESSION"));
273 260
274 printf (UT_SUPPORT); 261 printf(UT_SUPPORT);
275} 262}
276 263
277void 264void print_usage(void) {
278print_usage (void) 265 printf("%s\n", _("Usage:"));
279{ 266 printf("%s -w <users> -c <users>\n", progname);
280 printf ("%s\n", _("Usage:"));
281 printf ("%s -w <users> -c <users>\n", progname);
282} 267}
diff --git a/plugins/common.h b/plugins/common.h
index 833479ce..35d1e549 100644
--- a/plugins/common.h
+++ b/plugins/common.h
@@ -31,7 +31,8 @@
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 36
36#ifdef HAVE_FEATURES_H 37#ifdef HAVE_FEATURES_H
37#include <features.h> 38#include <features.h>
@@ -90,16 +91,10 @@
90# define GET_NUMBER_OF_CPUS() -1 91# define GET_NUMBER_OF_CPUS() -1
91#endif 92#endif
92 93
93#ifdef TIME_WITH_SYS_TIME 94#ifdef HAVE_SYS_TIME_H
94# include <sys/time.h> 95# include <sys/time.h>
95# include <time.h>
96#else
97# ifdef HAVE_SYS_TIME_H
98# include <sys/time.h>
99# else
100# include <time.h>
101# endif
102#endif 96#endif
97#include <time.h>
103 98
104#ifdef HAVE_SYS_TYPES_H 99#ifdef HAVE_SYS_TYPES_H
105#include <sys/types.h> 100#include <sys/types.h>
@@ -115,7 +110,7 @@
115 110
116/* GNU Libraries */ 111/* GNU Libraries */
117#include <getopt.h> 112#include <getopt.h>
118#include "dirname.h" 113#include "../gl/dirname.h"
119 114
120#include <locale.h> 115#include <locale.h>
121 116
@@ -185,14 +180,6 @@ enum {
185}; 180};
186 181
187enum { 182enum {
188 STATE_OK,
189 STATE_WARNING,
190 STATE_CRITICAL,
191 STATE_UNKNOWN,
192 STATE_DEPENDENT
193};
194
195enum {
196 DEFAULT_SOCKET_TIMEOUT = 10, /* timeout after 10 seconds */ 183 DEFAULT_SOCKET_TIMEOUT = 10, /* timeout after 10 seconds */
197 MAX_INPUT_BUFFER = 8192, /* max size of most buffers we use */ 184 MAX_INPUT_BUFFER = 8192, /* max size of most buffers we use */
198 MAX_HOST_ADDRESS_LENGTH = 256 /* max size of a host address */ 185 MAX_HOST_ADDRESS_LENGTH = 256 /* max size of a host address */
@@ -203,7 +190,7 @@ enum {
203 * Internationalization 190 * Internationalization
204 * 191 *
205 */ 192 */
206#include "gettext.h" 193#include "../gl/gettext.h"
207#define _(String) gettext (String) 194#define _(String) gettext (String)
208#if ! ENABLE_NLS 195#if ! ENABLE_NLS
209# undef textdomain 196# undef textdomain
diff --git a/plugins/negate.c b/plugins/negate.c
index c5fe7e13..0520d298 100644
--- a/plugins/negate.c
+++ b/plugins/negate.c
@@ -1,36 +1,36 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring negate plugin 3 * Monitoring negate plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2002-2008 Monitoring Plugins Development Team 6 * Copyright (c) 2002-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the negate plugin 10 * This file contains the negate plugin
11* 11 *
12* Negates the status of a plugin (returns OK for CRITICAL, and vice-versa). 12 * Negates the status of a plugin (returns OK for CRITICAL, and vice-versa).
13* Can also perform custom state switching. 13 * Can also perform custom state switching.
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 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 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 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 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/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "negate"; 32const char *progname = "negate";
33const char *copyright = "2002-2008"; 33const char *copyright = "2002-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#define DEFAULT_TIMEOUT 11 36#define DEFAULT_TIMEOUT 11
@@ -38,203 +38,203 @@ 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
44/* char *command_line; */ 51static void print_help(void);
52void print_usage(void);
45 53
46static const char **process_arguments (int, char **); 54int main(int argc, char **argv) {
47void validate_arguments (char **); 55 setlocale(LC_ALL, "");
48void print_help (void); 56 bindtextdomain(PACKAGE, LOCALEDIR);
49void print_usage (void); 57 textdomain(PACKAGE);
50bool subst_text = false;
51 58
52static int state[4] = { 59 timeout_interval = DEFAULT_TIMEOUT;
53 STATE_OK,
54 STATE_WARNING,
55 STATE_CRITICAL,
56 STATE_UNKNOWN,
57};
58 60
59int 61 negate_config_wrapper tmp_config = process_arguments(argc, argv);
60main (int argc, char **argv)
61{
62 int result = STATE_UNKNOWN;
63 char *sub;
64 char **command_line;
65 output chld_out, chld_err;
66 62
67 setlocale (LC_ALL, ""); 63 if (tmp_config.errorcode == ERROR) {
68 bindtextdomain (PACKAGE, LOCALEDIR); 64 die(STATE_UNKNOWN, _("negate: Failed to parse input"));
69 textdomain (PACKAGE); 65 }
70 66
71 timeout_interval = DEFAULT_TIMEOUT; 67 negate_config config = tmp_config.config;
72 68
73 command_line = (char **) process_arguments (argc, argv); 69 char **command_line = config.command_line;
74 70
75 /* Set signal handling and alarm */ 71 /* Set signal handling and alarm */
76 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) 72 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
77 die (STATE_UNKNOWN, _("Cannot catch SIGALRM")); 73 die(STATE_UNKNOWN, _("Cannot catch SIGALRM"));
74 }
75
76 (void)alarm(timeout_interval);
78 77
79 (void) alarm ((unsigned) timeout_interval); 78 mp_state_enum result = STATE_UNKNOWN;
79 output chld_out;
80 output chld_err;
80 81
81 /* catch when the command is quoted */ 82 /* catch when the command is quoted */
82 if(command_line[1] == NULL) { 83 if (command_line[1] == NULL) {
83 result = cmd_run (command_line[0], &chld_out, &chld_err, 0); 84 result = cmd_run(command_line[0], &chld_out, &chld_err, 0);
84 } else { 85 } else {
85 result = cmd_run_array (command_line, &chld_out, &chld_err, 0); 86 result = cmd_run_array(command_line, &chld_out, &chld_err, 0);
86 } 87 }
87 if (chld_err.lines > 0) { 88 if (chld_err.lines > 0) {
88 for (size_t i = 0; i < chld_err.lines; i++) { 89 for (size_t i = 0; i < chld_err.lines; i++) {
89 fprintf (stderr, "%s\n", chld_err.line[i]); 90 fprintf(stderr, "%s\n", chld_err.line[i]);
90 } 91 }
91 } 92 }
92 93
93 /* Return UNKNOWN or worse if no output is returned */ 94 /* Return UNKNOWN or worse if no output is returned */
94 if (chld_out.lines == 0) 95 if (chld_out.lines == 0) {
95 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 }
96 98
99 char *sub;
97 for (size_t i = 0; i < chld_out.lines; i++) { 100 for (size_t i = 0; i < chld_out.lines; i++) {
98 if (subst_text && result >= 0 && result <= 4 && result != state[result]) { 101 if (config.subst_text && result >= 0 && result <= 4 && result != config.state[result]) {
99 /* Loop over each match found */ 102 /* Loop over each match found */
100 while ((sub = strstr (chld_out.line[i], state_text (result)))) { 103 while ((sub = strstr(chld_out.line[i], state_text(result)))) {
101 /* 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 */
102 *sub = '\0'; 105 *sub = '\0';
103 sub += strlen (state_text (result)); 106 sub += strlen(state_text(result));
104 /* then put everything back together */ 107 /* then put everything back together */
105 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], state_text(config.state[result]), sub);
106 } 109 }
107 } 110 }
108 printf ("%s\n", chld_out.line[i]); 111 printf("%s\n", chld_out.line[i]);
109 } 112 }
110 113
111 if (result >= 0 && result <= 4) { 114 if (result >= 0 && result <= 4) {
112 exit (state[result]); 115 exit(config.state[result]);
113 } else { 116 } else {
114 exit (result); 117 exit(result);
115 } 118 }
116} 119}
117 120
118
119/* process command-line arguments */ 121/* process command-line arguments */
120static const char ** 122static negate_config_wrapper process_arguments(int argc, char **argv) {
121process_arguments (int argc, char **argv) 123 static struct option longopts[] = {{"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'},
122{ 124 {"timeout", required_argument, 0, 't'}, {"timeout-result", required_argument, 0, 'T'},
123 int c; 125 {"ok", required_argument, 0, 'o'}, {"warning", required_argument, 0, 'w'},
124 bool permute = true; 126 {"critical", required_argument, 0, 'c'}, {"unknown", required_argument, 0, 'u'},
125 127 {"substitute", no_argument, 0, 's'}, {0, 0, 0, 0}};
126 int option = 0; 128
127 static struct option longopts[] = { 129 negate_config_wrapper result = {
128 {"help", no_argument, 0, 'h'}, 130 .errorcode = OK,
129 {"version", no_argument, 0, 'V'}, 131 .config = negate_config_init(),
130 {"timeout", required_argument, 0, 't'},
131 {"timeout-result", required_argument, 0, 'T'},
132 {"ok", required_argument, 0, 'o'},
133 {"warning", required_argument, 0, 'w'},
134 {"critical", required_argument, 0, 'c'},
135 {"unknown", required_argument, 0, 'u'},
136 {"substitute", no_argument, 0, 's'},
137 {0, 0, 0, 0}
138 }; 132 };
133 bool permute = true;
134 while (true) {
135 int option = 0;
136 int option_char = getopt_long(argc, argv, "+hVt:T:o:w:c:u:s", longopts, &option);
139 137
140 while (1) { 138 if (option_char == -1 || option_char == EOF) {
141 c = getopt_long (argc, argv, "+hVt:T:o:w:c:u:s", longopts, &option);
142
143 if (c == -1 || c == EOF)
144 break; 139 break;
140 }
145 141
146 switch (c) { 142 switch (option_char) {
147 case '?': /* help */ 143 case '?': /* help */
148 usage5 (); 144 usage5();
149 break; 145 break;
150 case 'h': /* help */ 146 case 'h': /* help */
151 print_help (); 147 print_help();
152 exit (EXIT_SUCCESS); 148 exit(STATE_UNKNOWN);
153 break; 149 break;
154 case 'V': /* version */ 150 case 'V': /* version */
155 print_revision (progname, NP_VERSION); 151 print_revision(progname, NP_VERSION);
156 exit (EXIT_SUCCESS); 152 exit(STATE_UNKNOWN);
157 case 't': /* timeout period */ 153 case 't': /* timeout period */
158 if (!is_integer (optarg)) 154 if (!is_integer(optarg)) {
159 usage2 (_("Timeout interval must be a positive integer"), optarg); 155 usage2(_("Timeout interval must be a positive integer"), optarg);
160 else 156 } else {
161 timeout_interval = atoi (optarg); 157 timeout_interval = atoi(optarg);
158 }
162 break; 159 break;
163 case 'T': /* Result to return on timeouts */ 160 case 'T': /* Result to return on timeouts */
164 if ((timeout_state = mp_translate_state(optarg)) == ERROR) 161 if ((timeout_state = mp_translate_state(optarg)) == ERROR) {
165 usage4 (_("Timeout result must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 162 usage4(_("Timeout result must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
163 }
166 break; 164 break;
167 case 'o': /* replacement for OK */ 165 case 'o': /* replacement for OK */
168 if ((state[STATE_OK] = mp_translate_state(optarg)) == ERROR) 166 if ((result.config.state[STATE_OK] = mp_translate_state(optarg)) == ERROR) {
169 usage4 (_("Ok must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 167 usage4(_("Ok must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
168 }
170 permute = false; 169 permute = false;
171 break; 170 break;
172 171
173 case 'w': /* replacement for WARNING */ 172 case 'w': /* replacement for WARNING */
174 if ((state[STATE_WARNING] = mp_translate_state(optarg)) == ERROR) 173 if ((result.config.state[STATE_WARNING] = mp_translate_state(optarg)) == ERROR) {
175 usage4 (_("Warning must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 174 usage4(_("Warning must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
175 }
176 permute = false; 176 permute = false;
177 break; 177 break;
178 case 'c': /* replacement for CRITICAL */ 178 case 'c': /* replacement for CRITICAL */
179 if ((state[STATE_CRITICAL] = mp_translate_state(optarg)) == ERROR) 179 if ((result.config.state[STATE_CRITICAL] = mp_translate_state(optarg)) == ERROR) {
180 usage4 (_("Critical must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 180 usage4(_("Critical must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
181 }
181 permute = false; 182 permute = false;
182 break; 183 break;
183 case 'u': /* replacement for UNKNOWN */ 184 case 'u': /* replacement for UNKNOWN */
184 if ((state[STATE_UNKNOWN] = mp_translate_state(optarg)) == ERROR) 185 if ((result.config.state[STATE_UNKNOWN] = mp_translate_state(optarg)) == ERROR) {
185 usage4 (_("Unknown must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 186 usage4(_("Unknown must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
187 }
186 permute = false; 188 permute = false;
187 break; 189 break;
188 case 's': /* Substitute status text */ 190 case 's': /* Substitute status text */
189 subst_text = true; 191 result.config.subst_text = true;
190 break; 192 break;
191 } 193 }
192 } 194 }
193 195
194 validate_arguments (&argv[optind]);
195
196 if (permute) { /* No [owcu] switch specified, default to this */ 196 if (permute) { /* No [owcu] switch specified, default to this */
197 state[STATE_OK] = STATE_CRITICAL; 197 result.config.state[STATE_OK] = STATE_CRITICAL;
198 state[STATE_CRITICAL] = STATE_OK; 198 result.config.state[STATE_CRITICAL] = STATE_OK;
199 } 199 }
200 200
201 return (const char **) &argv[optind]; 201 result.config.command_line = &argv[optind];
202
203 return validate_arguments(result);
202} 204}
203 205
206negate_config_wrapper validate_arguments(negate_config_wrapper config_wrapper) {
207 if (config_wrapper.config.command_line[0] == NULL) {
208 usage4(_("Could not parse arguments"));
209 }
204 210
205void 211 if (strncmp(config_wrapper.config.command_line[0], "/", 1) != 0 && strncmp(config_wrapper.config.command_line[0], "./", 2) != 0) {
206validate_arguments (char **command_line) 212 usage4(_("Require path to command"));
207{ 213 }
208 if (command_line[0] == NULL)
209 usage4 (_("Could not parse arguments"));
210 214
211 if (strncmp(command_line[0],"/",1) != 0 && strncmp(command_line[0],"./",2) != 0) 215 return config_wrapper;
212 usage4 (_("Require path to command"));
213} 216}
214 217
218void print_help(void) {
219 print_revision(progname, NP_VERSION);
215 220
216void 221 printf(COPYRIGHT, copyright, email);
217print_help (void)
218{
219 print_revision (progname, NP_VERSION);
220 222
221 printf (COPYRIGHT, copyright, email); 223 printf("%s\n", _("Negates only the return code of a plugin (returns OK for CRITICAL and vice-versa) by default."));
224 printf("%s\n", _("Additional switches can be used to control:\n"));
225 printf("\t - which state becomes what\n");
226 printf("\t - changing the plugin output text to match the return code");
222 227
223 printf ("%s\n", _("Negates only the return code of a plugin (returns OK for CRITICAL and vice-versa) by default.")); 228 printf("\n\n");
224 printf ("%s\n", _("Additional switches can be used to control:\n"));
225 printf ("\t - which state becomes what\n");
226 printf ("\t - changing the plugin output text to match the return code");
227 229
228 printf ("\n\n"); 230 print_usage();
229 231
230 print_usage (); 232 printf(UT_HELP_VRSN);
231 233
232 printf (UT_HELP_VRSN); 234 printf(UT_PLUG_TIMEOUT, timeout_interval);
233 235 printf(" %s\n", _("Keep timeout longer than the plugin timeout to retain CRITICAL status."));
234 printf (UT_PLUG_TIMEOUT, timeout_interval); 236 printf(" -T, --timeout-result=STATUS\n");
235 printf (" %s\n", _("Keep timeout longer than the plugin timeout to retain CRITICAL status.")); 237 printf(" %s\n", _("Custom result on Negate timeouts; see below for STATUS definition\n"));
236 printf (" -T, --timeout-result=STATUS\n");
237 printf (" %s\n", _("Custom result on Negate timeouts; see below for STATUS definition\n"));
238 238
239 printf(" -o, --ok=STATUS\n"); 239 printf(" -o, --ok=STATUS\n");
240 printf(" -w, --warning=STATUS\n"); 240 printf(" -w, --warning=STATUS\n");
@@ -246,31 +246,27 @@ print_help (void)
246 printf(" -s, --substitute\n"); 246 printf(" -s, --substitute\n");
247 printf(_(" Substitute output text as well. Will only substitute text in CAPITALS\n")); 247 printf(_(" Substitute output text as well. Will only substitute text in CAPITALS\n"));
248 248
249 printf ("\n"); 249 printf("\n");
250 printf ("%s\n", _("Examples:")); 250 printf("%s\n", _("Examples:"));
251 printf (" %s\n", "negate /usr/local/nagios/libexec/check_ping -H host"); 251 printf(" %s\n", "negate /usr/local/nagios/libexec/check_ping -H host");
252 printf (" %s\n", _("Run check_ping and invert result. Must use full path to plugin")); 252 printf(" %s\n", _("Run check_ping and invert result. Must use full path to plugin"));
253 printf (" %s\n", "negate -w OK -c UNKNOWN /usr/local/nagios/libexec/check_procs -a 'vi negate.c'"); 253 printf(" %s\n", "negate -w OK -c UNKNOWN /usr/local/nagios/libexec/check_procs -a 'vi negate.c'");
254 printf (" %s\n", _("This will return OK instead of WARNING and UNKNOWN instead of CRITICAL")); 254 printf(" %s\n", _("This will return OK instead of WARNING and UNKNOWN instead of CRITICAL"));
255 printf ("\n"); 255 printf("\n");
256 printf ("%s\n", _("Notes:")); 256 printf("%s\n", _("Notes:"));
257 printf (" %s\n", _("This plugin is a wrapper to take the output of another plugin and invert it.")); 257 printf(" %s\n", _("This plugin is a wrapper to take the output of another plugin and invert it."));
258 printf (" %s\n", _("The full path of the plugin must be provided.")); 258 printf(" %s\n", _("The full path of the plugin must be provided."));
259 printf (" %s\n", _("If the wrapped plugin returns OK, the wrapper will return CRITICAL.")); 259 printf(" %s\n", _("If the wrapped plugin returns OK, the wrapper will return CRITICAL."));
260 printf (" %s\n", _("If the wrapped plugin returns CRITICAL, the wrapper will return OK.")); 260 printf(" %s\n", _("If the wrapped plugin returns CRITICAL, the wrapper will return OK."));
261 printf (" %s\n", _("Otherwise, the output state of the wrapped plugin is unchanged.")); 261 printf(" %s\n", _("Otherwise, the output state of the wrapped plugin is unchanged."));
262 printf ("\n"); 262 printf("\n");
263 printf (" %s\n", _("Using timeout-result, it is possible to override the timeout behaviour or a")); 263 printf(" %s\n", _("Using timeout-result, it is possible to override the timeout behaviour or a"));
264 printf (" %s\n", _("plugin by setting the negate timeout a bit lower.")); 264 printf(" %s\n", _("plugin by setting the negate timeout a bit lower."));
265 265
266 printf (UT_SUPPORT); 266 printf(UT_SUPPORT);
267} 267}
268 268
269 269void print_usage(void) {
270 270 printf("%s\n", _("Usage:"));
271void 271 printf("%s [-t timeout] [-Towcu STATE] [-s] <definition of wrapped plugin>\n", progname);
272print_usage (void)
273{
274 printf ("%s\n", _("Usage:"));
275 printf ("%s [-t timeout] [-Towcu STATE] [-s] <definition of wrapped plugin>\n", progname);
276} 272}
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 c6af248e..e2916c65 100644
--- a/plugins/netutils.c
+++ b/plugins/netutils.c
@@ -1,33 +1,35 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring Plugins network utilities 3 * Monitoring Plugins network utilities
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-2008 Monitoring Plugins Development Team 7 * Copyright (c) 2003-2024 Monitoring Plugins Development Team
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains commons functions used in many of the plugins. 11 * This file contains commons functions used in many of the plugins.
12* 12 *
13* 13 *
14* This program is free software: you can redistribute it and/or modify 14 * This program is free software: you can redistribute it and/or modify
15* it under the terms of the GNU General Public License as published by 15 * it under the terms of the GNU General Public License as published by
16* the Free Software Foundation, either version 3 of the License, or 16 * the Free Software Foundation, either version 3 of the License, or
17* (at your option) any later version. 17 * (at your option) any later version.
18* 18 *
19* This program is distributed in the hope that it will be useful, 19 * This program is distributed in the hope that it will be useful,
20* but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22* GNU General Public License for more details. 22 * GNU General Public License for more details.
23* 23 *
24* You should have received a copy of the GNU General Public License 24 * You should have received a copy of the GNU General Public License
25* along with this program. If not, see <http://www.gnu.org/licenses/>. 25 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26* 26 *
27* 27 *
28*****************************************************************************/ 28 *****************************************************************************/
29 29
30#include "common.h" 30#include "common.h"
31#include "output.h"
32#include "states.h"
31#include "netutils.h" 33#include "netutils.h"
32 34
33unsigned int socket_timeout = DEFAULT_SOCKET_TIMEOUT; 35unsigned int socket_timeout = DEFAULT_SOCKET_TIMEOUT;
@@ -42,25 +44,26 @@ int address_family = AF_INET;
42#endif 44#endif
43 45
44/* handles socket timeouts */ 46/* handles socket timeouts */
45void 47void socket_timeout_alarm_handler(int sig) {
46socket_timeout_alarm_handler (int sig) 48 mp_subcheck timeout_sc = mp_subcheck_init();
47{ 49 timeout_sc = mp_set_subcheck_state(timeout_sc, socket_timeout_state);
48 if (sig == SIGALRM) 50
49 printf (_("%s - Socket timeout after %d seconds\n"), state_text(socket_timeout_state), socket_timeout); 51 if (sig == SIGALRM) {
50 else 52 xasprintf(&timeout_sc.output, _("Socket timeout after %d seconds\n"), socket_timeout);
51 printf (_("%s - Abnormal timeout after %d seconds\n"), state_text(socket_timeout_state), socket_timeout); 53 } else {
52 54 xasprintf(&timeout_sc.output, _("Abnormal timeout after %d seconds\n"), socket_timeout);
53 exit (socket_timeout_state); 55 }
54}
55 56
57 mp_check overall = mp_check_init();
58 mp_add_subcheck_to_check(&overall, timeout_sc);
59
60 mp_exit(overall);
61}
56 62
57/* connects to a host on a specified tcp port, sends a string, and gets a 63/* connects to a host on a specified tcp port, sends a string, and gets a
58 response. loops on select-recv until timeout or eof to get all of a 64 response. loops on select-recv until timeout or eof to get all of a
59 multi-packet answer */ 65 multi-packet answer */
60int 66int process_tcp_request2(const char *server_address, int server_port, const char *send_buffer, char *recv_buffer, int recv_size) {
61process_tcp_request2 (const char *server_address, int server_port,
62 const char *send_buffer, char *recv_buffer, int recv_size)
63{
64 67
65 int result; 68 int result;
66 int send_result; 69 int send_result;
@@ -70,13 +73,14 @@ process_tcp_request2 (const char *server_address, int server_port,
70 fd_set readfds; 73 fd_set readfds;
71 int recv_length = 0; 74 int recv_length = 0;
72 75
73 result = np_net_connect (server_address, server_port, &sd, IPPROTO_TCP); 76 result = np_net_connect(server_address, server_port, &sd, IPPROTO_TCP);
74 if (result != STATE_OK) 77 if (result != STATE_OK) {
75 return STATE_CRITICAL; 78 return STATE_CRITICAL;
79 }
76 80
77 send_result = send (sd, send_buffer, strlen (send_buffer), 0); 81 send_result = send(sd, send_buffer, strlen(send_buffer), 0);
78 if (send_result<0 || (size_t)send_result!=strlen(send_buffer)) { 82 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) {
79 printf ("%s\n", _("Send failed")); 83 // printf("%s\n", _("Send failed"));
80 result = STATE_WARNING; 84 result = STATE_WARNING;
81 } 85 }
82 86
@@ -85,38 +89,32 @@ process_tcp_request2 (const char *server_address, int server_port,
85 minus one for data from the host */ 89 minus one for data from the host */
86 tv.tv_sec = socket_timeout - 1; 90 tv.tv_sec = socket_timeout - 1;
87 tv.tv_usec = 0; 91 tv.tv_usec = 0;
88 FD_ZERO (&readfds); 92 FD_ZERO(&readfds);
89 FD_SET (sd, &readfds); 93 FD_SET(sd, &readfds);
90 select (sd + 1, &readfds, NULL, NULL, &tv); 94 select(sd + 1, &readfds, NULL, NULL, &tv);
91 95
92 /* make sure some data has arrived */ 96 /* make sure some data has arrived */
93 if (!FD_ISSET (sd, &readfds)) { /* it hasn't */ 97 if (!FD_ISSET(sd, &readfds)) { /* it hasn't */
94 if (!recv_length) { 98 if (!recv_length) {
95 strcpy (recv_buffer, ""); 99 strcpy(recv_buffer, "");
96 printf ("%s\n", _("No data was received from host!")); 100 // printf("%s\n", _("No data was received from host!"));
97 result = STATE_WARNING; 101 result = STATE_WARNING;
98 } 102 } else { /* this one failed, but previous ones worked */
99 else { /* this one failed, but previous ones worked */
100 recv_buffer[recv_length] = 0; 103 recv_buffer[recv_length] = 0;
101 } 104 }
102 break; 105 break;
103 } 106 } else { /* it has */
104 else { /* it has */ 107 recv_result = recv(sd, recv_buffer + recv_length, (size_t)recv_size - recv_length - 1, 0);
105 recv_result =
106 recv (sd, recv_buffer + recv_length,
107 (size_t)recv_size - recv_length - 1, 0);
108 if (recv_result == -1) { 108 if (recv_result == -1) {
109 /* recv failed, bail out */ 109 /* recv failed, bail out */
110 strcpy (recv_buffer + recv_length, ""); 110 strcpy(recv_buffer + recv_length, "");
111 result = STATE_WARNING; 111 result = STATE_WARNING;
112 break; 112 break;
113 } 113 } else if (recv_result == 0) {
114 else if (recv_result == 0) {
115 /* end of file ? */ 114 /* end of file ? */
116 recv_buffer[recv_length] = 0; 115 recv_buffer[recv_length] = 0;
117 break; 116 break;
118 } 117 } else { /* we got data! */
119 else { /* we got data! */
120 recv_length += recv_result; 118 recv_length += recv_result;
121 if (recv_length >= recv_size - 1) { 119 if (recv_length >= recv_size - 1) {
122 /* buffer full, we're done */ 120 /* buffer full, we're done */
@@ -129,42 +127,36 @@ process_tcp_request2 (const char *server_address, int server_port,
129 } 127 }
130 /* end while(1) */ 128 /* end while(1) */
131 129
132 close (sd); 130 close(sd);
133 return result; 131 return result;
134} 132}
135 133
136
137/* connects to a host on a specified port, sends a string, and gets a 134/* connects to a host on a specified port, sends a string, and gets a
138 response */ 135 response */
139int 136int process_request(const char *server_address, int server_port, int proto, const char *send_buffer, char *recv_buffer, int recv_size) {
140process_request (const char *server_address, int server_port, int proto,
141 const char *send_buffer, char *recv_buffer, int recv_size)
142{
143 int result; 137 int result;
144 int sd; 138 int sd;
145 139
146 result = STATE_OK; 140 result = STATE_OK;
147 141
148 result = np_net_connect (server_address, server_port, &sd, proto); 142 result = np_net_connect(server_address, server_port, &sd, proto);
149 if (result != STATE_OK) 143 if (result != STATE_OK) {
150 return STATE_CRITICAL; 144 return STATE_CRITICAL;
145 }
151 146
152 result = send_request (sd, proto, send_buffer, recv_buffer, recv_size); 147 result = send_request(sd, proto, send_buffer, recv_buffer, recv_size);
153 148
154 close (sd); 149 close(sd);
155 150
156 return result; 151 return result;
157} 152}
158 153
159
160/* opens a tcp or udp connection to a remote host or local socket */ 154/* opens a tcp or udp connection to a remote host or local socket */
161int 155int np_net_connect(const char *host_name, int port, int *sd, int proto) {
162np_net_connect (const char *host_name, int port, int *sd, int proto) 156 /* send back STATE_UNKOWN if there's an error
163{ 157 send back STATE_OK if we connect
164 /* send back STATE_UNKOWN if there's an error 158 send back STATE_CRITICAL if we can't connect.
165 send back STATE_OK if we connect 159 Let upstream figure out what to send to the user. */
166 send back STATE_CRITICAL if we can't connect.
167 Let upstream figure out what to send to the user. */
168 struct addrinfo hints; 160 struct addrinfo hints;
169 struct addrinfo *r, *res; 161 struct addrinfo *r, *res;
170 struct sockaddr_un su; 162 struct sockaddr_un su;
@@ -176,43 +168,44 @@ np_net_connect (const char *host_name, int port, int *sd, int proto)
176 socktype = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM; 168 socktype = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
177 169
178 /* as long as it doesn't start with a '/', it's assumed a host or ip */ 170 /* as long as it doesn't start with a '/', it's assumed a host or ip */
179 if (!is_socket){ 171 if (!is_socket) {
180 memset (&hints, 0, sizeof (hints)); 172 memset(&hints, 0, sizeof(hints));
181 hints.ai_family = address_family; 173 hints.ai_family = address_family;
182 hints.ai_protocol = proto; 174 hints.ai_protocol = proto;
183 hints.ai_socktype = socktype; 175 hints.ai_socktype = socktype;
184 176
185 len = strlen (host_name); 177 len = strlen(host_name);
186 /* check for an [IPv6] address (and strip the brackets) */ 178 /* check for an [IPv6] address (and strip the brackets) */
187 if (len >= 2 && host_name[0] == '[' && host_name[len - 1] == ']') { 179 if (len >= 2 && host_name[0] == '[' && host_name[len - 1] == ']') {
188 host_name++; 180 host_name++;
189 len -= 2; 181 len -= 2;
190 } 182 }
191 if (len >= sizeof(host)) 183 if (len >= sizeof(host)) {
192 return STATE_UNKNOWN; 184 return STATE_UNKNOWN;
193 memcpy (host, host_name, len); 185 }
186 memcpy(host, host_name, len);
194 host[len] = '\0'; 187 host[len] = '\0';
195 snprintf (port_str, sizeof (port_str), "%d", port); 188 snprintf(port_str, sizeof(port_str), "%d", port);
196 result = getaddrinfo (host, port_str, &hints, &res); 189 result = getaddrinfo(host, port_str, &hints, &res);
197 190
198 if (result != 0) { 191 if (result != 0) {
199 printf ("%s\n", gai_strerror (result)); 192 // printf("%s\n", gai_strerror(result));
200 return STATE_UNKNOWN; 193 return STATE_UNKNOWN;
201 } 194 }
202 195
203 r = res; 196 r = res;
204 while (r) { 197 while (r) {
205 /* attempt to create a socket */ 198 /* attempt to create a socket */
206 *sd = socket (r->ai_family, socktype, r->ai_protocol); 199 *sd = socket(r->ai_family, socktype, r->ai_protocol);
207 200
208 if (*sd < 0) { 201 if (*sd < 0) {
209 printf ("%s\n", _("Socket creation failed")); 202 // printf("%s\n", _("Socket creation failed"));
210 freeaddrinfo (r); 203 freeaddrinfo(r);
211 return STATE_UNKNOWN; 204 return STATE_UNKNOWN;
212 } 205 }
213 206
214 /* attempt to open a connection */ 207 /* attempt to open a connection */
215 result = connect (*sd, r->ai_addr, r->ai_addrlen); 208 result = connect(*sd, r->ai_addr, r->ai_addrlen);
216 209
217 if (result == 0) { 210 if (result == 0) {
218 was_refused = false; 211 was_refused = false;
@@ -227,69 +220,67 @@ np_net_connect (const char *host_name, int port, int *sd, int proto)
227 } 220 }
228 } 221 }
229 222
230 close (*sd); 223 close(*sd);
231 r = r->ai_next; 224 r = r->ai_next;
232 } 225 }
233 freeaddrinfo (res); 226 freeaddrinfo(res);
234 } 227 }
235 /* else the hostname is interpreted as a path to a unix socket */ 228 /* else the hostname is interpreted as a path to a unix socket */
236 else { 229 else {
237 if(strlen(host_name) >= UNIX_PATH_MAX){ 230 if (strlen(host_name) >= UNIX_PATH_MAX) {
238 die(STATE_UNKNOWN, _("Supplied path too long unix domain socket")); 231 die(STATE_UNKNOWN, _("Supplied path too long unix domain socket"));
239 } 232 }
240 memset(&su, 0, sizeof(su)); 233 memset(&su, 0, sizeof(su));
241 su.sun_family = AF_UNIX; 234 su.sun_family = AF_UNIX;
242 strncpy(su.sun_path, host_name, UNIX_PATH_MAX); 235 strncpy(su.sun_path, host_name, UNIX_PATH_MAX);
243 *sd = socket(PF_UNIX, SOCK_STREAM, 0); 236 *sd = socket(PF_UNIX, SOCK_STREAM, 0);
244 if(*sd < 0){ 237 if (*sd < 0) {
245 die(STATE_UNKNOWN, _("Socket creation failed")); 238 die(STATE_UNKNOWN, _("Socket creation failed"));
246 } 239 }
247 result = connect(*sd, (struct sockaddr *)&su, sizeof(su)); 240 result = connect(*sd, (struct sockaddr *)&su, sizeof(su));
248 if (result < 0 && errno == ECONNREFUSED) 241 if (result < 0 && errno == ECONNREFUSED) {
249 was_refused = true; 242 was_refused = true;
243 }
250 } 244 }
251 245
252 if (result == 0) 246 if (result == 0) {
253 return STATE_OK; 247 return STATE_OK;
254 else if (was_refused) { 248 } else if (was_refused) {
255 switch (econn_refuse_state) { /* a user-defined expected outcome */ 249 switch (econn_refuse_state) { /* a user-defined expected outcome */
256 case STATE_OK: 250 case STATE_OK:
257 case STATE_WARNING: /* user wants WARN or OK on refusal, or... */ 251 case STATE_WARNING: /* user wants WARN or OK on refusal, or... */
258 case STATE_CRITICAL: /* user did not set econn_refuse_state, or wanted critical */ 252 case STATE_CRITICAL: /* user did not set econn_refuse_state, or wanted critical */
259 if (is_socket) 253 if (is_socket) {
260 printf("connect to file socket %s: %s\n", host_name, strerror(errno)); 254 // printf("connect to file socket %s: %s\n", host_name, strerror(errno));
261 else 255 } else {
262 printf("connect to address %s and port %d: %s\n", 256 // printf("connect to address %s and port %d: %s\n", host_name, port, strerror(errno));
263 host_name, port, strerror(errno)); 257 }
264 return STATE_CRITICAL; 258 return STATE_CRITICAL;
265 break; 259 break;
266 default: /* it's a logic error if we do not end up in STATE_(OK|WARNING|CRITICAL) */ 260 default: /* it's a logic error if we do not end up in STATE_(OK|WARNING|CRITICAL) */
267 return STATE_UNKNOWN; 261 return STATE_UNKNOWN;
268 break; 262 break;
269 } 263 }
270 } 264 } else {
271 else { 265 if (is_socket) {
272 if (is_socket) 266 // printf("connect to file socket %s: %s\n", host_name, strerror(errno));
273 printf("connect to file socket %s: %s\n", host_name, strerror(errno)); 267 } else {
274 else 268 // printf("connect to address %s and port %d: %s\n", host_name, port, strerror(errno));
275 printf("connect to address %s and port %d: %s\n", 269 }
276 host_name, port, strerror(errno));
277 return STATE_CRITICAL; 270 return STATE_CRITICAL;
278 } 271 }
279} 272}
280 273
281int 274int send_request(int sd, int proto, const char *send_buffer, char *recv_buffer, int recv_size) {
282send_request (int sd, int proto, const char *send_buffer, char *recv_buffer, int recv_size)
283{
284 int result = STATE_OK; 275 int result = STATE_OK;
285 int send_result; 276 int send_result;
286 int recv_result; 277 int recv_result;
287 struct timeval tv; 278 struct timeval tv;
288 fd_set readfds; 279 fd_set readfds;
289 280
290 send_result = send (sd, send_buffer, strlen (send_buffer), 0); 281 send_result = send(sd, send_buffer, strlen(send_buffer), 0);
291 if (send_result<0 || (size_t)send_result!=strlen(send_buffer)) { 282 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) {
292 printf ("%s\n", _("Send failed")); 283 // printf("%s\n", _("Send failed"));
293 result = STATE_WARNING; 284 result = STATE_WARNING;
294 } 285 }
295 286
@@ -297,27 +288,28 @@ send_request (int sd, int proto, const char *send_buffer, char *recv_buffer, int
297 for data from the host */ 288 for data from the host */
298 tv.tv_sec = socket_timeout - 1; 289 tv.tv_sec = socket_timeout - 1;
299 tv.tv_usec = 0; 290 tv.tv_usec = 0;
300 FD_ZERO (&readfds); 291 FD_ZERO(&readfds);
301 FD_SET (sd, &readfds); 292 FD_SET(sd, &readfds);
302 select (sd + 1, &readfds, NULL, NULL, &tv); 293 select(sd + 1, &readfds, NULL, NULL, &tv);
303 294
304 /* make sure some data has arrived */ 295 /* make sure some data has arrived */
305 if (!FD_ISSET (sd, &readfds)) { 296 if (!FD_ISSET(sd, &readfds)) {
306 strcpy (recv_buffer, ""); 297 strcpy(recv_buffer, "");
307 printf ("%s\n", _("No data was received from host!")); 298 // printf("%s\n", _("No data was received from host!"));
308 result = STATE_WARNING; 299 result = STATE_WARNING;
309 } 300 }
310 301
311 else { 302 else {
312 recv_result = recv (sd, recv_buffer, (size_t)recv_size - 1, 0); 303 recv_result = recv(sd, recv_buffer, (size_t)recv_size - 1, 0);
313 if (recv_result == -1) { 304 if (recv_result == -1) {
314 strcpy (recv_buffer, ""); 305 strcpy(recv_buffer, "");
315 if (proto != IPPROTO_TCP) 306 if (proto != IPPROTO_TCP) {
316 printf ("%s\n", _("Receive failed")); 307 // printf("%s\n", _("Receive failed"));
308 }
317 result = STATE_WARNING; 309 result = STATE_WARNING;
318 } 310 } else {
319 else
320 recv_buffer[recv_result] = 0; 311 recv_buffer[recv_result] = 0;
312 }
321 313
322 /* die returned string */ 314 /* die returned string */
323 recv_buffer[recv_size - 1] = 0; 315 recv_buffer[recv_size - 1] = 0;
@@ -325,51 +317,52 @@ send_request (int sd, int proto, const char *send_buffer, char *recv_buffer, int
325 return result; 317 return result;
326} 318}
327 319
328 320bool is_host(const char *address) {
329bool is_host (const char *address) { 321 if (is_addr(address) || is_hostname(address)) {
330 if (is_addr (address) || is_hostname (address))
331 return (true); 322 return (true);
323 }
332 324
333 return (false); 325 return (false);
334} 326}
335 327
336void 328void host_or_die(const char *str) {
337host_or_die(const char *str) 329 if (!str || (!is_addr(str) && !is_hostname(str))) {
338{
339 if(!str || (!is_addr(str) && !is_hostname(str)))
340 usage_va(_("Invalid hostname/address - %s"), str); 330 usage_va(_("Invalid hostname/address - %s"), str);
331 }
341} 332}
342 333
343bool is_addr (const char *address) { 334bool is_addr(const char *address) {
344#ifdef USE_IPV6 335#ifdef USE_IPV6
345 if (address_family == AF_INET && is_inet_addr (address)) 336 if (address_family == AF_INET && is_inet_addr(address)) {
346 return true; 337 return true;
347 else if (address_family == AF_INET6 && is_inet6_addr (address)) 338 } else if (address_family == AF_INET6 && is_inet6_addr(address)) {
348 return true; 339 return true;
340 }
349#else 341#else
350 if (is_inet_addr (address)) 342 if (is_inet_addr(address)) {
351 return (true); 343 return (true);
344 }
352#endif 345#endif
353 346
354 return (false); 347 return (false);
355} 348}
356 349
357int 350int dns_lookup(const char *in, struct sockaddr_storage *ss, int family) {
358dns_lookup (const char *in, struct sockaddr_storage *ss, int family)
359{
360 struct addrinfo hints; 351 struct addrinfo hints;
361 struct addrinfo *res; 352 struct addrinfo *res;
362 int retval; 353 int retval;
363 354
364 memset (&hints, 0, sizeof(struct addrinfo)); 355 memset(&hints, 0, sizeof(struct addrinfo));
365 hints.ai_family = family; 356 hints.ai_family = family;
366 357
367 retval = getaddrinfo (in, NULL, &hints, &res); 358 retval = getaddrinfo(in, NULL, &hints, &res);
368 if (retval != 0) 359 if (retval != 0) {
369 return false; 360 return false;
361 }
370 362
371 if (ss != NULL) 363 if (ss != NULL) {
372 memcpy (ss, res->ai_addr, res->ai_addrlen); 364 memcpy(ss, res->ai_addr, res->ai_addrlen);
373 freeaddrinfo (res); 365 }
366 freeaddrinfo(res);
374 return true; 367 return true;
375} 368}
diff --git a/plugins/picohttpparser/picohttpparser.c b/plugins/picohttpparser/picohttpparser.c
index d0bfac62..2ae92d66 100644
--- a/plugins/picohttpparser/picohttpparser.c
+++ b/plugins/picohttpparser/picohttpparser.c
@@ -28,623 +28,610 @@
28#include <stddef.h> 28#include <stddef.h>
29#include <string.h> 29#include <string.h>
30#ifdef __SSE4_2__ 30#ifdef __SSE4_2__
31#ifdef _MSC_VER 31# ifdef _MSC_VER
32#include <nmmintrin.h> 32# include <nmmintrin.h>
33#else 33# else
34#include <x86intrin.h> 34# include <x86intrin.h>
35#endif 35# endif
36#endif 36#endif
37#include "picohttpparser.h" 37#include "picohttpparser.h"
38 38
39#if __GNUC__ >= 3 39#if __GNUC__ >= 3
40#define likely(x) __builtin_expect(!!(x), 1) 40# define likely(x) __builtin_expect(!!(x), 1)
41#define unlikely(x) __builtin_expect(!!(x), 0) 41# define unlikely(x) __builtin_expect(!!(x), 0)
42#else 42#else
43#define likely(x) (x) 43# define likely(x) (x)
44#define unlikely(x) (x) 44# define unlikely(x) (x)
45#endif 45#endif
46 46
47#ifdef _MSC_VER 47#ifdef _MSC_VER
48#define ALIGNED(n) _declspec(align(n)) 48# define ALIGNED(n) _declspec(align(n))
49#else 49#else
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 = "\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"
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\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"
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\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"
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 "\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"
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 "\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" 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
105static const char *findchar_fast(const char *buf, const char *buf_end, const char *ranges, size_t ranges_size, int *found) 105static const char *findchar_fast(const char *buf, const char *buf_end, const char *ranges, size_t ranges_size, int *found) {
106{ 106 *found = 0;
107 *found = 0;
108#if __SSE4_2__ 107#if __SSE4_2__
109 if (likely(buf_end - buf >= 16)) { 108 if (likely(buf_end - buf >= 16)) {
110 __m128i ranges16 = _mm_loadu_si128((const __m128i *)ranges); 109 __m128i ranges16 = _mm_loadu_si128((const __m128i *)ranges);
111 110
112 size_t left = (buf_end - buf) & ~15; 111 size_t left = (buf_end - buf) & ~15;
113 do { 112 do {
114 __m128i b16 = _mm_loadu_si128((const __m128i *)buf); 113 __m128i b16 = _mm_loadu_si128((const __m128i *)buf);
115 int r = _mm_cmpestri(ranges16, ranges_size, b16, 16, _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS); 114 int r = _mm_cmpestri(ranges16, ranges_size, b16, 16, _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS);
116 if (unlikely(r != 16)) { 115 if (unlikely(r != 16)) {
117 buf += r; 116 buf += r;
118 *found = 1; 117 *found = 1;
119 break; 118 break;
120 } 119 }
121 buf += 16; 120 buf += 16;
122 left -= 16; 121 left -= 16;
123 } while (likely(left != 0)); 122 } while (likely(left != 0));
124 } 123 }
125#else 124#else
126 /* suppress unused parameter warning */ 125 /* suppress unused parameter warning */
127 (void)buf_end; 126 (void)buf_end;
128 (void)ranges; 127 (void)ranges;
129 (void)ranges_size; 128 (void)ranges_size;
130#endif 129#endif
131 return buf; 130 return buf;
132} 131}
133 132
134static const char *get_token_to_eol(const char *buf, const char *buf_end, const char **token, size_t *token_len, int *ret) 133static const char *get_token_to_eol(const char *buf, const char *buf_end, const char **token, size_t *token_len, int *ret) {
135{ 134 const char *token_start = buf;
136 const char *token_start = buf;
137 135
138#ifdef __SSE4_2__ 136#ifdef __SSE4_2__
139 static const char ALIGNED(16) ranges1[16] = "\0\010" /* allow HT */ 137 static const char ALIGNED(16) ranges1[16] = "\0\010" /* allow HT */
140 "\012\037" /* allow SP and up to but not including DEL */ 138 "\012\037" /* allow SP and up to but not including DEL */
141 "\177\177"; /* allow chars w. MSB set */ 139 "\177\177"; /* allow chars w. MSB set */
142 int found; 140 int found;
143 buf = findchar_fast(buf, buf_end, ranges1, 6, &found); 141 buf = findchar_fast(buf, buf_end, ranges1, 6, &found);
144 if (found) 142 if (found)
145 goto FOUND_CTL; 143 goto FOUND_CTL;
146#else 144#else
147 /* find non-printable char within the next 8 bytes, this is the hottest code; manually inlined */ 145 /* find non-printable char within the next 8 bytes, this is the hottest code; manually inlined */
148 while (likely(buf_end - buf >= 8)) { 146 while (likely(buf_end - buf >= 8)) {
149#define DOIT() \ 147# define DOIT() \
150 do { \ 148 do { \
151 if (unlikely(!IS_PRINTABLE_ASCII(*buf))) \ 149 if (unlikely(!IS_PRINTABLE_ASCII(*buf))) \
152 goto NonPrintable; \ 150 goto NonPrintable; \
153 ++buf; \ 151 ++buf; \
154 } while (0) 152 } while (0)
155 DOIT(); 153 DOIT();
156 DOIT(); 154 DOIT();
157 DOIT(); 155 DOIT();
158 DOIT(); 156 DOIT();
159 DOIT(); 157 DOIT();
160 DOIT(); 158 DOIT();
161 DOIT(); 159 DOIT();
162 DOIT(); 160 DOIT();
163#undef DOIT 161# undef DOIT
164 continue; 162 continue;
165 NonPrintable: 163 NonPrintable:
166 if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) { 164 if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) {
167 goto FOUND_CTL; 165 goto FOUND_CTL;
168 } 166 }
169 ++buf; 167 ++buf;
170 } 168 }
171#endif 169#endif
172 for (;; ++buf) { 170 for (;; ++buf) {
173 CHECK_EOF(); 171 CHECK_EOF();
174 if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { 172 if (unlikely(!IS_PRINTABLE_ASCII(*buf))) {
175 if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) { 173 if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) {
176 goto FOUND_CTL; 174 goto FOUND_CTL;
177 } 175 }
178 } 176 }
179 } 177 }
180FOUND_CTL: 178FOUND_CTL:
181 if (likely(*buf == '\015')) { 179 if (likely(*buf == '\015')) {
182 ++buf; 180 ++buf;
183 EXPECT_CHAR('\012'); 181 EXPECT_CHAR('\012');
184 *token_len = buf - 2 - token_start; 182 *token_len = buf - 2 - token_start;
185 } else if (*buf == '\012') { 183 } else if (*buf == '\012') {
186 *token_len = buf - token_start; 184 *token_len = buf - token_start;
187 ++buf; 185 ++buf;
188 } else { 186 } else {
189 *ret = -1; 187 *ret = -1;
190 return NULL; 188 return NULL;
191 } 189 }
192 *token = token_start; 190 *token = token_start;
193 191
194 return buf; 192 return buf;
195} 193}
196 194
197static const char *is_complete(const char *buf, const char *buf_end, size_t last_len, int *ret) 195static const char *is_complete(const char *buf, const char *buf_end, size_t last_len, int *ret) {
198{ 196 int ret_cnt = 0;
199 int ret_cnt = 0; 197 buf = last_len < 3 ? buf : buf + last_len - 3;
200 buf = last_len < 3 ? buf : buf + last_len - 3; 198
201 199 while (1) {
202 while (1) { 200 CHECK_EOF();
203 CHECK_EOF(); 201 if (*buf == '\015') {
204 if (*buf == '\015') { 202 ++buf;
205 ++buf; 203 CHECK_EOF();
206 CHECK_EOF(); 204 EXPECT_CHAR('\012');
207 EXPECT_CHAR('\012'); 205 ++ret_cnt;
208 ++ret_cnt; 206 } else if (*buf == '\012') {
209 } else if (*buf == '\012') { 207 ++buf;
210 ++buf; 208 ++ret_cnt;
211 ++ret_cnt; 209 } else {
212 } else { 210 ++buf;
213 ++buf; 211 ret_cnt = 0;
214 ret_cnt = 0; 212 }
215 } 213 if (ret_cnt == 2) {
216 if (ret_cnt == 2) { 214 return buf;
217 return buf; 215 }
218 } 216 }
219 } 217
220 218 *ret = -2;
221 *ret = -2; 219 return NULL;
222 return NULL;
223} 220}
224 221
225#define PARSE_INT(valp_, mul_) \ 222#define PARSE_INT(valp_, mul_) \
226 if (*buf < '0' || '9' < *buf) { \ 223 if (*buf < '0' || '9' < *buf) { \
227 buf++; \ 224 buf++; \
228 *ret = -1; \ 225 *ret = -1; \
229 return NULL; \ 226 return NULL; \
230 } \ 227 } \
231 *(valp_) = (mul_) * (*buf++ - '0'); 228 *(valp_) = (mul_) * (*buf++ - '0');
232 229
233#define PARSE_INT_3(valp_) \ 230#define PARSE_INT_3(valp_) \
234 do { \ 231 do { \
235 int res_ = 0; \ 232 int res_ = 0; \
236 PARSE_INT(&res_, 100) \ 233 PARSE_INT(&res_, 100) \
237 *valp_ = res_; \ 234 *valp_ = res_; \
238 PARSE_INT(&res_, 10) \ 235 PARSE_INT(&res_, 10) \
239 *valp_ += res_; \ 236 *valp_ += res_; \
240 PARSE_INT(&res_, 1) \ 237 PARSE_INT(&res_, 1) \
241 *valp_ += res_; \ 238 *valp_ += res_; \
242 } while (0) 239 } while (0)
243 240
244/* returned pointer is always within [buf, buf_end), or null */ 241/* returned pointer is always within [buf, buf_end), or null */
245static const char *parse_http_version(const char *buf, const char *buf_end, int *major_version, int *minor_version, int *ret) 242static const char *parse_http_version(const char *buf, const char *buf_end, int *major_version, int *minor_version, int *ret) {
246{ 243 /* we want at least [HTTP/1.<two chars>] to try to parse */
247 /* we want at least [HTTP/1.<two chars>] to try to parse */ 244 if (buf_end - buf < 9) {
248 if (buf_end - buf < 9) { 245 *ret = -2;
249 *ret = -2; 246 return NULL;
250 return NULL; 247 }
251 } 248 EXPECT_CHAR_NO_CHECK('H');
252 EXPECT_CHAR_NO_CHECK('H'); 249 EXPECT_CHAR_NO_CHECK('T');
253 EXPECT_CHAR_NO_CHECK('T'); 250 EXPECT_CHAR_NO_CHECK('T');
254 EXPECT_CHAR_NO_CHECK('T'); 251 EXPECT_CHAR_NO_CHECK('P');
255 EXPECT_CHAR_NO_CHECK('P'); 252 EXPECT_CHAR_NO_CHECK('/');
256 EXPECT_CHAR_NO_CHECK('/'); 253 PARSE_INT(major_version, 1);
257 PARSE_INT(major_version, 1); 254 if (*major_version == 1) {
258 if (*major_version == 1) { 255 EXPECT_CHAR_NO_CHECK('.');
259 EXPECT_CHAR_NO_CHECK('.'); 256 PARSE_INT(minor_version, 1);
260 PARSE_INT(minor_version, 1); 257 } else {
261 } else { 258 *minor_version = 0;
262 *minor_version = 0; 259 }
263 } 260 return buf;
264 return buf;
265} 261}
266 262
267static const char *parse_headers(const char *buf, const char *buf_end, struct phr_header *headers, size_t *num_headers, 263static const char *parse_headers(const char *buf, const char *buf_end, struct phr_header *headers, size_t *num_headers, size_t max_headers,
268 size_t max_headers, int *ret) 264 int *ret) {
269{ 265 for (;; ++*num_headers) {
270 for (;; ++*num_headers) { 266 CHECK_EOF();
271 CHECK_EOF(); 267 if (*buf == '\015') {
272 if (*buf == '\015') { 268 ++buf;
273 ++buf; 269 EXPECT_CHAR('\012');
274 EXPECT_CHAR('\012'); 270 break;
275 break; 271 } else if (*buf == '\012') {
276 } else if (*buf == '\012') { 272 ++buf;
277 ++buf; 273 break;
278 break; 274 }
279 } 275 if (*num_headers == max_headers) {
280 if (*num_headers == max_headers) { 276 *ret = -1;
281 *ret = -1; 277 return NULL;
282 return NULL; 278 }
283 } 279 if (!(*num_headers != 0 && (*buf == ' ' || *buf == '\t'))) {
284 if (!(*num_headers != 0 && (*buf == ' ' || *buf == '\t'))) { 280 /* parsing name, but do not discard SP before colon, see
285 /* parsing name, but do not discard SP before colon, see 281 * http://www.mozilla.org/security/announce/2006/mfsa2006-33.html */
286 * http://www.mozilla.org/security/announce/2006/mfsa2006-33.html */ 282 headers[*num_headers].name = buf;
287 headers[*num_headers].name = buf; 283 static const char ALIGNED(16) ranges1[] = "\x00 " /* control chars and up to SP */
288 static const char ALIGNED(16) ranges1[] = "\x00 " /* control chars and up to SP */ 284 "\"\"" /* 0x22 */
289 "\"\"" /* 0x22 */ 285 "()" /* 0x28,0x29 */
290 "()" /* 0x28,0x29 */ 286 ",," /* 0x2c */
291 ",," /* 0x2c */ 287 "//" /* 0x2f */
292 "//" /* 0x2f */ 288 ":@" /* 0x3a-0x40 */
293 ":@" /* 0x3a-0x40 */ 289 "[]" /* 0x5b-0x5d */
294 "[]" /* 0x5b-0x5d */ 290 "{\377"; /* 0x7b-0xff */
295 "{\377"; /* 0x7b-0xff */ 291 int found;
296 int found; 292 buf = findchar_fast(buf, buf_end, ranges1, sizeof(ranges1) - 1, &found);
297 buf = findchar_fast(buf, buf_end, ranges1, sizeof(ranges1) - 1, &found); 293 if (!found) {
298 if (!found) { 294 CHECK_EOF();
299 CHECK_EOF(); 295 }
300 } 296 while (1) {
301 while (1) { 297 if (*buf == ':') {
302 if (*buf == ':') { 298 break;
303 break; 299 } else if (!token_char_map[(unsigned char)*buf]) {
304 } else if (!token_char_map[(unsigned char)*buf]) { 300 *ret = -1;
305 *ret = -1; 301 return NULL;
306 return NULL; 302 }
307 } 303 ++buf;
308 ++buf; 304 CHECK_EOF();
309 CHECK_EOF(); 305 }
310 } 306 if ((headers[*num_headers].name_len = buf - headers[*num_headers].name) == 0) {
311 if ((headers[*num_headers].name_len = buf - headers[*num_headers].name) == 0) { 307 *ret = -1;
312 *ret = -1; 308 return NULL;
313 return NULL; 309 }
314 } 310 ++buf;
315 ++buf; 311 for (;; ++buf) {
316 for (;; ++buf) { 312 CHECK_EOF();
317 CHECK_EOF(); 313 if (!(*buf == ' ' || *buf == '\t')) {
318 if (!(*buf == ' ' || *buf == '\t')) { 314 break;
319 break; 315 }
320 } 316 }
321 } 317 } else {
322 } else { 318 headers[*num_headers].name = NULL;
323 headers[*num_headers].name = NULL; 319 headers[*num_headers].name_len = 0;
324 headers[*num_headers].name_len = 0; 320 }
325 } 321 const char *value;
326 const char *value; 322 size_t value_len;
327 size_t value_len; 323 if ((buf = get_token_to_eol(buf, buf_end, &value, &value_len, ret)) == NULL) {
328 if ((buf = get_token_to_eol(buf, buf_end, &value, &value_len, ret)) == NULL) { 324 return NULL;
329 return NULL; 325 }
330 } 326 /* remove trailing SPs and HTABs */
331 /* remove trailing SPs and HTABs */ 327 const char *value_end = value + value_len;
332 const char *value_end = value + value_len; 328 for (; value_end != value; --value_end) {
333 for (; value_end != value; --value_end) { 329 const char c = *(value_end - 1);
334 const char c = *(value_end - 1); 330 if (!(c == ' ' || c == '\t')) {
335 if (!(c == ' ' || c == '\t')) { 331 break;
336 break; 332 }
337 } 333 }
338 } 334 headers[*num_headers].value = value;
339 headers[*num_headers].value = value; 335 headers[*num_headers].value_len = value_end - value;
340 headers[*num_headers].value_len = value_end - value; 336 }
341 } 337 return buf;
342 return buf;
343} 338}
344 339
345static const char *parse_request(const char *buf, const char *buf_end, const char **method, size_t *method_len, const char **path, 340static const char *parse_request(const char *buf, const char *buf_end, const char **method, size_t *method_len, const char **path,
346 size_t *path_len, int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers, 341 size_t *path_len, int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers,
347 size_t max_headers, int *ret) 342 size_t max_headers, int *ret) {
348{ 343 /* skip first empty line (some clients add CRLF after POST content) */
349 /* skip first empty line (some clients add CRLF after POST content) */ 344 CHECK_EOF();
350 CHECK_EOF(); 345 if (*buf == '\015') {
351 if (*buf == '\015') { 346 ++buf;
352 ++buf; 347 EXPECT_CHAR('\012');
353 EXPECT_CHAR('\012'); 348 } else if (*buf == '\012') {
354 } else if (*buf == '\012') { 349 ++buf;
355 ++buf; 350 }
356 } 351
357 352 /* parse request line */
358 /* parse request line */ 353 ADVANCE_TOKEN(*method, *method_len);
359 ADVANCE_TOKEN(*method, *method_len); 354 do {
360 do { 355 ++buf;
361 ++buf; 356 } while (*buf == ' ');
362 } while (*buf == ' '); 357 ADVANCE_TOKEN(*path, *path_len);
363 ADVANCE_TOKEN(*path, *path_len); 358 do {
364 do { 359 ++buf;
365 ++buf; 360 } while (*buf == ' ');
366 } while (*buf == ' '); 361 if (*method_len == 0 || *path_len == 0) {
367 if (*method_len == 0 || *path_len == 0) { 362 *ret = -1;
368 *ret = -1; 363 return NULL;
369 return NULL; 364 }
370 } 365 if ((buf = parse_http_version(buf, buf_end, major_version, minor_version, ret)) == NULL) {
371 if ((buf = parse_http_version(buf, buf_end, major_version, minor_version, ret)) == NULL) { 366 return NULL;
372 return NULL; 367 }
373 } 368 if (*buf == '\015') {
374 if (*buf == '\015') { 369 ++buf;
375 ++buf; 370 EXPECT_CHAR('\012');
376 EXPECT_CHAR('\012'); 371 } else if (*buf == '\012') {
377 } else if (*buf == '\012') { 372 ++buf;
378 ++buf; 373 } else {
379 } else { 374 *ret = -1;
380 *ret = -1; 375 return NULL;
381 return NULL; 376 }
382 } 377
383 378 return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret);
384 return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret);
385} 379}
386 380
387int phr_parse_request(const char *buf_start, size_t len, const char **method, size_t *method_len, const char **path, 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,
388 size_t *path_len, int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len) 382 int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len) {
389{ 383 const char *buf = buf_start, *buf_end = buf_start + len;
390 const char *buf = buf_start, *buf_end = buf_start + len; 384 size_t max_headers = *num_headers;
391 size_t max_headers = *num_headers; 385 int r;
392 int r; 386
393 387 *method = NULL;
394 *method = NULL; 388 *method_len = 0;
395 *method_len = 0; 389 *path = NULL;
396 *path = NULL; 390 *path_len = 0;
397 *path_len = 0; 391 *major_version = -1;
398 *major_version = -1; 392 *minor_version = -1;
399 *minor_version = -1; 393 *num_headers = 0;
400 *num_headers = 0; 394
401 395 /* if last_len != 0, check if the request is complete (a fast countermeasure
402 /* if last_len != 0, check if the request is complete (a fast countermeasure 396 against slowloris */
403 against slowloris */ 397 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) {
404 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { 398 return r;
405 return r; 399 }
406 } 400
407 401 if ((buf = parse_request(buf, buf_end, method, method_len, path, path_len, major_version, minor_version, headers, num_headers,
408 if ((buf = parse_request(buf, buf_end, method, method_len, path, path_len, major_version, minor_version, headers, num_headers, max_headers, 402 max_headers, &r)) == NULL) {
409 &r)) == NULL) { 403 return r;
410 return r; 404 }
411 } 405
412 406 return (int)(buf - buf_start);
413 return (int)(buf - buf_start);
414} 407}
415 408
416static const char *parse_response(const char *buf, const char *buf_end, int *major_version, int *minor_version, int *status, const char **msg, 409static const char *parse_response(const char *buf, const char *buf_end, int *major_version, int *minor_version, int *status,
417 size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t max_headers, int *ret) 410 const char **msg, size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t max_headers,
418{ 411 int *ret) {
419 /* parse "HTTP/1.x" */ 412 /* parse "HTTP/1.x" */
420 if ((buf = parse_http_version(buf, buf_end, major_version, minor_version, ret)) == NULL) { 413 if ((buf = parse_http_version(buf, buf_end, major_version, minor_version, ret)) == NULL) {
421 return NULL; 414 return NULL;
422 } 415 }
423 /* skip space */ 416 /* skip space */
424 if (*buf != ' ') { 417 if (*buf != ' ') {
425 *ret = -1; 418 *ret = -1;
426 return NULL; 419 return NULL;
427 } 420 }
428 do { 421 do {
429 ++buf; 422 ++buf;
430 } while (*buf == ' '); 423 } while (*buf == ' ');
431 /* parse status code, we want at least [:digit:][:digit:][:digit:]<other char> to try to parse */ 424 /* parse status code, we want at least [:digit:][:digit:][:digit:]<other char> to try to parse */
432 if (buf_end - buf < 4) { 425 if (buf_end - buf < 4) {
433 *ret = -2; 426 *ret = -2;
434 return NULL; 427 return NULL;
435 } 428 }
436 PARSE_INT_3(status); 429 PARSE_INT_3(status);
437 430
438 /* get message including preceding space */ 431 /* get message including preceding space */
439 if ((buf = get_token_to_eol(buf, buf_end, msg, msg_len, ret)) == NULL) { 432 if ((buf = get_token_to_eol(buf, buf_end, msg, msg_len, ret)) == NULL) {
440 return NULL; 433 return NULL;
441 } 434 }
442 if (*msg_len == 0) { 435 if (*msg_len == 0) {
443 /* ok */ 436 /* ok */
444 } else if (**msg == ' ') { 437 } else if (**msg == ' ') {
445 /* remove preceding space */ 438 /* remove preceding space */
446 do { 439 do {
447 ++*msg; 440 ++*msg;
448 --*msg_len; 441 --*msg_len;
449 } while (**msg == ' '); 442 } while (**msg == ' ');
450 } else { 443 } else {
451 /* garbage found after status code */ 444 /* garbage found after status code */
452 *ret = -1; 445 *ret = -1;
453 return NULL; 446 return NULL;
454 } 447 }
455 448
456 return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret); 449 return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret);
457} 450}
458 451
459int phr_parse_response(const char *buf_start, size_t len, int *major_version, int *minor_version, int *status, const char **msg, size_t *msg_len, 452int phr_parse_response(const char *buf_start, size_t len, int *major_version, int *minor_version, int *status, const char **msg,
460 struct phr_header *headers, size_t *num_headers, size_t last_len) 453 size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t last_len) {
461{ 454 const char *buf = buf_start, *buf_end = buf + len;
462 const char *buf = buf_start, *buf_end = buf + len; 455 size_t max_headers = *num_headers;
463 size_t max_headers = *num_headers; 456 int r;
464 int r; 457
465 458 *major_version = -1;
466 *major_version = -1; 459 *minor_version = -1;
467 *minor_version = -1; 460 *status = 0;
468 *status = 0; 461 *msg = NULL;
469 *msg = NULL; 462 *msg_len = 0;
470 *msg_len = 0; 463 *num_headers = 0;
471 *num_headers = 0; 464
472 465 /* if last_len != 0, check if the response is complete (a fast countermeasure
473 /* if last_len != 0, check if the response is complete (a fast countermeasure 466 against slowloris */
474 against slowloris */ 467 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) {
475 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { 468 return r;
476 return r; 469 }
477 } 470
478 471 if ((buf = parse_response(buf, buf_end, major_version, minor_version, status, msg, msg_len, headers, num_headers, max_headers, &r)) ==
479 if ((buf = parse_response(buf, buf_end, major_version, minor_version, status, msg, msg_len, headers, num_headers, max_headers, &r)) == NULL) { 472 NULL) {
480 return r; 473 return r;
481 } 474 }
482 475
483 return (int)(buf - buf_start); 476 return (int)(buf - buf_start);
484} 477}
485 478
486int phr_parse_headers(const char *buf_start, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len) 479int phr_parse_headers(const char *buf_start, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len) {
487{ 480 const char *buf = buf_start, *buf_end = buf + len;
488 const char *buf = buf_start, *buf_end = buf + len; 481 size_t max_headers = *num_headers;
489 size_t max_headers = *num_headers; 482 int r;
490 int r;
491 483
492 *num_headers = 0; 484 *num_headers = 0;
493 485
494 /* if last_len != 0, check if the response is complete (a fast countermeasure 486 /* if last_len != 0, check if the response is complete (a fast countermeasure
495 against slowloris */ 487 against slowloris */
496 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { 488 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) {
497 return r; 489 return r;
498 } 490 }
499 491
500 if ((buf = parse_headers(buf, buf_end, headers, num_headers, max_headers, &r)) == NULL) { 492 if ((buf = parse_headers(buf, buf_end, headers, num_headers, max_headers, &r)) == NULL) {
501 return r; 493 return r;
502 } 494 }
503 495
504 return (int)(buf - buf_start); 496 return (int)(buf - buf_start);
505} 497}
506 498
507enum { 499enum {
508 CHUNKED_IN_CHUNK_SIZE, 500 CHUNKED_IN_CHUNK_SIZE,
509 CHUNKED_IN_CHUNK_EXT, 501 CHUNKED_IN_CHUNK_EXT,
510 CHUNKED_IN_CHUNK_DATA, 502 CHUNKED_IN_CHUNK_DATA,
511 CHUNKED_IN_CHUNK_CRLF, 503 CHUNKED_IN_CHUNK_CRLF,
512 CHUNKED_IN_TRAILERS_LINE_HEAD, 504 CHUNKED_IN_TRAILERS_LINE_HEAD,
513 CHUNKED_IN_TRAILERS_LINE_MIDDLE 505 CHUNKED_IN_TRAILERS_LINE_MIDDLE
514}; 506};
515 507
516static int decode_hex(int ch) 508static int decode_hex(int ch) {
517{ 509 if ('0' <= ch && ch <= '9') {
518 if ('0' <= ch && ch <= '9') { 510 return ch - '0';
519 return ch - '0'; 511 } else if ('A' <= ch && ch <= 'F') {
520 } else if ('A' <= ch && ch <= 'F') { 512 return ch - 'A' + 0xa;
521 return ch - 'A' + 0xa; 513 } else if ('a' <= ch && ch <= 'f') {
522 } else if ('a' <= ch && ch <= 'f') { 514 return ch - 'a' + 0xa;
523 return ch - 'a' + 0xa; 515 } else {
524 } else { 516 return -1;
525 return -1; 517 }
526 }
527} 518}
528 519
529ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *_bufsz) 520ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *_bufsz) {
530{ 521 size_t dst = 0, src = 0, bufsz = *_bufsz;
531 size_t dst = 0, src = 0, bufsz = *_bufsz; 522 ssize_t ret = -2; /* incomplete */
532 ssize_t ret = -2; /* incomplete */ 523
533 524 while (1) {
534 while (1) { 525 switch (decoder->_state) {
535 switch (decoder->_state) { 526 case CHUNKED_IN_CHUNK_SIZE:
536 case CHUNKED_IN_CHUNK_SIZE: 527 for (;; ++src) {
537 for (;; ++src) { 528 int v;
538 int v; 529 if (src == bufsz)
539 if (src == bufsz) 530 goto Exit;
540 goto Exit; 531 if ((v = decode_hex(buf[src])) == -1) {
541 if ((v = decode_hex(buf[src])) == -1) { 532 if (decoder->_hex_count == 0) {
542 if (decoder->_hex_count == 0) { 533 ret = -1;
543 ret = -1; 534 goto Exit;
544 goto Exit; 535 }
545 } 536 break;
546 break; 537 }
547 } 538 if (decoder->_hex_count == sizeof(size_t) * 2) {
548 if (decoder->_hex_count == sizeof(size_t) * 2) { 539 ret = -1;
549 ret = -1; 540 goto Exit;
550 goto Exit; 541 }
551 } 542 decoder->bytes_left_in_chunk = decoder->bytes_left_in_chunk * 16 + v;
552 decoder->bytes_left_in_chunk = decoder->bytes_left_in_chunk * 16 + v; 543 ++decoder->_hex_count;
553 ++decoder->_hex_count; 544 }
554 } 545 decoder->_hex_count = 0;
555 decoder->_hex_count = 0; 546 decoder->_state = CHUNKED_IN_CHUNK_EXT;
556 decoder->_state = CHUNKED_IN_CHUNK_EXT; 547 /* fallthru */
557 /* fallthru */ 548 case CHUNKED_IN_CHUNK_EXT:
558 case CHUNKED_IN_CHUNK_EXT: 549 /* RFC 7230 A.2 "Line folding in chunk extensions is disallowed" */
559 /* RFC 7230 A.2 "Line folding in chunk extensions is disallowed" */ 550 for (;; ++src) {
560 for (;; ++src) { 551 if (src == bufsz)
561 if (src == bufsz) 552 goto Exit;
562 goto Exit; 553 if (buf[src] == '\012')
563 if (buf[src] == '\012') 554 break;
564 break; 555 }
565 } 556 ++src;
566 ++src; 557 if (decoder->bytes_left_in_chunk == 0) {
567 if (decoder->bytes_left_in_chunk == 0) { 558 if (decoder->consume_trailer) {
568 if (decoder->consume_trailer) { 559 decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD;
569 decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD; 560 break;
570 break; 561 } else {
571 } else { 562 goto Complete;
572 goto Complete; 563 }
573 } 564 }
574 } 565 decoder->_state = CHUNKED_IN_CHUNK_DATA;
575 decoder->_state = CHUNKED_IN_CHUNK_DATA; 566 /* fallthru */
576 /* fallthru */ 567 case CHUNKED_IN_CHUNK_DATA: {
577 case CHUNKED_IN_CHUNK_DATA: { 568 size_t avail = bufsz - src;
578 size_t avail = bufsz - src; 569 if (avail < decoder->bytes_left_in_chunk) {
579 if (avail < decoder->bytes_left_in_chunk) { 570 if (dst != src)
580 if (dst != src) 571 memmove(buf + dst, buf + src, avail);
581 memmove(buf + dst, buf + src, avail); 572 src += avail;
582 src += avail; 573 dst += avail;
583 dst += avail; 574 decoder->bytes_left_in_chunk -= avail;
584 decoder->bytes_left_in_chunk -= avail; 575 goto Exit;
585 goto Exit; 576 }
586 } 577 if (dst != src)
587 if (dst != src) 578 memmove(buf + dst, buf + src, decoder->bytes_left_in_chunk);
588 memmove(buf + dst, buf + src, decoder->bytes_left_in_chunk); 579 src += decoder->bytes_left_in_chunk;
589 src += decoder->bytes_left_in_chunk; 580 dst += decoder->bytes_left_in_chunk;
590 dst += decoder->bytes_left_in_chunk; 581 decoder->bytes_left_in_chunk = 0;
591 decoder->bytes_left_in_chunk = 0; 582 decoder->_state = CHUNKED_IN_CHUNK_CRLF;
592 decoder->_state = CHUNKED_IN_CHUNK_CRLF; 583 }
593 } 584 /* fallthru */
594 /* fallthru */ 585 case CHUNKED_IN_CHUNK_CRLF:
595 case CHUNKED_IN_CHUNK_CRLF: 586 for (;; ++src) {
596 for (;; ++src) { 587 if (src == bufsz)
597 if (src == bufsz) 588 goto Exit;
598 goto Exit; 589 if (buf[src] != '\015')
599 if (buf[src] != '\015') 590 break;
600 break; 591 }
601 } 592 if (buf[src] != '\012') {
602 if (buf[src] != '\012') { 593 ret = -1;
603 ret = -1; 594 goto Exit;
604 goto Exit; 595 }
605 } 596 ++src;
606 ++src; 597 decoder->_state = CHUNKED_IN_CHUNK_SIZE;
607 decoder->_state = CHUNKED_IN_CHUNK_SIZE; 598 break;
608 break; 599 case CHUNKED_IN_TRAILERS_LINE_HEAD:
609 case CHUNKED_IN_TRAILERS_LINE_HEAD: 600 for (;; ++src) {
610 for (;; ++src) { 601 if (src == bufsz)
611 if (src == bufsz) 602 goto Exit;
612 goto Exit; 603 if (buf[src] != '\015')
613 if (buf[src] != '\015') 604 break;
614 break; 605 }
615 } 606 if (buf[src++] == '\012')
616 if (buf[src++] == '\012') 607 goto Complete;
617 goto Complete; 608 decoder->_state = CHUNKED_IN_TRAILERS_LINE_MIDDLE;
618 decoder->_state = CHUNKED_IN_TRAILERS_LINE_MIDDLE; 609 /* fallthru */
619 /* fallthru */ 610 case CHUNKED_IN_TRAILERS_LINE_MIDDLE:
620 case CHUNKED_IN_TRAILERS_LINE_MIDDLE: 611 for (;; ++src) {
621 for (;; ++src) { 612 if (src == bufsz)
622 if (src == bufsz) 613 goto Exit;
623 goto Exit; 614 if (buf[src] == '\012')
624 if (buf[src] == '\012') 615 break;
625 break; 616 }
626 } 617 ++src;
627 ++src; 618 decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD;
628 decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD; 619 break;
629 break; 620 default:
630 default: 621 assert(!"decoder is corrupt");
631 assert(!"decoder is corrupt"); 622 }
632 } 623 }
633 }
634 624
635Complete: 625Complete:
636 ret = bufsz - src; 626 ret = bufsz - src;
637Exit: 627Exit:
638 if (dst != src) 628 if (dst != src)
639 memmove(buf + dst, buf + src, bufsz - src); 629 memmove(buf + dst, buf + src, bufsz - src);
640 *_bufsz = dst; 630 *_bufsz = dst;
641 return ret; 631 return ret;
642} 632}
643 633
644int phr_decode_chunked_is_in_data(struct phr_chunked_decoder *decoder) 634int phr_decode_chunked_is_in_data(struct phr_chunked_decoder *decoder) { return decoder->_state == CHUNKED_IN_CHUNK_DATA; }
645{
646 return decoder->_state == CHUNKED_IN_CHUNK_DATA;
647}
648 635
649#undef CHECK_EOF 636#undef CHECK_EOF
650#undef EXPECT_CHAR 637#undef EXPECT_CHAR
diff --git a/plugins/popen.c b/plugins/popen.c
index 54e63bc5..cfe930b6 100644
--- a/plugins/popen.c
+++ b/plugins/popen.c
@@ -1,109 +1,97 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring Plugins popen 3 * Monitoring Plugins popen
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2005-2007 Monitoring Plugins Development Team 6 * Copyright (c) 2005-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* A safe alternative to popen 10 * A safe alternative to popen
11* 11 *
12* Provides spopen and spclose 12 * Provides spopen and spclose
13* 13 *
14* FILE * spopen(const char *); 14 * FILE * spopen(const char *);
15* int spclose(FILE *); 15 * int spclose(FILE *);
16* 16 *
17* Code taken with little modification from "Advanced Programming for the Unix 17 * Code taken with little modification from "Advanced Programming for the Unix
18* Environment" by W. Richard Stevens 18 * Environment" by W. Richard Stevens
19* 19 *
20* This is considered safe in that no shell is spawned, and the environment 20 * This is considered safe in that no shell is spawned, and the environment
21* and path passed to the exec'd program are essentially empty. (popen create 21 * and path passed to the exec'd program are essentially empty. (popen create
22* a shell and passes the environment to it). 22 * a shell and passes the environment to it).
23* 23 *
24* 24 *
25* This program is free software: you can redistribute it and/or modify 25 * This program is free software: you can redistribute it and/or modify
26* it under the terms of the GNU General Public License as published by 26 * it under the terms of the GNU General Public License as published by
27* the Free Software Foundation, either version 3 of the License, or 27 * the Free Software Foundation, either version 3 of the License, or
28* (at your option) any later version. 28 * (at your option) any later version.
29* 29 *
30* This program is distributed in the hope that it will be useful, 30 * This program is distributed in the hope that it will be useful,
31* but WITHOUT ANY WARRANTY; without even the implied warranty of 31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33* GNU General Public License for more details. 33 * GNU General Public License for more details.
34* 34 *
35* You should have received a copy of the GNU General Public License 35 * You should have received a copy of the GNU General Public License
36* along with this program. If not, see <http://www.gnu.org/licenses/>. 36 * along with this program. If not, see <http://www.gnu.org/licenses/>.
37* 37 *
38* 38 *
39*****************************************************************************/ 39 *****************************************************************************/
40 40
41#include "./common.h" 41#include "./common.h"
42#include "./utils.h" 42#include "./utils.h"
43#include "../lib/maxfd.h"
44 43
45/* extern so plugin has pid to kill exec'd process on timeouts */ 44/* extern so plugin has pid to kill exec'd process on timeouts */
46extern pid_t *childpid; 45extern pid_t *childpid;
47extern int *child_stderr_array; 46extern int *child_stderr_array;
48extern FILE *child_process; 47extern FILE *child_process;
49 48
50FILE *spopen (const char *); 49FILE *spopen(const char * /*cmdstring*/);
51int spclose (FILE *); 50int spclose(FILE * /*fp*/);
52#ifdef REDHAT_SPOPEN_ERROR 51#ifdef REDHAT_SPOPEN_ERROR
53void popen_sigchld_handler (int); 52void popen_sigchld_handler(int);
54#endif 53#endif
55void popen_timeout_alarm_handler (int); 54void popen_timeout_alarm_handler(int /*signo*/);
56 55
57#include <stdarg.h> /* ANSI C header file */ 56#include <stdarg.h> /* ANSI C header file */
58#include <fcntl.h> 57#include <fcntl.h>
59 58
60#include <limits.h> 59#include <limits.h>
61#include <sys/resource.h> 60#include <sys/resource.h>
62 61
63#ifdef HAVE_SYS_WAIT_H 62#ifdef HAVE_SYS_WAIT_H
64#include <sys/wait.h> 63# include <sys/wait.h>
65#endif 64#endif
66 65
67#ifndef WEXITSTATUS 66#ifndef WEXITSTATUS
68# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) 67# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
69#endif 68#endif
70 69
71#ifndef WIFEXITED 70#ifndef WIFEXITED
72# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) 71# define WIFEXITED(stat_val) (((stat_val)&255) == 0)
73#endif 72#endif
74 73
75/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */ 74/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */
76#if defined(SIG_IGN) && !defined(SIG_ERR) 75#if defined(SIG_IGN) && !defined(SIG_ERR)
77#define SIG_ERR ((Sigfunc *)-1) 76# define SIG_ERR ((Sigfunc *)-1)
78#endif 77#endif
79 78
80 79char *pname = NULL; /* caller can set this from argv[0] */
81char *pname = NULL; /* caller can set this from argv[0] */
82 80
83#ifdef REDHAT_SPOPEN_ERROR 81#ifdef REDHAT_SPOPEN_ERROR
84static volatile int childtermd = 0; 82static volatile int childtermd = 0;
85#endif 83#endif
86 84
87FILE * 85FILE *spopen(const char *cmdstring) {
88spopen (const char *cmdstring) 86#ifdef RLIMIT_CORE
89{
90 char *env[2];
91 char *cmd = NULL;
92 char **argv = NULL;
93 char *str, *tmp;
94 int argc;
95
96 int i = 0, pfd[2], pfderr[2];
97 pid_t pid;
98
99#ifdef RLIMIT_CORE
100 /* do not leave core files */ 87 /* do not leave core files */
101 struct rlimit limit; 88 struct rlimit limit;
102 getrlimit (RLIMIT_CORE, &limit); 89 getrlimit(RLIMIT_CORE, &limit);
103 limit.rlim_cur = 0; 90 limit.rlim_cur = 0;
104 setrlimit (RLIMIT_CORE, &limit); 91 setrlimit(RLIMIT_CORE, &limit);
105#endif 92#endif
106 93
94 char *env[2];
107 env[0] = strdup("LC_ALL=C"); 95 env[0] = strdup("LC_ALL=C");
108 env[1] = NULL; 96 env[1] = NULL;
109 97
@@ -111,184 +99,182 @@ spopen (const char *cmdstring)
111 if (cmdstring == NULL) 99 if (cmdstring == NULL)
112 return (NULL); 100 return (NULL);
113 101
102 char *cmd = NULL;
114 /* make copy of command string so strtok() doesn't silently modify it */ 103 /* make copy of command string so strtok() doesn't silently modify it */
115 /* (the calling program may want to access it later) */ 104 /* (the calling program may want to access it later) */
116 cmd = malloc (strlen (cmdstring) + 1); 105 cmd = malloc(strlen(cmdstring) + 1);
117 if (cmd == NULL) 106 if (cmd == NULL)
118 return NULL; 107 return NULL;
119 strcpy (cmd, cmdstring); 108 strcpy(cmd, cmdstring);
120 109
121 /* This is not a shell, so we don't handle "???" */ 110 /* This is not a shell, so we don't handle "???" */
122 if (strstr (cmdstring, "\"")) 111 if (strstr(cmdstring, "\""))
123 return NULL; 112 return NULL;
124 113
125 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */ 114 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */
126 if (strstr (cmdstring, " ' ") || strstr (cmdstring, "'''")) 115 if (strstr(cmdstring, " ' ") || strstr(cmdstring, "'''"))
127 return NULL; 116 return NULL;
128 117
118 int argc;
119 char **argv = NULL;
129 /* there cannot be more args than characters */ 120 /* there cannot be more args than characters */
130 argc = strlen (cmdstring) + 1; /* add 1 for NULL termination */ 121 argc = strlen(cmdstring) + 1; /* add 1 for NULL termination */
131 argv = malloc (sizeof(char*)*argc); 122 argv = malloc(sizeof(char *) * argc);
132 123
133 if (argv == NULL) { 124 if (argv == NULL) {
134 printf ("%s\n", _("Could not malloc argv array in popen()")); 125 printf("%s\n", _("Could not malloc argv array in popen()"));
135 return NULL; 126 return NULL;
136 } 127 }
137 128
129 int i = 0;
130 char *str;
138 /* loop to get arguments to command */ 131 /* loop to get arguments to command */
139 while (cmd) { 132 while (cmd) {
140 str = cmd; 133 str = cmd;
141 str += strspn (str, " \t\r\n"); /* trim any leading whitespace */ 134 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */
142 135
143 if (i >= argc - 2) { 136 if (i >= argc - 2) {
144 printf ("%s\n",_("CRITICAL - You need more args!!!")); 137 printf("%s\n", _("CRITICAL - You need more args!!!"));
145 return (NULL); 138 return (NULL);
146 } 139 }
147 140
148 if (strstr (str, "'") == str) { /* handle SIMPLE quoted strings */ 141 if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */
149 str++; 142 str++;
150 if (!strstr (str, "'")) 143 if (!strstr(str, "'"))
151 return NULL; /* balanced? */ 144 return NULL; /* balanced? */
152 cmd = 1 + strstr (str, "'"); 145 cmd = 1 + strstr(str, "'");
153 str[strcspn (str, "'")] = 0; 146 str[strcspn(str, "'")] = 0;
154 } 147 } else if (strcspn(str, "'") < strcspn(str, " \t\r\n")) {
155 else if (strcspn(str,"'") < strcspn (str, " \t\r\n")) { 148 /* handle --option='foo bar' strings */
156 /* handle --option='foo bar' strings */ 149 char *tmp = str + strcspn(str, "'") + 1;
157 tmp = str + strcspn(str, "'") + 1; 150 if (!strstr(tmp, "'"))
158 if (!strstr (tmp, "'")) 151 return NULL; /* balanced? */
159 return NULL; /* balanced? */ 152 tmp += strcspn(tmp, "'") + 1;
160 tmp += strcspn(tmp,"'") + 1;
161 *tmp = 0; 153 *tmp = 0;
162 cmd = tmp + 1; 154 cmd = tmp + 1;
163 } else { 155 } else {
164 if (strpbrk (str, " \t\r\n")) { 156 if (strpbrk(str, " \t\r\n")) {
165 cmd = 1 + strpbrk (str, " \t\r\n"); 157 cmd = 1 + strpbrk(str, " \t\r\n");
166 str[strcspn (str, " \t\r\n")] = 0; 158 str[strcspn(str, " \t\r\n")] = 0;
167 } 159 } else {
168 else {
169 cmd = NULL; 160 cmd = NULL;
170 } 161 }
171 } 162 }
172 163
173 if (cmd && strlen (cmd) == strspn (cmd, " \t\r\n")) 164 if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n"))
174 cmd = NULL; 165 cmd = NULL;
175 166
176 argv[i++] = str; 167 argv[i++] = str;
177
178 } 168 }
179 argv[i] = NULL; 169 argv[i] = NULL;
180 170
181 long maxfd = mp_open_max(); 171 long maxfd = mp_open_max();
182 172
183 if (childpid == NULL) { /* first time through */ 173 if (childpid == NULL) { /* first time through */
184 if ((childpid = calloc ((size_t)maxfd, sizeof (pid_t))) == NULL) 174 if ((childpid = calloc((size_t)maxfd, sizeof(pid_t))) == NULL)
185 return (NULL); 175 return (NULL);
186 } 176 }
187 177
188 if (child_stderr_array == NULL) { /* first time through */ 178 if (child_stderr_array == NULL) { /* first time through */
189 if ((child_stderr_array = calloc ((size_t)maxfd, sizeof (int))) == NULL) 179 if ((child_stderr_array = calloc((size_t)maxfd, sizeof(int))) == NULL)
190 return (NULL); 180 return (NULL);
191 } 181 }
192 182
193 if (pipe (pfd) < 0) 183 int pfd[2];
194 return (NULL); /* errno set by pipe() */ 184 if (pipe(pfd) < 0)
185 return (NULL); /* errno set by pipe() */
195 186
196 if (pipe (pfderr) < 0) 187 int pfderr[2];
197 return (NULL); /* errno set by pipe() */ 188 if (pipe(pfderr) < 0)
189 return (NULL); /* errno set by pipe() */
198 190
199#ifdef REDHAT_SPOPEN_ERROR 191#ifdef REDHAT_SPOPEN_ERROR
200 if (signal (SIGCHLD, popen_sigchld_handler) == SIG_ERR) { 192 if (signal(SIGCHLD, popen_sigchld_handler) == SIG_ERR) {
201 usage4 (_("Cannot catch SIGCHLD")); 193 usage4(_("Cannot catch SIGCHLD"));
202 } 194 }
203#endif 195#endif
204 196
205 if ((pid = fork ()) < 0) 197 pid_t pid;
206 return (NULL); /* errno set by fork() */ 198 if ((pid = fork()) < 0)
207 else if (pid == 0) { /* child */ 199 return (NULL); /* errno set by fork() */
208 close (pfd[0]); 200
201 if (pid == 0) { /* child */
202 close(pfd[0]);
209 if (pfd[1] != STDOUT_FILENO) { 203 if (pfd[1] != STDOUT_FILENO) {
210 dup2 (pfd[1], STDOUT_FILENO); 204 dup2(pfd[1], STDOUT_FILENO);
211 close (pfd[1]); 205 close(pfd[1]);
212 } 206 }
213 close (pfderr[0]); 207 close(pfderr[0]);
214 if (pfderr[1] != STDERR_FILENO) { 208 if (pfderr[1] != STDERR_FILENO) {
215 dup2 (pfderr[1], STDERR_FILENO); 209 dup2(pfderr[1], STDERR_FILENO);
216 close (pfderr[1]); 210 close(pfderr[1]);
217 } 211 }
218 /* close all descriptors in childpid[] */ 212 /* close all descriptors in childpid[] */
219 for (i = 0; i < maxfd; i++) 213 for (i = 0; i < maxfd; i++)
220 if (childpid[i] > 0) 214 if (childpid[i] > 0)
221 close (i); 215 close(i);
222 216
223 execve (argv[0], argv, env); 217 execve(argv[0], argv, env);
224 _exit (0); 218 _exit(0);
225 } 219 }
226 220
227 close (pfd[1]); /* parent */ 221 close(pfd[1]); /* parent */
228 if ((child_process = fdopen (pfd[0], "r")) == NULL) 222 if ((child_process = fdopen(pfd[0], "r")) == NULL)
229 return (NULL); 223 return (NULL);
230 close (pfderr[1]); 224 close(pfderr[1]);
231 225
232 childpid[fileno (child_process)] = pid; /* remember child pid for this fd */ 226 childpid[fileno(child_process)] = pid; /* remember child pid for this fd */
233 child_stderr_array[fileno (child_process)] = pfderr[0]; /* remember STDERR */ 227 child_stderr_array[fileno(child_process)] = pfderr[0]; /* remember STDERR */
234 return (child_process); 228 return (child_process);
235} 229}
236 230
237int 231int spclose(FILE *fp) {
238spclose (FILE * fp)
239{
240 int fd, status;
241 pid_t pid;
242
243 if (childpid == NULL) 232 if (childpid == NULL)
244 return (1); /* popen() has never been called */ 233 return (1); /* popen() has never been called */
245 234
246 fd = fileno (fp); 235 pid_t pid;
236 int fd = fileno(fp);
247 if ((pid = childpid[fd]) == 0) 237 if ((pid = childpid[fd]) == 0)
248 return (1); /* fp wasn't opened by popen() */ 238 return (1); /* fp wasn't opened by popen() */
249 239
250 childpid[fd] = 0; 240 childpid[fd] = 0;
251 if (fclose (fp) == EOF) 241 if (fclose(fp) == EOF)
252 return (1); 242 return (1);
253 243
254#ifdef REDHAT_SPOPEN_ERROR 244#ifdef REDHAT_SPOPEN_ERROR
255 while (!childtermd); /* wait until SIGCHLD */ 245 while (!childtermd)
246 ; /* wait until SIGCHLD */
256#endif 247#endif
257 248
258 while (waitpid (pid, &status, 0) < 0) 249 int status;
250 while (waitpid(pid, &status, 0) < 0)
259 if (errno != EINTR) 251 if (errno != EINTR)
260 return (1); /* error other than EINTR from waitpid() */ 252 return (1); /* error other than EINTR from waitpid() */
261 253
262 if (WIFEXITED (status)) 254 if (WIFEXITED(status))
263 return (WEXITSTATUS (status)); /* return child's termination status */ 255 return (WEXITSTATUS(status)); /* return child's termination status */
264 256
265 return (1); 257 return (1);
266} 258}
267 259
268#ifdef REDHAT_SPOPEN_ERROR 260#ifdef REDHAT_SPOPEN_ERROR
269void 261void popen_sigchld_handler(int signo) {
270popen_sigchld_handler (int signo)
271{
272 if (signo == SIGCHLD) 262 if (signo == SIGCHLD)
273 childtermd = 1; 263 childtermd = 1;
274} 264}
275#endif 265#endif
276 266
277void 267void popen_timeout_alarm_handler(int signo) {
278popen_timeout_alarm_handler (int signo)
279{
280 int fh;
281 if (signo == SIGALRM) { 268 if (signo == SIGALRM) {
282 if (child_process != NULL) { 269 if (child_process != NULL) {
283 fh=fileno (child_process); 270 int fh = fileno(child_process);
284 if(fh >= 0){ 271 if (fh >= 0) {
285 kill (childpid[fh], SIGKILL); 272 kill(childpid[fh], SIGKILL);
286 } 273 }
287 printf (_("CRITICAL - Plugin timed out after %d seconds\n"), 274 printf(_("CRITICAL - Plugin timed out after %d seconds\n"), timeout_interval);
288 timeout_interval);
289 } else { 275 } else {
290 printf ("%s\n", _("CRITICAL - popen timeout received, but no child process")); 276 printf("%s\n", _("CRITICAL - popen timeout received, but no child process"));
291 } 277 }
292 exit (STATE_CRITICAL); 278 exit(STATE_CRITICAL);
293 } 279 }
294} 280}
diff --git a/plugins/runcmd.c b/plugins/runcmd.c
index ed49bb99..4429ceb0 100644
--- a/plugins/runcmd.c
+++ b/plugins/runcmd.c
@@ -1,63 +1,64 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring run command utilities 3 * Monitoring run command utilities
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2005-2006 Monitoring Plugins Development Team 6 * Copyright (c) 2005-2024 Monitoring Plugins Development Team
7* 7 *
8* Description : 8 * Description :
9* 9 *
10* A simple interface to executing programs from other programs, using an 10 * A simple interface to executing programs from other programs, using an
11* optimized and safe popen()-like implementation. It is considered safe 11 * optimized and safe popen()-like implementation. It is considered safe
12* in that no shell needs to be spawned and the environment passed to the 12 * in that no shell needs to be spawned and the environment passed to the
13* execve()'d program is essentially empty. 13 * execve()'d program is essentially empty.
14* 14 *
15* The code in this file is a derivative of popen.c which in turn was taken 15 * The code in this file is a derivative of popen.c which in turn was taken
16* from "Advanced Programming for the Unix Environment" by W. Richard Stevens. 16 * from "Advanced Programming for the Unix Environment" by W. Richard Stevens.
17* 17 *
18* Care has been taken to make sure the functions are async-safe. The one 18 * Care has been taken to make sure the functions are async-safe. The one
19* function which isn't is np_runcmd_init() which it doesn't make sense to 19 * function which isn't is np_runcmd_init() which it doesn't make sense to
20* call twice anyway, so the api as a whole should be considered async-safe. 20 * call twice anyway, so the api as a whole should be considered async-safe.
21* 21 *
22* 22 *
23* This program is free software: you can redistribute it and/or modify 23 * This program is free software: you can redistribute it and/or modify
24* it under the terms of the GNU General Public License as published by 24 * it under the terms of the GNU General Public License as published by
25* the Free Software Foundation, either version 3 of the License, or 25 * the Free Software Foundation, either version 3 of the License, or
26* (at your option) any later version. 26 * (at your option) any later version.
27* 27 *
28* This program is distributed in the hope that it will be useful, 28 * This program is distributed in the hope that it will be useful,
29* but WITHOUT ANY WARRANTY; without even the implied warranty of 29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31* GNU General Public License for more details. 31 * GNU General Public License for more details.
32* 32 *
33* You should have received a copy of the GNU General Public License 33 * You should have received a copy of the GNU General Public License
34* along with this program. If not, see <http://www.gnu.org/licenses/>. 34 * along with this program. If not, see <http://www.gnu.org/licenses/>.
35* 35 *
36* 36 *
37*****************************************************************************/ 37 *****************************************************************************/
38 38
39#define NAGIOSPLUG_API_C 1 39#define NAGIOSPLUG_API_C 1
40 40
41/** includes **/ 41/** includes **/
42#include "runcmd.h" 42#include "runcmd.h"
43#include "../lib/monitoringplug.h"
43#ifdef HAVE_SYS_WAIT_H 44#ifdef HAVE_SYS_WAIT_H
44# include <sys/wait.h> 45# include <sys/wait.h>
45#endif 46#endif
46 47
47#include "./utils.h" 48#include "./utils.h"
48 49
49/** macros **/ 50/** macros **/
50#ifndef WEXITSTATUS 51#ifndef WEXITSTATUS
51# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) 52# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
52#endif 53#endif
53 54
54#ifndef WIFEXITED 55#ifndef WIFEXITED
55# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) 56# define WIFEXITED(stat_val) (((stat_val)&255) == 0)
56#endif 57#endif
57 58
58/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */ 59/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */
59#if defined(SIG_IGN) && !defined(SIG_ERR) 60#if defined(SIG_IGN) && !defined(SIG_ERR)
60# define SIG_ERR ((Sigfunc *)-1) 61# define SIG_ERR ((Sigfunc *)-1)
61#endif 62#endif
62 63
63#include "../lib/maxfd.h" 64#include "../lib/maxfd.h"
@@ -72,33 +73,26 @@
72static pid_t *np_pids = NULL; 73static pid_t *np_pids = NULL;
73 74
74/** prototypes **/ 75/** prototypes **/
75static int np_runcmd_open(const char *, int *, int *) 76static int np_runcmd_open(const char *, int *, int *) __attribute__((__nonnull__(1, 2, 3)));
76 __attribute__((__nonnull__(1, 2, 3)));
77 77
78static int np_fetch_output(int, output *, int) 78static int np_fetch_output(int, output *, int) __attribute__((__nonnull__(2)));
79 __attribute__((__nonnull__(2)));
80 79
81static int np_runcmd_close(int); 80static int np_runcmd_close(int);
82 81
83/* prototype imported from utils.h */ 82/* prototype imported from utils.h */
84extern void die (int, const char *, ...) 83extern void die(int, const char *, ...) __attribute__((__noreturn__, __format__(__printf__, 2, 3)));
85 __attribute__((__noreturn__,__format__(__printf__, 2, 3)));
86
87 84
88/* this function is NOT async-safe. It is exported so multithreaded 85/* this function is NOT async-safe. It is exported so multithreaded
89 * plugins (or other apps) can call it prior to running any commands 86 * plugins (or other apps) can call it prior to running any commands
90 * through this api and thus achieve async-safeness throughout the api */ 87 * through this api and thus achieve async-safeness throughout the api */
91void np_runcmd_init(void) 88void np_runcmd_init(void) {
92{ 89 long maxfd = mp_open_max();
93 long maxfd = mp_open_max(); 90 if (!np_pids)
94 if(!np_pids) np_pids = calloc(maxfd, sizeof(pid_t)); 91 np_pids = calloc(maxfd, sizeof(pid_t));
95} 92}
96 93
97
98/* Start running a command */ 94/* Start running a command */
99static int 95static int np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr) {
100np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr)
101{
102 char *env[2]; 96 char *env[2];
103 char *cmd = NULL; 97 char *cmd = NULL;
104 char **argv = NULL; 98 char **argv = NULL;
@@ -112,7 +106,8 @@ np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr)
112 106
113 int i = 0; 107 int i = 0;
114 108
115 if(!np_pids) NP_RUNCMD_INIT; 109 if (!np_pids)
110 NP_RUNCMD_INIT;
116 111
117 env[0] = strdup("LC_ALL=C"); 112 env[0] = strdup("LC_ALL=C");
118 env[1] = NULL; 113 env[1] = NULL;
@@ -120,49 +115,50 @@ np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr)
120 /* make copy of command string so strtok() doesn't silently modify it */ 115 /* make copy of command string so strtok() doesn't silently modify it */
121 /* (the calling program may want to access it later) */ 116 /* (the calling program may want to access it later) */
122 cmdlen = strlen(cmdstring); 117 cmdlen = strlen(cmdstring);
123 if((cmd = malloc(cmdlen + 1)) == NULL) return -1; 118 if ((cmd = malloc(cmdlen + 1)) == NULL)
119 return -1;
124 memcpy(cmd, cmdstring, cmdlen); 120 memcpy(cmd, cmdstring, cmdlen);
125 cmd[cmdlen] = '\0'; 121 cmd[cmdlen] = '\0';
126 122
127 /* This is not a shell, so we don't handle "???" */ 123 /* This is not a shell, so we don't handle "???" */
128 if (strstr (cmdstring, "\"")) return -1; 124 if (strstr(cmdstring, "\""))
125 return -1;
129 126
130 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */ 127 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */
131 if (strstr (cmdstring, " ' ") || strstr (cmdstring, "'''")) 128 if (strstr(cmdstring, " ' ") || strstr(cmdstring, "'''"))
132 return -1; 129 return -1;
133 130
134 /* each arg must be whitespace-separated, so args can be a maximum 131 /* each arg must be whitespace-separated, so args can be a maximum
135 * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */ 132 * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */
136 argc = (cmdlen >> 1) + 2; 133 argc = (cmdlen >> 1) + 2;
137 argv = calloc(sizeof(char *), argc); 134 argv = calloc(argc, sizeof(char *));
138 135
139 if (argv == NULL) { 136 if (argv == NULL) {
140 printf ("%s\n", _("Could not malloc argv array in popen()")); 137 printf("%s\n", _("Could not malloc argv array in popen()"));
141 return -1; 138 return -1;
142 } 139 }
143 140
144 /* get command arguments (stupidly, but fairly quickly) */ 141 /* get command arguments (stupidly, but fairly quickly) */
145 while (cmd) { 142 while (cmd) {
146 str = cmd; 143 str = cmd;
147 str += strspn (str, " \t\r\n"); /* trim any leading whitespace */ 144 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */
148 145
149 if (strstr (str, "'") == str) { /* handle SIMPLE quoted strings */ 146 if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */
150 str++; 147 str++;
151 if (!strstr (str, "'")) return -1; /* balanced? */ 148 if (!strstr(str, "'"))
152 cmd = 1 + strstr (str, "'"); 149 return -1; /* balanced? */
153 str[strcspn (str, "'")] = 0; 150 cmd = 1 + strstr(str, "'");
154 } 151 str[strcspn(str, "'")] = 0;
155 else { 152 } else {
156 if (strpbrk (str, " \t\r\n")) { 153 if (strpbrk(str, " \t\r\n")) {
157 cmd = 1 + strpbrk (str, " \t\r\n"); 154 cmd = 1 + strpbrk(str, " \t\r\n");
158 str[strcspn (str, " \t\r\n")] = 0; 155 str[strcspn(str, " \t\r\n")] = 0;
159 } 156 } else {
160 else {
161 cmd = NULL; 157 cmd = NULL;
162 } 158 }
163 } 159 }
164 160
165 if (cmd && strlen (cmd) == strspn (cmd, " \t\r\n")) 161 if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n"))
166 cmd = NULL; 162 cmd = NULL;
167 163
168 argv[i++] = str; 164 argv[i++] = str;
@@ -173,33 +169,33 @@ np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr)
173 169
174 /* child runs exceve() and _exit. */ 170 /* child runs exceve() and _exit. */
175 if (pid == 0) { 171 if (pid == 0) {
176#ifdef RLIMIT_CORE 172#ifdef RLIMIT_CORE
177 /* the program we execve shouldn't leave core files */ 173 /* the program we execve shouldn't leave core files */
178 getrlimit (RLIMIT_CORE, &limit); 174 getrlimit(RLIMIT_CORE, &limit);
179 limit.rlim_cur = 0; 175 limit.rlim_cur = 0;
180 setrlimit (RLIMIT_CORE, &limit); 176 setrlimit(RLIMIT_CORE, &limit);
181#endif 177#endif
182 close (pfd[0]); 178 close(pfd[0]);
183 if (pfd[1] != STDOUT_FILENO) { 179 if (pfd[1] != STDOUT_FILENO) {
184 dup2 (pfd[1], STDOUT_FILENO); 180 dup2(pfd[1], STDOUT_FILENO);
185 close (pfd[1]); 181 close(pfd[1]);
186 } 182 }
187 close (pfderr[0]); 183 close(pfderr[0]);
188 if (pfderr[1] != STDERR_FILENO) { 184 if (pfderr[1] != STDERR_FILENO) {
189 dup2 (pfderr[1], STDERR_FILENO); 185 dup2(pfderr[1], STDERR_FILENO);
190 close (pfderr[1]); 186 close(pfderr[1]);
191 } 187 }
192 188
193 /* close all descriptors in np_pids[] 189 /* close all descriptors in np_pids[]
194 * This is executed in a separate address space (pure child), 190 * This is executed in a separate address space (pure child),
195 * so we don't have to worry about async safety */ 191 * so we don't have to worry about async safety */
196 long maxfd = mp_open_max(); 192 long maxfd = mp_open_max();
197 for (i = 0; i < maxfd; i++) 193 for (i = 0; i < maxfd; i++)
198 if(np_pids[i] > 0) 194 if (np_pids[i] > 0)
199 close (i); 195 close(i);
200 196
201 execve (argv[0], argv, env); 197 execve(argv[0], argv, env);
202 _exit (STATE_UNKNOWN); 198 _exit(STATE_UNKNOWN);
203 } 199 }
204 200
205 /* parent picks up execution here */ 201 /* parent picks up execution here */
@@ -213,49 +209,44 @@ np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr)
213 return pfd[0]; 209 return pfd[0];
214} 210}
215 211
216 212static int np_runcmd_close(int fd) {
217static int
218np_runcmd_close(int fd)
219{
220 int status; 213 int status;
221 pid_t pid; 214 pid_t pid;
222 215
223 /* make sure this fd was opened by popen() */ 216 /* make sure this fd was opened by popen() */
224 long maxfd = mp_open_max(); 217 long maxfd = mp_open_max();
225 if(fd < 0 || fd > maxfd || !np_pids || (pid = np_pids[fd]) == 0) 218 if (fd < 0 || fd > maxfd || !np_pids || (pid = np_pids[fd]) == 0)
226 return -1; 219 return -1;
227 220
228 np_pids[fd] = 0; 221 np_pids[fd] = 0;
229 if (close (fd) == -1) return -1; 222 if (close(fd) == -1)
223 return -1;
230 224
231 /* EINTR is ok (sort of), everything else is bad */ 225 /* EINTR is ok (sort of), everything else is bad */
232 while (waitpid (pid, &status, 0) < 0) 226 while (waitpid(pid, &status, 0) < 0)
233 if (errno != EINTR) return -1; 227 if (errno != EINTR)
228 return -1;
234 229
235 /* return child's termination status */ 230 /* return child's termination status */
236 return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1; 231 return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1;
237} 232}
238 233
239 234void runcmd_timeout_alarm_handler(int signo) {
240void
241runcmd_timeout_alarm_handler (int signo)
242{
243 235
244 if (signo == SIGALRM) 236 if (signo == SIGALRM)
245 puts(_("CRITICAL - Plugin timed out while executing system call")); 237 puts(_("CRITICAL - Plugin timed out while executing system call"));
246 238
247 long maxfd = mp_open_max(); 239 long maxfd = mp_open_max();
248 if(np_pids) for(long int i = 0; i < maxfd; i++) { 240 if (np_pids)
249 if(np_pids[i] != 0) kill(np_pids[i], SIGKILL); 241 for (long int i = 0; i < maxfd; i++) {
250 } 242 if (np_pids[i] != 0)
243 kill(np_pids[i], SIGKILL);
244 }
251 245
252 exit (STATE_CRITICAL); 246 exit(STATE_CRITICAL);
253} 247}
254 248
255 249static int np_fetch_output(int fd, output *op, int flags) {
256static int
257np_fetch_output(int fd, output *op, int flags)
258{
259 size_t len = 0, i = 0, lineno = 0; 250 size_t len = 0, i = 0, lineno = 0;
260 size_t rsf = 6, ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */ 251 size_t rsf = 6, ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */
261 char *buf = NULL; 252 char *buf = NULL;
@@ -264,7 +255,7 @@ np_fetch_output(int fd, output *op, int flags)
264 255
265 op->buf = NULL; 256 op->buf = NULL;
266 op->buflen = 0; 257 op->buflen = 0;
267 while((ret = read(fd, tmpbuf, sizeof(tmpbuf))) > 0) { 258 while ((ret = read(fd, tmpbuf, sizeof(tmpbuf))) > 0) {
268 len = (size_t)ret; 259 len = (size_t)ret;
269 op->buf = realloc(op->buf, op->buflen + len + 1); 260 op->buf = realloc(op->buf, op->buflen + len + 1);
270 memcpy(op->buf + op->buflen, tmpbuf, len); 261 memcpy(op->buf + op->buflen, tmpbuf, len);
@@ -272,33 +263,33 @@ np_fetch_output(int fd, output *op, int flags)
272 i++; 263 i++;
273 } 264 }
274 265
275 if(ret < 0) { 266 if (ret < 0) {
276 printf("read() returned %d: %s\n", ret, strerror(errno)); 267 printf("read() returned %d: %s\n", ret, strerror(errno));
277 return ret; 268 return ret;
278 } 269 }
279 270
280 /* some plugins may want to keep output unbroken, and some commands 271 /* some plugins may want to keep output unbroken, and some commands
281 * will yield no output, so return here for those */ 272 * will yield no output, so return here for those */
282 if(flags & RUNCMD_NO_ARRAYS || !op->buf || !op->buflen) 273 if (flags & RUNCMD_NO_ARRAYS || !op->buf || !op->buflen)
283 return op->buflen; 274 return op->buflen;
284 275
285 /* and some may want both */ 276 /* and some may want both */
286 if(flags & RUNCMD_NO_ASSOC) { 277 if (flags & RUNCMD_NO_ASSOC) {
287 buf = malloc(op->buflen); 278 buf = malloc(op->buflen);
288 memcpy(buf, op->buf, op->buflen); 279 memcpy(buf, op->buf, op->buflen);
289 } 280 } else
290 else buf = op->buf; 281 buf = op->buf;
291 282
292 op->line = NULL; 283 op->line = NULL;
293 op->lens = NULL; 284 op->lens = NULL;
294 i = 0; 285 i = 0;
295 while(i < op->buflen) { 286 while (i < op->buflen) {
296 /* make sure we have enough memory */ 287 /* make sure we have enough memory */
297 if(lineno >= ary_size) { 288 if (lineno >= ary_size) {
298 /* ary_size must never be zero */ 289 /* ary_size must never be zero */
299 do { 290 do {
300 ary_size = op->buflen >> --rsf; 291 ary_size = op->buflen >> --rsf;
301 } while(!ary_size); 292 } while (!ary_size);
302 293
303 op->line = realloc(op->line, ary_size * sizeof(char *)); 294 op->line = realloc(op->line, ary_size * sizeof(char *));
304 op->lens = realloc(op->lens, ary_size * sizeof(size_t)); 295 op->lens = realloc(op->lens, ary_size * sizeof(size_t));
@@ -308,7 +299,8 @@ np_fetch_output(int fd, output *op, int flags)
308 op->line[lineno] = &buf[i]; 299 op->line[lineno] = &buf[i];
309 300
310 /* hop to next newline or end of buffer */ 301 /* hop to next newline or end of buffer */
311 while(buf[i] != '\n' && i < op->buflen) i++; 302 while (buf[i] != '\n' && i < op->buflen)
303 i++;
312 buf[i] = '\0'; 304 buf[i] = '\0';
313 305
314 /* calculate the string length using pointer difference */ 306 /* calculate the string length using pointer difference */
@@ -321,21 +313,22 @@ np_fetch_output(int fd, output *op, int flags)
321 return lineno; 313 return lineno;
322} 314}
323 315
324 316int np_runcmd(const char *cmd, output *out, output *err, int flags) {
325int
326np_runcmd(const char *cmd, output *out, output *err, int flags)
327{
328 int fd, pfd_out[2], pfd_err[2]; 317 int fd, pfd_out[2], pfd_err[2];
329 318
330 /* initialize the structs */ 319 /* initialize the structs */
331 if(out) memset(out, 0, sizeof(output)); 320 if (out)
332 if(err) memset(err, 0, sizeof(output)); 321 memset(out, 0, sizeof(output));
333 322 if (err)
334 if((fd = np_runcmd_open(cmd, pfd_out, pfd_err)) == -1) 323 memset(err, 0, sizeof(output));
335 die (STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd); 324
336 325 if ((fd = np_runcmd_open(cmd, pfd_out, pfd_err)) == -1)
337 if(out) out->lines = np_fetch_output(pfd_out[0], out, flags); 326 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd);
338 if(err) err->lines = np_fetch_output(pfd_err[0], err, flags); 327
328 if (out)
329 out->lines = np_fetch_output(pfd_out[0], out, flags);
330 if (err)
331 err->lines = np_fetch_output(pfd_err[0], err, flags);
339 332
340 return np_runcmd_close(fd); 333 return np_runcmd_close(fd);
341} 334}
diff --git a/plugins/sslutils.c b/plugins/sslutils.c
index 6bc0ba81..96740b3a 100644
--- a/plugins/sslutils.c
+++ b/plugins/sslutils.c
@@ -1,46 +1,43 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring Plugins SSL utilities 3 * Monitoring Plugins SSL utilities
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2005-2010 Monitoring Plugins Development Team 6 * Copyright (c) 2005-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains common functions for plugins that require SSL. 10 * This file contains common functions for plugins that require SSL.
11* 11 *
12* 12 *
13* This program is free software: you can redistribute it and/or modify 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 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 15 * the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16 * (at your option) any later version.
17* 17 *
18* This program is distributed in the hope that it will be useful, 18 * This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21 * GNU General Public License for more details.
22* 22 *
23* You should have received a copy of the GNU General Public License 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/>. 24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25 *
26* 26 *
27*****************************************************************************/ 27 *****************************************************************************/
28 28
29#define MAX_CN_LENGTH 256 29#define MAX_CN_LENGTH 256
30#include "common.h" 30#include "common.h"
31#include "netutils.h" 31#include "netutils.h"
32#include "../lib/monitoringplug.h"
32 33
33#ifdef HAVE_SSL 34#ifdef HAVE_SSL
34static SSL_CTX *ctx=NULL; 35static SSL_CTX *ctx = NULL;
35static SSL *s=NULL; 36static SSL *s = NULL;
36 37
37int np_net_ssl_init(int sd) { 38int np_net_ssl_init(int sd) { return np_net_ssl_init_with_hostname(sd, NULL); }
38 return np_net_ssl_init_with_hostname(sd, NULL);
39}
40 39
41int np_net_ssl_init_with_hostname(int sd, char *host_name) { 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); }
42 return np_net_ssl_init_with_hostname_and_version(sd, host_name, 0);
43}
44 41
45int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int version) { 42int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int version) {
46 return np_net_ssl_init_with_hostname_version_and_cert(sd, host_name, version, NULL, NULL); 43 return np_net_ssl_init_with_hostname_version_and_cert(sd, host_name, version, NULL, NULL);
@@ -59,145 +56,141 @@ int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int
59 printf("%s\n", _("UNKNOWN - SSL protocol version 2 is not supported by your SSL library.")); 56 printf("%s\n", _("UNKNOWN - SSL protocol version 2 is not supported by your SSL library."));
60 return STATE_UNKNOWN; 57 return STATE_UNKNOWN;
61 case MP_SSLv3: /* SSLv3 protocol */ 58 case MP_SSLv3: /* SSLv3 protocol */
62#if defined(OPENSSL_NO_SSL3) 59# if defined(OPENSSL_NO_SSL3)
63 printf("%s\n", _("UNKNOWN - SSL protocol version 3 is not supported by your SSL library.")); 60 printf("%s\n", _("UNKNOWN - SSL protocol version 3 is not supported by your SSL library."));
64 return STATE_UNKNOWN; 61 return STATE_UNKNOWN;
65#else 62# else
66 SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION); 63 SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION);
67 SSL_CTX_set_max_proto_version(ctx, SSL3_VERSION); 64 SSL_CTX_set_max_proto_version(ctx, SSL3_VERSION);
68 break; 65 break;
69#endif 66# endif
70 case MP_TLSv1: /* TLSv1 protocol */ 67 case MP_TLSv1: /* TLSv1 protocol */
71#if defined(OPENSSL_NO_TLS1) 68# if defined(OPENSSL_NO_TLS1)
72 printf("%s\n", _("UNKNOWN - TLS protocol version 1 is not supported by your SSL library.")); 69 printf("%s\n", _("UNKNOWN - TLS protocol version 1 is not supported by your SSL library."));
73 return STATE_UNKNOWN; 70 return STATE_UNKNOWN;
74#else 71# else
75 SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION); 72 SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION);
76 SSL_CTX_set_max_proto_version(ctx, TLS1_VERSION); 73 SSL_CTX_set_max_proto_version(ctx, TLS1_VERSION);
77 break; 74 break;
78#endif 75# endif
79 case MP_TLSv1_1: /* TLSv1.1 protocol */ 76 case MP_TLSv1_1: /* TLSv1.1 protocol */
80#if !defined(SSL_OP_NO_TLSv1_1) 77# if !defined(SSL_OP_NO_TLSv1_1)
81 printf("%s\n", _("UNKNOWN - TLS protocol version 1.1 is not supported by your SSL library.")); 78 printf("%s\n", _("UNKNOWN - TLS protocol version 1.1 is not supported by your SSL library."));
82 return STATE_UNKNOWN; 79 return STATE_UNKNOWN;
83#else 80# else
84 SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION); 81 SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION);
85 SSL_CTX_set_max_proto_version(ctx, TLS1_1_VERSION); 82 SSL_CTX_set_max_proto_version(ctx, TLS1_1_VERSION);
86 break; 83 break;
87#endif 84# endif
88 case MP_TLSv1_2: /* TLSv1.2 protocol */ 85 case MP_TLSv1_2: /* TLSv1.2 protocol */
89#if !defined(SSL_OP_NO_TLSv1_2) 86# if !defined(SSL_OP_NO_TLSv1_2)
90 printf("%s\n", _("UNKNOWN - TLS protocol version 1.2 is not supported by your SSL library.")); 87 printf("%s\n", _("UNKNOWN - TLS protocol version 1.2 is not supported by your SSL library."));
91 return STATE_UNKNOWN; 88 return STATE_UNKNOWN;
92#else 89# else
93 SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); 90 SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
94 SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION); 91 SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION);
95 break; 92 break;
96#endif 93# endif
97 case MP_TLSv1_2_OR_NEWER: 94 case MP_TLSv1_2_OR_NEWER:
98#if !defined(SSL_OP_NO_TLSv1_1) 95# if !defined(SSL_OP_NO_TLSv1_1)
99 printf("%s\n", _("UNKNOWN - Disabling TLSv1.1 is not supported by your SSL library.")); 96 printf("%s\n", _("UNKNOWN - Disabling TLSv1.1 is not supported by your SSL library."));
100 return STATE_UNKNOWN; 97 return STATE_UNKNOWN;
101#else 98# else
102 SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); 99 SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
103 break; 100 break;
104#endif 101# endif
105 case MP_TLSv1_1_OR_NEWER: 102 case MP_TLSv1_1_OR_NEWER:
106#if !defined(SSL_OP_NO_TLSv1) 103# if !defined(SSL_OP_NO_TLSv1)
107 printf("%s\n", _("UNKNOWN - Disabling TLSv1 is not supported by your SSL library.")); 104 printf("%s\n", _("UNKNOWN - Disabling TLSv1 is not supported by your SSL library."));
108 return STATE_UNKNOWN; 105 return STATE_UNKNOWN;
109#else 106# else
110 SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION); 107 SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION);
111 break; 108 break;
112#endif 109# endif
113 case MP_TLSv1_OR_NEWER: 110 case MP_TLSv1_OR_NEWER:
114#if defined(SSL_OP_NO_SSLv3) 111# if defined(SSL_OP_NO_SSLv3)
115 SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION); 112 SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION);
116 break; 113 break;
117#endif 114# endif
118 case MP_SSLv3_OR_NEWER: 115 case MP_SSLv3_OR_NEWER:
119#if defined(SSL_OP_NO_SSLv2) 116# if defined(SSL_OP_NO_SSLv2)
120 SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION); 117 SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION);
121 break; 118 break;
122#endif 119# endif
123 } 120 }
124 121
125 if (cert && privkey) { 122 if (cert && privkey) {
126#ifdef USE_OPENSSL 123# ifdef USE_OPENSSL
127 if (!SSL_CTX_use_certificate_chain_file(ctx, cert)) { 124 if (!SSL_CTX_use_certificate_chain_file(ctx, cert)) {
128#elif USE_GNUTLS 125# elif USE_GNUTLS
129 if (!SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM)) { 126 if (!SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM)) {
130#else 127# else
131#error Unported for unknown SSL library 128# error Unported for unknown SSL library
132#endif 129# endif
133 printf ("%s\n", _("CRITICAL - Unable to open certificate chain file!\n")); 130 printf("%s\n", _("CRITICAL - Unable to open certificate chain file!\n"));
134 return STATE_CRITICAL; 131 return STATE_CRITICAL;
135 } 132 }
136 SSL_CTX_use_PrivateKey_file(ctx, privkey, SSL_FILETYPE_PEM); 133 SSL_CTX_use_PrivateKey_file(ctx, privkey, SSL_FILETYPE_PEM);
137#ifdef USE_OPENSSL 134# ifdef USE_OPENSSL
138 if (!SSL_CTX_check_private_key(ctx)) { 135 if (!SSL_CTX_check_private_key(ctx)) {
139 printf ("%s\n", _("CRITICAL - Private key does not seem to match certificate!\n")); 136 printf("%s\n", _("CRITICAL - Private key does not seem to match certificate!\n"));
140 return STATE_CRITICAL; 137 return STATE_CRITICAL;
141 } 138 }
142#endif 139# endif
143 } 140 }
144#ifdef SSL_OP_NO_TICKET 141# ifdef SSL_OP_NO_TICKET
145 options |= SSL_OP_NO_TICKET; 142 options |= SSL_OP_NO_TICKET;
146#endif 143# endif
147 SSL_CTX_set_options(ctx, options); 144 SSL_CTX_set_options(ctx, options);
148 SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); 145 SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
149 if ((s = SSL_new(ctx)) != NULL) { 146 if ((s = SSL_new(ctx)) != NULL) {
150#ifdef SSL_set_tlsext_host_name 147# ifdef SSL_set_tlsext_host_name
151 if (host_name != NULL) 148 if (host_name != NULL)
152 SSL_set_tlsext_host_name(s, host_name); 149 SSL_set_tlsext_host_name(s, host_name);
153#endif 150# endif
154 SSL_set_fd(s, sd); 151 SSL_set_fd(s, sd);
155 if (SSL_connect(s) == 1) { 152 if (SSL_connect(s) == 1) {
156 return OK; 153 return OK;
157 } else { 154 } else {
158 printf("%s\n", _("CRITICAL - Cannot make SSL connection.")); 155 printf("%s\n", _("CRITICAL - Cannot make SSL connection."));
159# ifdef USE_OPENSSL /* XXX look into ERR_error_string */ 156# ifdef USE_OPENSSL /* XXX look into ERR_error_string */
160 ERR_print_errors_fp(stdout); 157 ERR_print_errors_fp(stdout);
161# endif /* USE_OPENSSL */ 158# endif /* USE_OPENSSL */
162 } 159 }
163 } else { 160 } else {
164 printf("%s\n", _("CRITICAL - Cannot initiate SSL handshake.")); 161 printf("%s\n", _("CRITICAL - Cannot initiate SSL handshake."));
165 } 162 }
166 return STATE_CRITICAL; 163 return STATE_CRITICAL;
167} 164}
168 165
169void np_net_ssl_cleanup() { 166void np_net_ssl_cleanup() {
170 if (s) { 167 if (s) {
171#ifdef SSL_set_tlsext_host_name 168# ifdef SSL_set_tlsext_host_name
172 SSL_set_tlsext_host_name(s, NULL); 169 SSL_set_tlsext_host_name(s, NULL);
173#endif 170# endif
174 SSL_shutdown(s); 171 SSL_shutdown(s);
175 SSL_free(s); 172 SSL_free(s);
176 if (ctx) { 173 if (ctx) {
177 SSL_CTX_free(ctx); 174 SSL_CTX_free(ctx);
178 ctx=NULL; 175 ctx = NULL;
179 } 176 }
180 s=NULL; 177 s = NULL;
181 } 178 }
182} 179}
183 180
184int np_net_ssl_write(const void *buf, int num) { 181int np_net_ssl_write(const void *buf, int num) { return SSL_write(s, buf, num); }
185 return SSL_write(s, buf, num);
186}
187 182
188int np_net_ssl_read(void *buf, int num) { 183int np_net_ssl_read(void *buf, int num) { return SSL_read(s, buf, num); }
189 return SSL_read(s, buf, num);
190}
191 184
192int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit){ 185int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit) {
193# ifdef USE_OPENSSL 186# ifdef USE_OPENSSL
194 X509_NAME *subj=NULL; 187 X509_NAME *subj = NULL;
195 char timestamp[50] = ""; 188 char timestamp[50] = "";
196 char cn[MAX_CN_LENGTH]= ""; 189 char cn[MAX_CN_LENGTH] = "";
197 char *tz; 190 char *tz;
198 191
199 int cnlen =-1; 192 int cnlen = -1;
200 int status=STATE_UNKNOWN; 193 int status = STATE_UNKNOWN;
201 194
202 ASN1_STRING *tm; 195 ASN1_STRING *tm;
203 int offset; 196 int offset;
@@ -208,15 +201,15 @@ int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int
208 time_t tm_t; 201 time_t tm_t;
209 202
210 if (!certificate) { 203 if (!certificate) {
211 printf("%s\n",_("CRITICAL - Cannot retrieve server certificate.")); 204 printf("%s\n", _("CRITICAL - No server certificate present to inspect."));
212 return STATE_CRITICAL; 205 return STATE_CRITICAL;
213 } 206 }
214 207
215 /* Extract CN from certificate subject */ 208 /* Extract CN from certificate subject */
216 subj=X509_get_subject_name(certificate); 209 subj = X509_get_subject_name(certificate);
217 210
218 if (!subj) { 211 if (!subj) {
219 printf("%s\n",_("CRITICAL - Cannot retrieve certificate subject.")); 212 printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject."));
220 return STATE_CRITICAL; 213 return STATE_CRITICAL;
221 } 214 }
222 cnlen = X509_NAME_get_text_by_NID(subj, NID_commonName, cn, sizeof(cn)); 215 cnlen = X509_NAME_get_text_by_NID(subj, NID_commonName, cn, sizeof(cn));
@@ -242,23 +235,16 @@ int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int
242 printf("%s\n", _("CRITICAL - Wrong time format in certificate.")); 235 printf("%s\n", _("CRITICAL - Wrong time format in certificate."));
243 return STATE_CRITICAL; 236 return STATE_CRITICAL;
244 } else { 237 } else {
245 stamp.tm_year = 238 stamp.tm_year = (tm->data[0] - '0') * 1000 + (tm->data[1] - '0') * 100 + (tm->data[2] - '0') * 10 + (tm->data[3] - '0');
246 (tm->data[0] - '0') * 1000 + (tm->data[1] - '0') * 100 +
247 (tm->data[2] - '0') * 10 + (tm->data[3] - '0');
248 stamp.tm_year -= 1900; 239 stamp.tm_year -= 1900;
249 offset = 2; 240 offset = 2;
250 } 241 }
251 } 242 }
252 stamp.tm_mon = 243 stamp.tm_mon = (tm->data[2 + offset] - '0') * 10 + (tm->data[3 + offset] - '0') - 1;
253 (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');
254 stamp.tm_mday = 245 stamp.tm_hour = (tm->data[6 + offset] - '0') * 10 + (tm->data[7 + offset] - '0');
255 (tm->data[4 + offset] - '0') * 10 + (tm->data[5 + offset] - '0'); 246 stamp.tm_min = (tm->data[8 + offset] - '0') * 10 + (tm->data[9 + offset] - '0');
256 stamp.tm_hour = 247 stamp.tm_sec = (tm->data[10 + offset] - '0') * 10 + (tm->data[11 + offset] - '0');
257 (tm->data[6 + offset] - '0') * 10 + (tm->data[7 + offset] - '0');
258 stamp.tm_min =
259 (tm->data[8 + offset] - '0') * 10 + (tm->data[9 + offset] - '0');
260 stamp.tm_sec =
261 (tm->data[10 + offset] - '0') * 10 + (tm->data[11 + offset] - '0');
262 stamp.tm_isdst = -1; 248 stamp.tm_isdst = -1;
263 249
264 tm_t = timegm(&stamp); 250 tm_t = timegm(&stamp);
@@ -275,30 +261,30 @@ int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int
275 tzset(); 261 tzset();
276 262
277 if (days_left > 0 && days_left <= days_till_exp_warn) { 263 if (days_left > 0 && days_left <= days_till_exp_warn) {
278 printf (_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", cn, days_left, timestamp); 264 printf(_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn,
265 days_left, timestamp);
279 if (days_left > days_till_exp_crit) 266 if (days_left > days_till_exp_crit)
280 status = STATE_WARNING; 267 status = STATE_WARNING;
281 else 268 else
282 status = STATE_CRITICAL; 269 status = STATE_CRITICAL;
283 } else if (days_left == 0 && time_left > 0) { 270 } else if (days_left == 0 && time_left > 0) {
284 if (time_left >= 3600) 271 if (time_left >= 3600)
285 time_remaining = (int) time_left / 3600; 272 time_remaining = (int)time_left / 3600;
286 else 273 else
287 time_remaining = (int) time_left / 60; 274 time_remaining = (int)time_left / 60;
288 275
289 printf (_("%s - Certificate '%s' expires in %u %s (%s)\n"), 276 printf(_("%s - Certificate '%s' expires in %u %s (%s)\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn,
290 (days_left>days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, time_remaining, 277 time_remaining, time_left >= 3600 ? "hours" : "minutes", timestamp);
291 time_left >= 3600 ? "hours" : "minutes", timestamp);
292 278
293 if ( days_left > days_till_exp_crit) 279 if (days_left > days_till_exp_crit)
294 status = STATE_WARNING; 280 status = STATE_WARNING;
295 else 281 else
296 status = STATE_CRITICAL; 282 status = STATE_CRITICAL;
297 } else if (time_left < 0) { 283 } else if (time_left < 0) {
298 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), cn, timestamp); 284 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), cn, timestamp);
299 status=STATE_CRITICAL; 285 status = STATE_CRITICAL;
300 } else if (days_left == 0) { 286 } else if (days_left == 0) {
301 printf (_("%s - Certificate '%s' just expired (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", cn, timestamp); 287 printf(_("%s - Certificate '%s' just expired (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, timestamp);
302 if (days_left > days_till_exp_crit) 288 if (days_left > days_till_exp_crit)
303 status = STATE_WARNING; 289 status = STATE_WARNING;
304 else 290 else
@@ -309,22 +295,21 @@ int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int
309 } 295 }
310 X509_free(certificate); 296 X509_free(certificate);
311 return status; 297 return status;
312# else /* ifndef USE_OPENSSL */ 298# else /* ifndef USE_OPENSSL */
313 printf("%s\n", _("WARNING - Plugin does not support checking certificates.")); 299 printf("%s\n", _("WARNING - Plugin does not support checking certificates."));
314 return STATE_WARNING; 300 return STATE_WARNING;
315# endif /* USE_OPENSSL */ 301# endif /* USE_OPENSSL */
316} 302}
317 303
318int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit){ 304int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit) {
319# ifdef USE_OPENSSL 305# ifdef USE_OPENSSL
320 X509 *certificate = NULL; 306 X509 *certificate = NULL;
321 certificate=SSL_get_peer_certificate(s); 307 certificate = SSL_get_peer_certificate(s);
322 return(np_net_ssl_check_certificate(certificate, days_till_exp_warn, days_till_exp_crit)); 308 return (np_net_ssl_check_certificate(certificate, days_till_exp_warn, days_till_exp_crit));
323# else /* ifndef USE_OPENSSL */ 309# else /* ifndef USE_OPENSSL */
324 printf("%s\n", _("WARNING - Plugin does not support checking certificates.")); 310 printf("%s\n", _("WARNING - Plugin does not support checking certificates."));
325 return STATE_WARNING; 311 return STATE_WARNING;
326# endif /* USE_OPENSSL */ 312# endif /* USE_OPENSSL */
327} 313}
328 314
329
330#endif /* HAVE_SSL */ 315#endif /* HAVE_SSL */
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_http.t b/plugins/t/check_http.t
index 6ab4a5b6..bb1fd27d 100644
--- a/plugins/t/check_http.t
+++ b/plugins/t/check_http.t
@@ -45,7 +45,7 @@ $res = NPTest->testCmd(
45 "./$plugin $host_nonresponsive -wt 1 -ct 2 -t 3" 45 "./$plugin $host_nonresponsive -wt 1 -ct 2 -t 3"
46 ); 46 );
47cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" ); 47cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" );
48cmp_ok( $res->output, 'eq', "CRITICAL - Socket timeout after 3 seconds", "Output OK"); 48like( $res->output, "/Socket timeout after/", "Output OK");
49 49
50$res = NPTest->testCmd( 50$res = NPTest->testCmd(
51 "./$plugin $hostname_invalid -wt 1 -ct 2" 51 "./$plugin $hostname_invalid -wt 1 -ct 2"
diff --git a/plugins/t/check_jabber.t b/plugins/t/check_jabber.t
index fcdae179..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 = '/CRITICAL\s-\sSocket 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 b8a4a766..fcba0393 100644
--- a/plugins/t/check_ldap.t
+++ b/plugins/t/check_ldap.t
@@ -24,7 +24,7 @@ SKIP: {
24 24
25 $result = NPTest->testCmd("$command -H $host_nonresponsive -b ou=blah -t 2 -w 1 -c 1"); 25 $result = NPTest->testCmd("$command -H $host_nonresponsive -b ou=blah -t 2 -w 1 -c 1");
26 is( $result->return_code, 2, "$command -H $host_nonresponsive -b ou=blah -t 5 -w 2 -c 3" ); 26 is( $result->return_code, 2, "$command -H $host_nonresponsive -b ou=blah -t 5 -w 2 -c 3" );
27 is( $result->output, 'CRITICAL - Socket timeout after 2 seconds', "output ok" ); 27 like($result->output, '/Socket timeout after \d+ seconds/', "output ok" );
28}; 28};
29 29
30SKIP: { 30SKIP: {
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 baf3acc6..a383bc99 100644
--- a/plugins/t/check_mysql.t
+++ b/plugins/t/check_mysql.t
@@ -21,11 +21,11 @@ plan skip_all => "check_mysql not compiled" unless (-x "check_mysql");
21plan tests => 15; 21plan tests => 15;
22 22
23my $bad_login_output = '/Access denied for user /'; 23my $bad_login_output = '/Access denied for user /';
24my $mysqlserver = getTestParameter("NP_MYSQL_SERVER", "A MySQL Server hostname or IP with no slaves setup"); 24my $mysqlserver = getTestParameter("NP_MYSQL_SERVER", "A MySQL Server hostname or IP with no replica setup");
25my $mysqlsocket = getTestParameter("NP_MYSQL_SOCKET", "Full path to a MySQL Server socket with no slaves setup"); 25my $mysqlsocket = getTestParameter("NP_MYSQL_SOCKET", "Full path to a MySQL Server socket with no replica setup");
26my $mysql_login_details = getTestParameter("NP_MYSQL_LOGIN_DETAILS", "Command line parameters to specify login access (requires REPLICATION CLIENT privileges)", "-u test -ptest"); 26my $mysql_login_details = getTestParameter("NP_MYSQL_LOGIN_DETAILS", "Command line parameters to specify login access (requires REPLICATION CLIENT privileges)", "-u test -ptest");
27my $with_slave = getTestParameter("NP_MYSQL_WITH_SLAVE", "MySQL server with slaves setup"); 27my $with_replica = getTestParameter("NP_MYSQL_WITH_REPLICA", "MySQL server with replica setup");
28my $with_slave_login = getTestParameter("NP_MYSQL_WITH_SLAVE_LOGIN", "Login details for server with slave (requires REPLICATION CLIENT privileges)", $mysql_login_details || "-u test -ptest"); 28my $with_replica_login = getTestParameter("NP_MYSQL_WITH_REPLICA_LOGIN", "Login details for server with replica (requires REPLICATION CLIENT privileges)", $mysql_login_details || "-u test -ptest");
29 29
30my $result; 30my $result;
31 31
@@ -39,8 +39,8 @@ SKIP: {
39 like( $result->output, $bad_login_output, "Expected login failure message"); 39 like( $result->output, $bad_login_output, "Expected login failure message");
40 40
41 $result = NPTest->testCmd("./check_mysql -S -H $mysqlserver $mysql_login_details"); 41 $result = NPTest->testCmd("./check_mysql -S -H $mysqlserver $mysql_login_details");
42 cmp_ok( $result->return_code, "==", 1, "No slaves defined" ); 42 cmp_ok( $result->return_code, "==", 1, "No replicas defined" );
43 like( $result->output, "/No slaves defined/", "Correct error message"); 43 like( $result->output, "/No replicas defined/", "Correct error message");
44} 44}
45 45
46SKIP: { 46SKIP: {
@@ -53,22 +53,22 @@ SKIP: {
53 like( $result->output, $bad_login_output, "Expected login failure message"); 53 like( $result->output, $bad_login_output, "Expected login failure message");
54 54
55 $result = NPTest->testCmd("./check_mysql -S -s $mysqlsocket $mysql_login_details"); 55 $result = NPTest->testCmd("./check_mysql -S -s $mysqlsocket $mysql_login_details");
56 cmp_ok( $result->return_code, "==", 1, "No slaves defined" ); 56 cmp_ok( $result->return_code, "==", 1, "No replicas defined" );
57 like( $result->output, "/No slaves defined/", "Correct error message"); 57 like( $result->output, "/No replicas defined/", "Correct error message");
58} 58}
59 59
60SKIP: { 60SKIP: {
61 skip "No mysql server with slaves defined", 5 unless $with_slave; 61 skip "No mysql server with replicas defined", 5 unless $with_replica;
62 $result = NPTest->testCmd("./check_mysql -H $with_slave $with_slave_login"); 62 $result = NPTest->testCmd("./check_mysql -H $with_replica $with_replica_login");
63 cmp_ok( $result->return_code, '==', 0, "Login okay"); 63 cmp_ok( $result->return_code, '==', 0, "Login okay");
64 64
65 $result = NPTest->testCmd("./check_mysql -S -H $with_slave $with_slave_login"); 65 $result = NPTest->testCmd("./check_mysql -S -H $with_replica $with_replica_login");
66 cmp_ok( $result->return_code, "==", 0, "Slaves okay" ); 66 cmp_ok( $result->return_code, "==", 0, "Replicas okay" );
67 67
68 $result = NPTest->testCmd("./check_mysql -S -H $with_slave $with_slave_login -w 60"); 68 $result = NPTest->testCmd("./check_mysql -S -H $with_replica $with_replica_login -w 60");
69 cmp_ok( $result->return_code, '==', 0, 'Slaves are not > 60 seconds behind'); 69 cmp_ok( $result->return_code, '==', 0, 'Replicas are not > 60 seconds behind');
70 70
71 $result = NPTest->testCmd("./check_mysql -S -H $with_slave $with_slave_login -w 60:"); 71 $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'); 72 cmp_ok( $result->return_code, '==', 1, 'Alert warning if < 60 seconds behind');
73 like( $result->output, "/^SLOW_SLAVE WARNING:/", "Output okay"); 73 like( $result->output, "/^SLOW_REPLICA WARNING:/", "Output okay");
74} 74}
diff --git a/plugins/t/check_ntp.t b/plugins/t/check_ntp.t
index b8fc8fdf..a8ac7bb8 100644
--- a/plugins/t/check_ntp.t
+++ b/plugins/t/check_ntp.t
@@ -37,7 +37,7 @@ my $ntp_critmatch1 = '/^NTP\sCRITICAL:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?
37my $ntp_okmatch2 = '/^NTP\sOK:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+,\sstratum=[0-9]{1,2},\struechimers=[0-9]+/'; 37my $ntp_okmatch2 = '/^NTP\sOK:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+,\sstratum=[0-9]{1,2},\struechimers=[0-9]+/';
38my $ntp_warnmatch2 = '/^NTP\sWARNING:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+,\sstratum=[0-9]{1,2}\s\(WARNING\),\struechimers=[0-9]+/'; 38my $ntp_warnmatch2 = '/^NTP\sWARNING:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+,\sstratum=[0-9]{1,2}\s\(WARNING\),\struechimers=[0-9]+/';
39my $ntp_critmatch2 = '/^NTP\sCRITICAL:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+\s\(CRITICAL\),\sstratum=[0-9]{1,2},\struechimers=[0-9]+/'; 39my $ntp_critmatch2 = '/^NTP\sCRITICAL:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+\s\(CRITICAL\),\sstratum=[0-9]{1,2},\struechimers=[0-9]+/';
40my $ntp_noresponse = '/^(CRITICAL - Socket timeout after 3 seconds)|(NTP CRITICAL: No response from NTP server)$/'; 40my $ntp_noresponse = '/(.*Socket timeout after \d+ seconds.*)|(.*No response from NTP server.*)/';
41my $ntp_nosuchhost = '/^check_ntp.*: Invalid hostname/address - ' . $hostname_invalid . '/'; 41my $ntp_nosuchhost = '/^check_ntp.*: Invalid hostname/address - ' . $hostname_invalid . '/';
42 42
43 43
diff --git a/plugins/t/check_smtp.t b/plugins/t/check_smtp.t
index 1a1ebe3e..73b4a1fd 100644
--- a/plugins/t/check_smtp.t
+++ b/plugins/t/check_smtp.t
@@ -24,7 +24,7 @@ my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
24 "An invalid (not known to DNS) hostname", "nosuchhost" ); 24 "An invalid (not known to DNS) hostname", "nosuchhost" );
25my $res; 25my $res;
26 26
27plan tests => 16; 27plan tests => 15;
28 28
29SKIP: { 29SKIP: {
30 skip "No SMTP server defined", 4 unless $host_tcp_smtp; 30 skip "No SMTP server defined", 4 unless $host_tcp_smtp;
@@ -73,7 +73,6 @@ SKIP: {
73 my $unused_port = 4465; 73 my $unused_port = 4465;
74 $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls -p $unused_port --ssl" ); 74 $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls -p $unused_port --ssl" );
75 is ($res->return_code, 2, "Check rc of connecting to $host_tcp_smtp_tls with TLS on unused port $unused_port" ); 75 is ($res->return_code, 2, "Check rc of connecting to $host_tcp_smtp_tls with TLS on unused port $unused_port" );
76 like ($res->output, qr/^connect to address $host_tcp_smtp_tls and port $unused_port: Connection refused/, "Check output of connecting to $host_tcp_smtp_tls with TLS on unused port $unused_port");
77} 76}
78 77
79$res = NPTest->testCmd( "./check_smtp $host_nonresponsive" ); 78$res = NPTest->testCmd( "./check_smtp $host_nonresponsive" );
diff --git a/plugins/t/check_ssh.t b/plugins/t/check_ssh.t
index 907d33a8..8a20782e 100644
--- a/plugins/t/check_ssh.t
+++ b/plugins/t/check_ssh.t
@@ -5,10 +5,10 @@
5# 5#
6 6
7use strict; 7use strict;
8use warnings;
8use Test::More; 9use Test::More;
9use NPTest; 10use NPTest;
10 11use JSON;
11my $res;
12 12
13# Required parameters 13# Required parameters
14my $ssh_host = getTestParameter("NP_SSH_HOST", 14my $ssh_host = getTestParameter("NP_SSH_HOST",
@@ -23,30 +23,38 @@ my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID",
23 "An invalid (not known to DNS) hostname", 23 "An invalid (not known to DNS) hostname",
24 "nosuchhost" ); 24 "nosuchhost" );
25 25
26 my $outputFormat = '--output-format mp-test-json';
27
28plan tests => 24;
26 29
27plan tests => 14 + 6; 30my $output;
31my $result;
28 32
29SKIP: { 33SKIP: {
30 skip "SSH_HOST must be defined", 6 unless $ssh_host; 34 skip "SSH_HOST must be defined", 6 unless $ssh_host;
35
36
31 my $result = NPTest->testCmd( 37 my $result = NPTest->testCmd(
32 "./check_ssh -H $ssh_host" 38 "./check_ssh -H $ssh_host" ." ". $outputFormat
33 ); 39 );
34 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)"); 40 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
35 like($result->output, '/^SSH OK - /', "Status text if command returned none (OK)"); 41 $output = decode_json($result->output);
42 is($output->{'state'}, "OK", "State was correct");
36 43
37 44
38 $result = NPTest->testCmd( 45 $result = NPTest->testCmd(
39 "./check_ssh -H $host_nonresponsive -t 2" 46 "./check_ssh -H $host_nonresponsive -t 2" ." ". $outputFormat
40 ); 47 );
41 cmp_ok($result->return_code, '==', 2, "Exit with return code 0 (OK)"); 48 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
42 like($result->output, '/^CRITICAL - Socket timeout after 2 seconds/', "Status text if command returned none (OK)"); 49 $output = decode_json($result->output);
50 is($output->{'state'}, "CRITICAL", "State was correct");
43 51
44 52
45 53
46 $result = NPTest->testCmd( 54 $result = NPTest->testCmd(
47 "./check_ssh -H $hostname_invalid -t 2" 55 "./check_ssh -H $hostname_invalid -t 2" ." ". $outputFormat
48 ); 56 );
49 cmp_ok($result->return_code, '==', 3, "Exit with return code 0 (OK)"); 57 cmp_ok($result->return_code, '==', 3, "Exit with return code 3 (UNKNOWN)");
50 like($result->output, '/^check_ssh: Invalid hostname/', "Status text if command returned none (OK)"); 58 like($result->output, '/^check_ssh: Invalid hostname/', "Status text if command returned none (OK)");
51 59
52 60
@@ -63,46 +71,80 @@ SKIP: {
63 # 71 #
64 # where `comments` is optional, protoversion is the SSH protocol version and 72 # where `comments` is optional, protoversion is the SSH protocol version and
65 # softwareversion is an arbitrary string representing the server software version 73 # softwareversion is an arbitrary string representing the server software version
74
75 my $found_version = 0;
76
66 open(NC, "echo 'SSH-2.0-nagiosplug.ssh.0.1' | nc ${nc_flags}|"); 77 open(NC, "echo 'SSH-2.0-nagiosplug.ssh.0.1' | nc ${nc_flags}|");
67 sleep 0.1; 78 sleep 0.1;
68 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ); 79 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
69 cmp_ok( $res->return_code, '==', 0, "Got SSH protocol version control string"); 80 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
70 like( $res->output, '/^SSH OK - nagiosplug.ssh.0.1 \(protocol 2.0\)/', "Output OK"); 81 $output = decode_json($result->output);
82 is($output->{'state'}, "OK", "State was correct");
83
84 # looking for the version
85 for my $subcheck (@{$output->{'checks'}}) {
86 if ($subcheck->{'output'} =~ /.*nagiosplug.ssh.0.1 \(protocol version: 2.0\).*/ ){
87 $found_version = 1;
88 }
89 }
90 cmp_ok($found_version, '==', 1, "Output OK");
71 close NC; 91 close NC;
72 92
73 open(NC, "echo 'SSH-2.0-3.2.9.1' | nc ${nc_flags}|"); 93 open(NC, "echo 'SSH-2.0-3.2.9.1' | nc ${nc_flags}|");
74 sleep 0.1; 94 sleep 0.1;
75 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ); 95 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
76 cmp_ok( $res->return_code, "==", 0, "Got SSH protocol version control string with non-alpha softwareversion string"); 96 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
77 like( $res->output, '/^SSH OK - 3.2.9.1 \(protocol 2.0\)/', "Output OK for non-alpha softwareversion string"); 97 $output = decode_json($result->output);
98 is($output->{'state'}, "OK", "State was correct");
99
100 $found_version = 0;
101 for my $subcheck (@{$output->{'checks'}}) {
102 if ($subcheck->{'output'} =~ /3.2.9.1 \(protocol version: 2.0\)/ ){
103 $found_version = 1;
104 }
105 }
106 cmp_ok($found_version, '==', 1, "Output OK");
78 close NC; 107 close NC;
79 108
80 open(NC, "echo 'SSH-2.0-nagiosplug.ssh.0.1 this is a comment' | nc ${nc_flags} |"); 109 open(NC, "echo 'SSH-2.0-nagiosplug.ssh.0.1 this is a comment' | nc ${nc_flags} |");
81 sleep 0.1; 110 sleep 0.1;
82 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003 -r nagiosplug.ssh.0.1" ); 111 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003 -r nagiosplug.ssh.0.1" ." ". $outputFormat);
83 cmp_ok( $res->return_code, '==', 0, "Got SSH protocol version control string, and parsed comment appropriately"); 112 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
84 like( $res->output, '/^SSH OK - nagiosplug.ssh.0.1 \(protocol 2.0\)/', "Output OK"); 113 $output = decode_json($result->output);
114 is($output->{'state'}, "OK", "State was correct");
115
116 # looking for the version
117 $found_version = 0;
118 for my $subcheck (@{$output->{'checks'}}) {
119 if ($subcheck->{'output'} =~ /nagiosplug.ssh.0.1 \(protocol version: 2.0\)/ ){
120 $found_version = 1;
121 }
122 }
123 cmp_ok($found_version, '==', 1, "Output OK");
85 close NC; 124 close NC;
86 125
87 open(NC, "echo 'SSH-' | nc ${nc_flags}|"); 126 open(NC, "echo 'SSH-' | nc ${nc_flags}|");
88 sleep 0.1; 127 sleep 0.1;
89 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ); 128 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
90 cmp_ok( $res->return_code, '==', 2, "Got invalid SSH protocol version control string"); 129 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
91 like( $res->output, '/^SSH CRITICAL/', "Output OK"); 130 $output = decode_json($result->output);
131 is($output->{'state'}, "CRITICAL", "Got invalid SSH protocol version control string");
92 close NC; 132 close NC;
93 133
94 open(NC, "echo '' | nc ${nc_flags}|"); 134 open(NC, "echo '' | nc ${nc_flags}|");
95 sleep 0.1; 135 sleep 0.1;
96 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ); 136 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
97 cmp_ok( $res->return_code, '==', 2, "No version control string received"); 137 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
98 like( $res->output, '/^SSH CRITICAL - No version control string received/', "Output OK"); 138 $output = decode_json($result->output);
139 is($output->{'state'}, "CRITICAL", "No version control string received");
99 close NC; 140 close NC;
100 141
101 open(NC, "echo 'Not a version control string' | nc ${nc_flags}|"); 142 open(NC, "echo 'Not a version control string' | nc ${nc_flags}|");
102 sleep 0.1; 143 sleep 0.1;
103 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ); 144 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
104 cmp_ok( $res->return_code, '==', 2, "No version control string received"); 145 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
105 like( $res->output, '/^SSH CRITICAL - No version control string received/', "Output OK"); 146 $output = decode_json($result->output);
147 is($output->{'state'}, "CRITICAL", "No version control string received");
106 close NC; 148 close NC;
107 149
108 150
@@ -116,8 +158,18 @@ SKIP: {
116 echo 'Some\nPrepended\nData\nLines\n'; sleep 0.2; 158 echo 'Some\nPrepended\nData\nLines\n'; sleep 0.2;
117 echo 'SSH-2.0-nagiosplug.ssh.0.2';} | nc ${nc_flags}|"); 159 echo 'SSH-2.0-nagiosplug.ssh.0.2';} | nc ${nc_flags}|");
118 sleep 0.1; 160 sleep 0.1;
119 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ); 161 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
120 cmp_ok( $res->return_code, '==', 0, "Got delayed SSH protocol version control string"); 162 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
121 like( $res->output, '/^SSH OK - nagiosplug.ssh.0.2 \(protocol 2.0\)/', "Output OK"); 163 $output = decode_json($result->output);
164 is($output->{'state'}, "OK", "State was correct");
165
166 # looking for the version
167 $found_version = 0;
168 for my $subcheck (@{$output->{'checks'}}) {
169 if ($subcheck->{'output'} =~ /nagiosplug.ssh.0.2 \(protocol version: 2.0\)/ ){
170 $found_version = 1;
171 }
172 }
173 cmp_ok($found_version, '==', 1, "Output OK");
122 close NC; 174 close NC;
123} 175}
diff --git a/plugins/t/check_swap.t b/plugins/t/check_swap.t
index 18780386..68946f6d 100644
--- a/plugins/t/check_swap.t
+++ b/plugins/t/check_swap.t
@@ -5,39 +5,47 @@
5# 5#
6 6
7use strict; 7use strict;
8use Test::More tests => 14; 8use warnings;
9use Test::More tests => 21;
9use NPTest; 10use NPTest;
10 11use JSON;
11my $successOutput = '/^SWAP OK - [0-9]+\% free \([0-9]+MB out of [0-9]+MB\)/';
12my $failureOutput = '/^SWAP CRITICAL - [0-9]+\% free \([0-9]+MB out of [0-9]+MB\)/';
13my $warnOutput = '/^SWAP WARNING - [0-9]+\% free \([0-9]+MB out of [0-9]+MB\)/';
14 12
15my $result; 13my $result;
14my $outputFormat = '--output-format mp-test-json';
15my $output;
16my $message = '/^[0-9]+\% free \([0-9]+MiB out of [0-9]+MiB\)/';
16 17
17$result = NPTest->testCmd( "./check_swap" ); # Always OK 18$result = NPTest->testCmd( "./check_swap $outputFormat" ); # Always OK
18cmp_ok( $result->return_code, "==", 0, "Always OK" ); 19cmp_ok( $result->return_code, "==", 0, "Always OK" );
19like( $result->output, $successOutput, "Right output" ); 20is($result->{'mp_test_result'}->{'state'}, "OK", "State was correct");
21like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
20 22
21$result = NPTest->testCmd( "./check_swap -w 1048576 -c 1048576" ); # 1 MB free 23$result = NPTest->testCmd( "./check_swap -w 1048576 -c 1048576 $outputFormat" ); # 1 MB free
22cmp_ok( $result->return_code, "==", 0, "At least 1MB free" ); 24cmp_ok( $result->return_code, "==", 0, "Always OK" );
23like( $result->output, $successOutput, "Right output" ); 25is($result->{'mp_test_result'}->{'state'}, "OK", "State was correct");
26like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
24 27
25$result = NPTest->testCmd( "./check_swap -w 1% -c 1%" ); # 1% free 28$result = NPTest->testCmd( "./check_swap -w 1% -c 1% $outputFormat" ); # 1% free
26cmp_ok( $result->return_code, "==", 0, 'At least 1% free' ); 29cmp_ok( $result->return_code, "==", 0, "Always OK" );
27like( $result->output, $successOutput, "Right output" ); 30is($result->{'mp_test_result'}->{'state'}, "OK", "State was correct");
31like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
28 32
29$result = NPTest->testCmd( "./check_swap -w 100% -c 100%" ); # 100% (always critical) 33$result = NPTest->testCmd( "./check_swap -w 100% -c 100% $outputFormat" ); # 100% (always critical)
30cmp_ok( $result->return_code, "==", 2, 'Get critical because not 100% free' ); 34cmp_ok( $result->return_code, "==", 0, "Always OK" );
31like( $result->output, $failureOutput, "Right output" ); 35is($result->{'mp_test_result'}->{'state'}, "CRITICAL", "State was correct");
36like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
32 37
33$result = NPTest->testCmd( "./check_swap -w 100% -c 1%" ); # 100% (always warn) 38$result = NPTest->testCmd( "./check_swap -w 100% -c 1% $outputFormat" ); # 100% (always warn)
34cmp_ok( $result->return_code, "==", 1, 'Get warning because not 100% free' ); 39cmp_ok( $result->return_code, "==", 0, "Always OK" );
35like( $result->output, $warnOutput, "Right output" ); 40is($result->{'mp_test_result'}->{'state'}, "WARNING", "State was correct");
41like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
36 42
37$result = NPTest->testCmd( "./check_swap -w 100%" ); # 100% (single threshold, always warn) 43$result = NPTest->testCmd( "./check_swap -w 100% $outputFormat" ); # 100% (single threshold, always warn)
38cmp_ok( $result->return_code, "==", 1, 'Get warning because not 100% free' ); 44cmp_ok( $result->return_code, "==", 0, "Always OK" );
39like( $result->output, $warnOutput, "Right output" ); 45is($result->{'mp_test_result'}->{'state'}, "WARNING", "State was correct");
46like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
40 47
41$result = NPTest->testCmd( "./check_swap -c 100%" ); # 100% (single threshold, always critical) 48$result = NPTest->testCmd( "./check_swap -c 100% $outputFormat" ); # 100% (single threshold, always critical)
42cmp_ok( $result->return_code, "==", 2, 'Get critical because not 100% free' ); 49cmp_ok( $result->return_code, "==", 0, "Always OK" );
43like( $result->output, $failureOutput, "Right output" ); 50is($result->{'mp_test_result'}->{'state'}, "CRITICAL", "State was correct");
51like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
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/tests/test_check_disk.c b/plugins/tests/test_check_disk.c
new file mode 100644
index 00000000..35c57bce
--- /dev/null
+++ b/plugins/tests/test_check_disk.c
@@ -0,0 +1,197 @@
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 "common.h"
20#include "../check_disk.d/utils_disk.h"
21#include "../../tap/tap.h"
22#include "regex.h"
23
24void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc);
25
26int main(int argc, char **argv) {
27 plan_tests(35);
28
29 struct name_list *exclude_filesystem = NULL;
30 ok(np_find_name(exclude_filesystem, "/var/log") == false, "/var/log not in list");
31 np_add_name(&exclude_filesystem, "/var/log");
32 ok(np_find_name(exclude_filesystem, "/var/log") == true, "is in list now");
33 ok(np_find_name(exclude_filesystem, "/home") == false, "/home not in list");
34 np_add_name(&exclude_filesystem, "/home");
35 ok(np_find_name(exclude_filesystem, "/home") == true, "is in list now");
36 ok(np_find_name(exclude_filesystem, "/var/log") == true, "/var/log still in list");
37
38 struct name_list *exclude_fstype = NULL;
39 ok(np_find_name(exclude_fstype, "iso9660") == false, "iso9660 not in list");
40 np_add_name(&exclude_fstype, "iso9660");
41 ok(np_find_name(exclude_fstype, "iso9660") == true, "is in list now");
42
43 ok(np_find_name(exclude_filesystem, "iso9660") == false, "Make sure no clashing in variables");
44
45 /*
46 for (temp_name = exclude_filesystem; temp_name; temp_name = temp_name->next) {
47 printf("Name: %s\n", temp_name->name);
48 }
49 */
50
51 struct mount_entry *dummy_mount_list;
52 struct mount_entry **mtail = &dummy_mount_list;
53 struct mount_entry *me = (struct mount_entry *)malloc(sizeof *me);
54 me->me_devname = strdup("/dev/c0t0d0s0");
55 me->me_mountdir = strdup("/");
56 *mtail = me;
57 mtail = &me->me_next;
58
59 me = (struct mount_entry *)malloc(sizeof *me);
60 me->me_devname = strdup("/dev/c1t0d1s0");
61 me->me_mountdir = strdup("/var");
62 *mtail = me;
63 mtail = &me->me_next;
64
65 me = (struct mount_entry *)malloc(sizeof *me);
66 me->me_devname = strdup("/dev/c2t0d0s0");
67 me->me_mountdir = strdup("/home");
68 *mtail = me;
69 mtail = &me->me_next;
70
71 int cflags = REG_NOSUB | REG_EXTENDED;
72 np_test_mount_entry_regex(dummy_mount_list, strdup("/"), cflags, 3, strdup("a"));
73 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("/foo"), cflags, 0, strdup("regex on non existent dev/path:"));
75 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("/c.t0"), cflags, 3, strdup("partial devname regex match:"));
77 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("C0t0"), cflags | REG_ICASE, 1, strdup("partial devname regi match:"));
79 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("hOme"), cflags | REG_ICASE, 1, strdup("partial pathname regi match:"));
81 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("(/homE)|(/Var)"), cflags | REG_ICASE, 2, strdup("grouped regi pathname match:"));
83
84 filesystem_list test_paths = filesystem_list_init();
85 mp_int_fs_list_append(&test_paths, "/home/groups");
86 mp_int_fs_list_append(&test_paths, "/var");
87 mp_int_fs_list_append(&test_paths, "/tmp");
88 mp_int_fs_list_append(&test_paths, "/home/tonvoon");
89 mp_int_fs_list_append(&test_paths, "/dev/c2t0d0s0");
90 ok(test_paths.length == 5, "List counter works correctly with appends");
91
92 mp_int_fs_list_set_best_match(test_paths, dummy_mount_list, false);
93 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
94 struct mount_entry *temp_me;
95 temp_me = p->best_match;
96 if (!strcmp(p->name, "/home/groups")) {
97 ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/groups got right best match: /home");
98 } else if (!strcmp(p->name, "/var")) {
99 ok(temp_me && !strcmp(temp_me->me_mountdir, "/var"), "/var got right best match: /var");
100 } else if (!strcmp(p->name, "/tmp")) {
101 ok(temp_me && !strcmp(temp_me->me_mountdir, "/"), "/tmp got right best match: /");
102 } else if (!strcmp(p->name, "/home/tonvoon")) {
103 ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/tonvoon got right best match: /home");
104 } else if (!strcmp(p->name, "/dev/c2t0d0s0")) {
105 ok(temp_me && !strcmp(temp_me->me_devname, "/dev/c2t0d0s0"), "/dev/c2t0d0s0 got right best match: /dev/c2t0d0s0");
106 }
107 }
108
109 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
110 mp_int_fs_list_del(&test_paths, p);
111 }
112 ok(test_paths.length == 0, "List delete sets counter properly");
113
114 mp_int_fs_list_append(&test_paths, "/home/groups");
115 mp_int_fs_list_append(&test_paths, "/var");
116 mp_int_fs_list_append(&test_paths, "/tmp");
117 mp_int_fs_list_append(&test_paths, "/home/tonvoon");
118 mp_int_fs_list_append(&test_paths, "/home");
119
120 mp_int_fs_list_set_best_match(test_paths, dummy_mount_list, true);
121 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
122 if (!strcmp(p->name, "/home/groups")) {
123 ok(!p->best_match, "/home/groups correctly not found");
124 } else if (!strcmp(p->name, "/var")) {
125 ok(p->best_match, "/var found");
126 } else if (!strcmp(p->name, "/tmp")) {
127 ok(!p->best_match, "/tmp correctly not found");
128 } else if (!strcmp(p->name, "/home/tonvoon")) {
129 ok(!p->best_match, "/home/tonvoon not found");
130 } else if (!strcmp(p->name, "/home")) {
131 ok(p->best_match, "/home found");
132 }
133 }
134
135 bool found = false;
136 /* test deleting first element in paths */
137 mp_int_fs_list_del(&test_paths, NULL);
138 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
139 if (!strcmp(p->name, "/home/groups")) {
140 found = true;
141 }
142 }
143 ok(!found, "first element successfully deleted");
144 found = false;
145
146 parameter_list_elem *prev = NULL;
147 parameter_list_elem *p = NULL;
148 for (parameter_list_elem *path = test_paths.first; path; path = mp_int_fs_list_get_next(path)) {
149 if (!strcmp(path->name, "/tmp")) {
150 mp_int_fs_list_del(&test_paths, path);
151 }
152 p = path;
153 }
154
155 parameter_list_elem *last = NULL;
156 for (parameter_list_elem *path = test_paths.first; path; path = mp_int_fs_list_get_next(path)) {
157 if (!strcmp(path->name, "/tmp")) {
158 found = true;
159 }
160 if (path->next) {
161 prev = path;
162 } else {
163 last = path;
164 }
165 }
166 ok(!found, "/tmp element successfully deleted");
167
168 int count = 0;
169 mp_int_fs_list_del(&test_paths, p);
170 for (p = test_paths.first; p; p = p->next) {
171 if (!strcmp(p->name, "/home")) {
172 found = true;
173 }
174 last = p;
175 count++;
176 }
177 ok(!found, "last (/home) element successfully deleted");
178 ok(count == 2, "two elements remaining");
179
180 return exit_status();
181}
182
183void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc) {
184 regex_t regex;
185 if (regcomp(&regex, regstr, cflags) == 0) {
186 int matches = 0;
187 for (struct mount_entry *me = dummy_mount_list; me; me = me->me_next) {
188 if (np_regex_match_mount_entry(me, &regex)) {
189 matches++;
190 }
191 }
192 ok(matches == expect, "%s '%s' matched %i/3 entries. ok: %i/3", desc, regstr, expect, matches);
193
194 } else {
195 ok(false, "regex '%s' not compilable", regstr);
196 }
197}
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_swap.c b/plugins/tests/test_check_swap.c
new file mode 100644
index 00000000..b85fb4ad
--- /dev/null
+++ b/plugins/tests/test_check_swap.c
@@ -0,0 +1,23 @@
1
2#include "../check_swap.d/check_swap.h"
3#include "../../tap/tap.h"
4
5int verbose = 0;
6
7void print_usage(void) {}
8void print_help(swap_config config) {
9 (void) config;
10}
11
12const char *progname = "test_check_swap";
13
14int main(void) {
15 swap_result test_data = getSwapFromProcMeminfo("./var/proc_meminfo");
16
17 plan_tests(4);
18
19 ok(test_data.errorcode == 0, "Test whether we manage to retrieve swap data");
20 ok(test_data.metrics.total == 34233905152, "Is the total Swap correct");
21 ok(test_data.metrics.free == 34233905152, "Is the free Swap correct");
22 ok(test_data.metrics.used == 0, "Is the used Swap correct");
23}
diff --git a/plugins/tests/test_check_swap.t b/plugins/tests/test_check_swap.t
new file mode 100755
index 00000000..826fae01
--- /dev/null
+++ b/plugins/tests/test_check_swap.t
@@ -0,0 +1,6 @@
1#!/usr/bin/perl
2use Test::More;
3if (! -e "./test_check_swap") {
4 plan skip_all => "./test_check_swap not compiled - please enable libtap library to test";
5}
6exec "./test_check_swap";
diff --git a/plugins/tests/var/proc_meminfo b/plugins/tests/var/proc_meminfo
new file mode 100644
index 00000000..6c5a618d
--- /dev/null
+++ b/plugins/tests/var/proc_meminfo
@@ -0,0 +1,55 @@
1MemTotal: 32767776 kB
2MemFree: 1693508 kB
3MemAvailable: 23807480 kB
4Buffers: 438456 kB
5Cached: 19124976 kB
6SwapCached: 0 kB
7Active: 7860680 kB
8Inactive: 18886776 kB
9Active(anon): 6108756 kB
10Inactive(anon): 1364500 kB
11Active(file): 1751924 kB
12Inactive(file): 17522276 kB
13Unevictable: 8548 kB
14Mlocked: 8548 kB
15SwapTotal: 33431548 kB
16SwapFree: 33431548 kB
17Zswap: 0 kB
18Zswapped: 0 kB
19Dirty: 784 kB
20Writeback: 0 kB
21AnonPages: 7139968 kB
22Mapped: 1094916 kB
23Shmem: 284160 kB
24KReclaimable: 3303788 kB
25Slab: 3801908 kB
26SReclaimable: 3303788 kB
27SUnreclaim: 498120 kB
28KernelStack: 32992 kB
29PageTables: 68160 kB
30SecPageTables: 0 kB
31NFS_Unstable: 0 kB
32Bounce: 0 kB
33WritebackTmp: 0 kB
34CommitLimit: 49815436 kB
35Committed_AS: 16888536 kB
36VmallocTotal: 34359738367 kB
37VmallocUsed: 91200 kB
38VmallocChunk: 0 kB
39Percpu: 41472 kB
40HardwareCorrupted: 0 kB
41AnonHugePages: 1708032 kB
42ShmemHugePages: 0 kB
43ShmemPmdMapped: 0 kB
44FileHugePages: 0 kB
45FilePmdMapped: 0 kB
46Unaccepted: 0 kB
47HugePages_Total: 0
48HugePages_Free: 0
49HugePages_Rsvd: 0
50HugePages_Surp: 0
51Hugepagesize: 2048 kB
52Hugetlb: 0 kB
53DirectMap4k: 860468 kB
54DirectMap2M: 20023296 kB
55DirectMap1G: 12582912 kB
diff --git a/plugins/urlize.c b/plugins/urlize.c
index 6fda72d1..1aa4e425 100644
--- a/plugins/urlize.c
+++ b/plugins/urlize.c
@@ -1,51 +1,49 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring urlize plugin 3 * Monitoring urlize plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2007 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 urlize plugin 10 * This file contains the urlize plugin
11* 11 *
12* This plugin wraps the text output of another command (plugin) in HTML <A> 12 * This plugin wraps the text output of another command (plugin) in HTML <A>
13* tags. This plugin returns the status of the invoked plugin. 13 * tags. This plugin returns the status of the invoked plugin.
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 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 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 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 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/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "urlize"; 32const char *progname = "urlize";
33const char *copyright = "2000-2006"; 33const char *copyright = "2000-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "common.h" 36#include "common.h"
37#include "utils.h" 37#include "utils.h"
38#include "popen.h" 38#include "popen.h"
39 39
40#define PERF_CHARACTER "|" 40#define PERF_CHARACTER "|"
41#define NEWLINE_CHARACTER '\n' 41#define NEWLINE_CHARACTER '\n'
42 42
43void print_help (void); 43void print_help(void);
44void print_usage (void); 44void print_usage(void);
45 45
46int 46int main(int argc, char **argv) {
47main (int argc, char **argv)
48{
49 int found = 0, result = STATE_UNKNOWN; 47 int found = 0, result = STATE_UNKNOWN;
50 char *url = NULL; 48 char *url = NULL;
51 char *cmd; 49 char *cmd;
@@ -56,79 +54,72 @@ main (int argc, char **argv)
56 int c; 54 int c;
57 int option = 0; 55 int option = 0;
58 static struct option longopts[] = { 56 static struct option longopts[] = {
59 {"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}};
60 {"version", no_argument, 0, 'V'},
61 {"url", required_argument, 0, 'u'},
62 {0, 0, 0, 0}
63 };
64 58
65 setlocale (LC_ALL, ""); 59 setlocale(LC_ALL, "");
66 bindtextdomain (PACKAGE, LOCALEDIR); 60 bindtextdomain(PACKAGE, LOCALEDIR);
67 textdomain (PACKAGE); 61 textdomain(PACKAGE);
68 62
69 /* Need at least 2 args */ 63 /* Need at least 2 args */
70 if (argc < 3) { 64 if (argc < 3) {
71 print_help(); 65 print_help();
72 exit (STATE_UNKNOWN); 66 exit(STATE_UNKNOWN);
73 } 67 }
74 68
75 while (1) { 69 while (1) {
76 c = getopt_long (argc, argv, "+hVu:", longopts, &option); 70 c = getopt_long(argc, argv, "+hVu:", longopts, &option);
77 71
78 if (c == -1 || c == EOF) 72 if (c == -1 || c == EOF)
79 break; 73 break;
80 74
81 switch (c) { 75 switch (c) {
82 case 'h': /* help */ 76 case 'h': /* help */
83 print_help (); 77 print_help();
84 exit (EXIT_SUCCESS); 78 exit(EXIT_SUCCESS);
85 break; 79 break;
86 case 'V': /* version */ 80 case 'V': /* version */
87 print_revision (progname, NP_VERSION); 81 print_revision(progname, NP_VERSION);
88 exit (EXIT_SUCCESS); 82 exit(EXIT_SUCCESS);
89 break; 83 break;
90 case 'u': 84 case 'u':
91 url = strdup (argv[optind]); 85 url = strdup(argv[optind]);
92 break; 86 break;
93 case '?': 87 case '?':
94 default: 88 default:
95 usage5 (); 89 usage5();
96 } 90 }
97 } 91 }
98 92
99 if (url == NULL) 93 if (url == NULL)
100 url = strdup (argv[optind++]); 94 url = strdup(argv[optind++]);
101 95
102 cmd = strdup (argv[optind++]); 96 cmd = strdup(argv[optind++]);
103 for (c = optind; c < argc; c++) { 97 for (c = optind; c < argc; c++) {
104 xasprintf (&cmd, "%s %s", cmd, argv[c]); 98 xasprintf(&cmd, "%s %s", cmd, argv[c]);
105 } 99 }
106 100
107 child_process = spopen (cmd); 101 child_process = spopen(cmd);
108 if (child_process == NULL) { 102 if (child_process == NULL) {
109 printf (_("Could not open pipe: %s\n"), cmd); 103 printf(_("Could not open pipe: %s\n"), cmd);
110 exit (STATE_UNKNOWN); 104 exit(STATE_UNKNOWN);
111 } 105 }
112 106
113 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); 107 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
114 if (child_stderr == NULL) { 108 if (child_stderr == NULL) {
115 printf (_("Could not open stderr for %s\n"), cmd); 109 printf(_("Could not open stderr for %s\n"), cmd);
116 } 110 }
117 111
118 bzero(tstr, sizeof(tstr)); 112 bzero(tstr, sizeof(tstr));
119 buf = malloc(MAX_INPUT_BUFFER); 113 buf = malloc(MAX_INPUT_BUFFER);
120 printf ("<A href=\"%s\">", argv[1]); 114 printf("<A href=\"%s\">", argv[1]);
121 while (fgets (buf, MAX_INPUT_BUFFER - 1, child_process)) { 115 while (fgets(buf, MAX_INPUT_BUFFER - 1, child_process)) {
122 found++; 116 found++;
123 /* Collect the string in temp str so we can tokenize */ 117 /* Collect the string in temp str so we can tokenize */
124 strcat(tstr, buf); 118 strcat(tstr, buf);
125 } 119 }
126 120
127 if (!found) 121 if (!found)
128 die (STATE_UNKNOWN, 122 die(STATE_UNKNOWN, _("%s UNKNOWN - No data received from host\nCMD: %s</A>\n"), argv[0], cmd);
129 _("%s UNKNOWN - No data received from host\nCMD: %s</A>\n"),
130 argv[0], cmd);
131
132 123
133 /* chop the newline character */ 124 /* chop the newline character */
134 if ((nstr = strchr(tstr, NEWLINE_CHARACTER)) != NULL) 125 if ((nstr = strchr(tstr, NEWLINE_CHARACTER)) != NULL)
@@ -136,63 +127,55 @@ main (int argc, char **argv)
136 127
137 /* tokenize the string for Perfdata if there is some */ 128 /* tokenize the string for Perfdata if there is some */
138 nstr = strtok(tstr, PERF_CHARACTER); 129 nstr = strtok(tstr, PERF_CHARACTER);
139 printf ("%s", nstr); 130 printf("%s", nstr);
140 printf ("</A>"); 131 printf("</A>");
141 nstr = strtok(NULL, PERF_CHARACTER); 132 nstr = strtok(NULL, PERF_CHARACTER);
142 if (nstr != NULL) 133 if (nstr != NULL)
143 printf (" | %s", nstr); 134 printf(" | %s", nstr);
144 135
145 /* close the pipe */ 136 /* close the pipe */
146 result = spclose (child_process); 137 result = spclose(child_process);
147 138
148 /* WARNING if output found on stderr */ 139 /* WARNING if output found on stderr */
149 if (fgets (buf, MAX_INPUT_BUFFER - 1, child_stderr)) 140 if (fgets(buf, MAX_INPUT_BUFFER - 1, child_stderr))
150 result = max_state (result, STATE_WARNING); 141 result = max_state(result, STATE_WARNING);
151 142
152 /* close stderr */ 143 /* close stderr */
153 (void) fclose (child_stderr); 144 (void)fclose(child_stderr);
154 145
155 return result; 146 return result;
156} 147}
157 148
149void print_help(void) {
150 print_revision(progname, NP_VERSION);
158 151
152 printf("Copyright (c) 2000 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n");
153 printf(COPYRIGHT, copyright, email);
159 154
160void 155 printf("%s\n", _("This plugin wraps the text output of another command (plugin) in HTML <A>"));
161print_help (void) 156 printf("%s\n", _("tags, thus displaying the child plugin's output as a clickable link in compatible"));
162{ 157 printf("%s\n", _("monitoring status screen. This plugin returns the status of the invoked plugin."));
163 print_revision (progname, NP_VERSION);
164
165 printf ("Copyright (c) 2000 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n");
166 printf (COPYRIGHT, copyright, email);
167
168 printf ("%s\n", _("This plugin wraps the text output of another command (plugin) in HTML <A>"));
169 printf ("%s\n", _("tags, thus displaying the child plugin's output as a clickable link in compatible"));
170 printf ("%s\n", _("monitoring status screen. This plugin returns the status of the invoked plugin."));
171 158
172 printf ("\n\n"); 159 printf("\n\n");
173 160
174 print_usage (); 161 print_usage();
175 162
176 printf (UT_HELP_VRSN); 163 printf(UT_HELP_VRSN);
177 164
178 printf ("\n"); 165 printf("\n");
179 printf ("%s\n", _("Examples:")); 166 printf("%s\n", _("Examples:"));
180 printf ("%s\n", _("Pay close attention to quoting to ensure that the shell passes the expected")); 167 printf("%s\n", _("Pay close attention to quoting to ensure that the shell passes the expected"));
181 printf ("%s\n\n", _("data to the plugin. For example, in:")); 168 printf("%s\n\n", _("data to the plugin. For example, in:"));
182 printf (" %s\n\n", _("urlize http://example.com/ check_http -H example.com -r 'two words'")); 169 printf(" %s\n\n", _("urlize http://example.com/ check_http -H example.com -r 'two words'"));
183 printf (" %s\n", _("the shell will remove the single quotes and urlize will see:")); 170 printf(" %s\n", _("the shell will remove the single quotes and urlize will see:"));
184 printf (" %s\n\n", _("urlize http://example.com/ check_http -H example.com -r two words")); 171 printf(" %s\n\n", _("urlize http://example.com/ check_http -H example.com -r two words"));
185 printf (" %s\n\n", _("You probably want:")); 172 printf(" %s\n\n", _("You probably want:"));
186 printf (" %s\n", _("urlize http://example.com/ \"check_http -H example.com -r 'two words'\"")); 173 printf(" %s\n", _("urlize http://example.com/ \"check_http -H example.com -r 'two words'\""));
187 174
188 printf (UT_SUPPORT); 175 printf(UT_SUPPORT);
189} 176}
190 177
191 178void print_usage(void) {
192 179 printf("%s\n", _("Usage:"));
193void 180 printf("%s <url> <plugin> <arg1> ... <argN>\n", progname);
194print_usage (void)
195{
196 printf ("%s\n", _("Usage:"));
197 printf ("%s <url> <plugin> <arg1> ... <argN>\n", progname);
198} 181}
diff --git a/plugins/utils.c b/plugins/utils.c
index 77d6a6f9..34335c89 100644
--- a/plugins/utils.c
+++ b/plugins/utils.c
@@ -1,26 +1,26 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Library of useful functions for plugins 3 * Library of useful functions for plugins
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000 Karl DeBisschop (karl@debisschop.net) 6 * Copyright (c) 2000 Karl DeBisschop (karl@debisschop.net)
7* Copyright (c) 2002-2007 Monitoring Plugins Development Team 7 * Copyright (c) 2002-2024 Monitoring Plugins Development Team
8* 8 *
9* This program is free software: you can redistribute it and/or modify 9 * This program is free software: you can redistribute it and/or modify
10* it under the terms of the GNU General Public License as published by 10 * it under the terms of the GNU General Public License as published by
11* the Free Software Foundation, either version 3 of the License, or 11 * the Free Software Foundation, either version 3 of the License, or
12* (at your option) any later version. 12 * (at your option) any later version.
13* 13 *
14* This program is distributed in the hope that it will be useful, 14 * This program is distributed in the hope that it will be useful,
15* but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17* GNU General Public License for more details. 17 * GNU General Public License for more details.
18* 18 *
19* You should have received a copy of the GNU General Public License 19 * You should have received a copy of the GNU General Public License
20* along with this program. If not, see <http://www.gnu.org/licenses/>. 20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21* 21 *
22* 22 *
23*****************************************************************************/ 23 *****************************************************************************/
24 24
25#include "common.h" 25#include "common.h"
26#include "./utils.h" 26#include "./utils.h"
@@ -34,7 +34,7 @@
34 34
35#include <arpa/inet.h> 35#include <arpa/inet.h>
36 36
37extern void print_usage (void); 37extern void print_usage(void);
38extern const char *progname; 38extern const char *progname;
39 39
40#define STRLEN 64 40#define STRLEN 64
@@ -42,173 +42,114 @@ extern const char *progname;
42 42
43time_t start_time, end_time; 43time_t start_time, end_time;
44 44
45/* ************************************************************************** 45void usage(const char *msg) {
46 * max_state(STATE_x, STATE_y) 46 printf("%s\n", msg);
47 * compares STATE_x to STATE_y and returns result based on the following 47 print_usage();
48 * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL 48 exit(STATE_UNKNOWN);
49 * 49}
50 * Note that numerically the above does not hold 50
51 ****************************************************************************/ 51void usage_va(const char *fmt, ...) {
52
53int
54max_state (int a, int b)
55{
56 if (a == STATE_CRITICAL || b == STATE_CRITICAL)
57 return STATE_CRITICAL;
58 else if (a == STATE_WARNING || b == STATE_WARNING)
59 return STATE_WARNING;
60 else if (a == STATE_OK || b == STATE_OK)
61 return STATE_OK;
62 else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN)
63 return STATE_UNKNOWN;
64 else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT)
65 return STATE_DEPENDENT;
66 else
67 return max (a, b);
68}
69
70/* **************************************************************************
71 * max_state_alt(STATE_x, STATE_y)
72 * compares STATE_x to STATE_y and returns result based on the following
73 * STATE_OK < STATE_DEPENDENT < STATE_UNKNOWN < STATE_WARNING < STATE_CRITICAL
74 *
75 * The main difference between max_state_alt and max_state it that it doesn't
76 * allow setting a default to UNKNOWN. It will instead prioritixe any valid
77 * non-OK state.
78 ****************************************************************************/
79
80int
81max_state_alt (int a, int b)
82{
83 if (a == STATE_CRITICAL || b == STATE_CRITICAL)
84 return STATE_CRITICAL;
85 else if (a == STATE_WARNING || b == STATE_WARNING)
86 return STATE_WARNING;
87 else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN)
88 return STATE_UNKNOWN;
89 else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT)
90 return STATE_DEPENDENT;
91 else if (a == STATE_OK || b == STATE_OK)
92 return STATE_OK;
93 else
94 return max (a, b);
95}
96
97void usage (const char *msg)
98{
99 printf ("%s\n", msg);
100 print_usage ();
101 exit (STATE_UNKNOWN);
102}
103
104void usage_va (const char *fmt, ...)
105{
106 va_list ap; 52 va_list ap;
107 printf("%s: ", progname); 53 printf("%s: ", progname);
108 va_start(ap, fmt); 54 va_start(ap, fmt);
109 vprintf(fmt, ap); 55 vprintf(fmt, ap);
110 va_end(ap); 56 va_end(ap);
111 printf("\n"); 57 printf("\n");
112 exit (STATE_UNKNOWN); 58 exit(STATE_UNKNOWN);
113} 59}
114 60
115void usage2(const char *msg, const char *arg) 61void usage2(const char *msg, const char *arg) {
116{ 62 printf("%s: %s - %s\n", progname, msg, arg ? arg : "(null)");
117 printf ("%s: %s - %s\n", progname, msg, arg?arg:"(null)" ); 63 print_usage();
118 print_usage (); 64 exit(STATE_UNKNOWN);
119 exit (STATE_UNKNOWN);
120} 65}
121 66
122void 67void usage3(const char *msg, int arg) {
123usage3 (const char *msg, int arg) 68 printf("%s: %s - %c\n", progname, msg, arg);
124{
125 printf ("%s: %s - %c\n", progname, msg, arg);
126 print_usage(); 69 print_usage();
127 exit (STATE_UNKNOWN); 70 exit(STATE_UNKNOWN);
128} 71}
129 72
130void 73void usage4(const char *msg) {
131usage4 (const char *msg) 74 printf("%s: %s\n", progname, msg);
132{
133 printf ("%s: %s\n", progname, msg);
134 print_usage(); 75 print_usage();
135 exit (STATE_UNKNOWN); 76 exit(STATE_UNKNOWN);
136} 77}
137 78
138void 79void usage5(void) {
139usage5 (void)
140{
141 print_usage(); 80 print_usage();
142 exit (STATE_UNKNOWN); 81 exit(STATE_UNKNOWN);
143} 82}
144 83
145void 84void print_revision(const char *command_name, const char *revision) {
146print_revision (const char *command_name, const char *revision) 85 printf("%s v%s (%s %s)\n", command_name, revision, PACKAGE, VERSION);
147{
148 printf ("%s v%s (%s %s)\n",
149 command_name, revision, PACKAGE, VERSION);
150} 86}
151 87
152bool is_numeric (char *number) { 88bool is_numeric(char *number) {
153 char tmp[1]; 89 char tmp[1];
154 float x; 90 float x;
155 91
156 if (!number) 92 if (!number) {
157 return false; 93 return false;
158 else if (sscanf (number, "%f%c", &x, tmp) == 1) 94 } else if (sscanf(number, "%f%c", &x, tmp) == 1) {
159 return true; 95 return true;
160 else 96 } else {
161 return false; 97 return false;
98 }
162} 99}
163 100
164bool is_positive (char *number) { 101bool is_positive(char *number) {
165 if (is_numeric (number) && atof (number) > 0.0) 102 if (is_numeric(number) && atof(number) > 0.0) {
166 return true; 103 return true;
167 else 104 } else {
168 return false; 105 return false;
106 }
169} 107}
170 108
171bool is_negative (char *number) { 109bool is_negative(char *number) {
172 if (is_numeric (number) && atof (number) < 0.0) 110 if (is_numeric(number) && atof(number) < 0.0) {
173 return true; 111 return true;
174 else 112 } else {
175 return false; 113 return false;
114 }
176} 115}
177 116
178bool is_nonnegative (char *number) { 117bool is_nonnegative(char *number) {
179 if (is_numeric (number) && atof (number) >= 0.0) 118 if (is_numeric(number) && atof(number) >= 0.0) {
180 return true; 119 return true;
181 else 120 } else {
182 return false; 121 return false;
122 }
183} 123}
184 124
185bool is_percentage (char *number) { 125bool is_percentage(char *number) {
186 int x; 126 int x;
187 if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100) 127 if (is_numeric(number) && (x = atof(number)) >= 0 && x <= 100) {
188 return true; 128 return true;
189 else 129 } else {
190 return false; 130 return false;
131 }
191} 132}
192 133
193bool is_percentage_expression (const char str[]) { 134bool is_percentage_expression(const char str[]) {
194 if (!str) { 135 if (!str) {
195 return false; 136 return false;
196 } 137 }
197 138
198 size_t len = strlen(str); 139 size_t len = strlen(str);
199 140
200 if (str[len-1] != '%') { 141 if (str[len - 1] != '%') {
201 return false; 142 return false;
202 } 143 }
203 144
204 char *foo = calloc(sizeof(char), len + 1); 145 char *foo = calloc(len + 1, sizeof(char));
205 146
206 if (!foo) { 147 if (!foo) {
207 die (STATE_UNKNOWN, _("calloc failed \n")); 148 die(STATE_UNKNOWN, _("calloc failed \n"));
208 } 149 }
209 150
210 strcpy(foo, str); 151 strcpy(foo, str);
211 foo[len-1] = '\0'; 152 foo[len - 1] = '\0';
212 153
213 bool result = is_numeric(foo); 154 bool result = is_numeric(foo);
214 155
@@ -217,39 +158,44 @@ bool is_percentage_expression (const char str[]) {
217 return result; 158 return result;
218} 159}
219 160
220bool is_integer (char *number) { 161bool is_integer(char *number) {
221 long int n; 162 long int n;
222 163
223 if (!number || (strspn (number, "-0123456789 ") != strlen (number))) 164 if (!number || (strspn(number, "-0123456789 ") != strlen(number))) {
224 return false; 165 return false;
166 }
225 167
226 n = strtol (number, NULL, 10); 168 n = strtol(number, NULL, 10);
227 169
228 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX) 170 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX) {
229 return true; 171 return true;
230 else 172 } else {
231 return false; 173 return false;
174 }
232} 175}
233 176
234bool is_intpos (char *number) { 177bool is_intpos(char *number) {
235 if (is_integer (number) && atoi (number) > 0) 178 if (is_integer(number) && atoi(number) > 0) {
236 return true; 179 return true;
237 else 180 } else {
238 return false; 181 return false;
182 }
239} 183}
240 184
241bool is_intneg (char *number) { 185bool is_intneg(char *number) {
242 if (is_integer (number) && atoi (number) < 0) 186 if (is_integer(number) && atoi(number) < 0) {
243 return true; 187 return true;
244 else 188 } else {
245 return false; 189 return false;
190 }
246} 191}
247 192
248bool is_intnonneg (char *number) { 193bool is_intnonneg(char *number) {
249 if (is_integer (number) && atoi (number) >= 0) 194 if (is_integer(number) && atoi(number) >= 0) {
250 return true; 195 return true;
251 else 196 } else {
252 return false; 197 return false;
198 }
253} 199}
254 200
255/* 201/*
@@ -259,7 +205,7 @@ bool is_intnonneg (char *number) {
259 */ 205 */
260bool is_int64(char *number, int64_t *target) { 206bool is_int64(char *number, int64_t *target) {
261 errno = 0; 207 errno = 0;
262 char *endptr = { 0 }; 208 char *endptr = {0};
263 209
264 int64_t tmp = strtoll(number, &endptr, 10); 210 int64_t tmp = strtoll(number, &endptr, 10);
265 if (errno != 0) { 211 if (errno != 0) {
@@ -287,7 +233,7 @@ bool is_int64(char *number, int64_t *target) {
287 */ 233 */
288bool is_uint64(char *number, uint64_t *target) { 234bool is_uint64(char *number, uint64_t *target) {
289 errno = 0; 235 errno = 0;
290 char *endptr = { 0 }; 236 char *endptr = {0};
291 unsigned long long tmp = strtoull(number, &endptr, 10); 237 unsigned long long tmp = strtoull(number, &endptr, 10);
292 238
293 if (errno != 0) { 239 if (errno != 0) {
@@ -309,74 +255,60 @@ bool is_uint64(char *number, uint64_t *target) {
309 return true; 255 return true;
310} 256}
311 257
312bool is_intpercent (char *number) { 258bool is_intpercent(char *number) {
313 int i; 259 int i;
314 if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100) 260 if (is_integer(number) && (i = atoi(number)) >= 0 && i <= 100) {
315 return true; 261 return true;
316 else 262 } else {
317 return false; 263 return false;
264 }
318} 265}
319 266
320bool is_option (char *str) { 267bool is_option(char *str) {
321 if (!str) 268 if (!str) {
322 return false; 269 return false;
323 else if (strspn (str, "-") == 1 || strspn (str, "-") == 2) 270 } else if (strspn(str, "-") == 1 || strspn(str, "-") == 2) {
324 return true; 271 return true;
325 else 272 } else {
326 return false; 273 return false;
274 }
327} 275}
328 276
329#ifdef NEED_GETTIMEOFDAY 277#ifdef NEED_GETTIMEOFDAY
330int 278int gettimeofday(struct timeval *tv, struct timezone *tz) {
331gettimeofday (struct timeval *tv, struct timezone *tz)
332{
333 tv->tv_usec = 0; 279 tv->tv_usec = 0;
334 tv->tv_sec = (long) time ((time_t) 0); 280 tv->tv_sec = (long)time((time_t)0);
335} 281}
336#endif 282#endif
337 283
338 284double delta_time(struct timeval tv) {
339
340double
341delta_time (struct timeval tv)
342{
343 struct timeval now; 285 struct timeval now;
344 286
345 gettimeofday (&now, NULL); 287 gettimeofday(&now, NULL);
346 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) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
347} 289}
348 290
349 291long deltime(struct timeval tv) {
350
351long
352deltime (struct timeval tv)
353{
354 struct timeval now; 292 struct timeval now;
355 gettimeofday (&now, NULL); 293 gettimeofday(&now, NULL);
356 return (now.tv_sec - tv.tv_sec)*1000000 + now.tv_usec - tv.tv_usec; 294 return (now.tv_sec - tv.tv_sec) * 1000000 + now.tv_usec - tv.tv_usec;
357} 295}
358 296
359 297void strip(char *buffer) {
360
361
362void
363strip (char *buffer)
364{
365 size_t x; 298 size_t x;
366 int i; 299 int i;
367 300
368 for (x = strlen (buffer); x >= 1; x--) { 301 for (x = strlen(buffer); x >= 1; x--) {
369 i = x - 1; 302 i = x - 1;
370 if (buffer[i] == ' ' || 303 if (buffer[i] == ' ' || buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t') {
371 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
372 buffer[i] = '\0'; 304 buffer[i] = '\0';
373 else 305 } else {
374 break; 306 break;
307 }
375 } 308 }
376 return; 309 return;
377} 310}
378 311
379
380/****************************************************************************** 312/******************************************************************************
381 * 313 *
382 * Copies one string to another. Any previously existing data in 314 * Copies one string to another. Any previously existing data in
@@ -389,19 +321,16 @@ strip (char *buffer)
389 * 321 *
390 *****************************************************************************/ 322 *****************************************************************************/
391 323
392char * 324char *strscpy(char *dest, const char *src) {
393strscpy (char *dest, const char *src) 325 if (src == NULL) {
394{
395 if (src == NULL)
396 return NULL; 326 return NULL;
327 }
397 328
398 xasprintf (&dest, "%s", src); 329 xasprintf(&dest, "%s", src);
399 330
400 return dest; 331 return dest;
401} 332}
402 333
403
404
405/****************************************************************************** 334/******************************************************************************
406 * 335 *
407 * Returns a pointer to the next line of a multiline string buffer 336 * Returns a pointer to the next line of a multiline string buffer
@@ -418,7 +347,7 @@ strscpy (char *dest, const char *src)
418 * This 347 * This
419 * is 348 * is
420 * a 349 * a
421 * 350 *
422 * multiline string buffer 351 * multiline string buffer
423 * ============================== 352 * ==============================
424 * 353 *
@@ -431,7 +360,7 @@ strscpy (char *dest, const char *src)
431 * printf("%d %s",i++,firstword(ptr)); 360 * printf("%d %s",i++,firstword(ptr));
432 * ptr = strnl(ptr); 361 * ptr = strnl(ptr);
433 * } 362 * }
434 * 363 *
435 * Produces the following: 364 * Produces the following:
436 * 365 *
437 * 1 This 366 * 1 This
@@ -452,25 +381,26 @@ strscpy (char *dest, const char *src)
452 * 381 *
453 *****************************************************************************/ 382 *****************************************************************************/
454 383
455char * 384char *strnl(char *str) {
456strnl (char *str)
457{
458 size_t len; 385 size_t len;
459 if (str == NULL) 386 if (str == NULL) {
460 return NULL; 387 return NULL;
461 str = strpbrk (str, "\r\n"); 388 }
462 if (str == NULL) 389 str = strpbrk(str, "\r\n");
390 if (str == NULL) {
463 return NULL; 391 return NULL;
464 len = strspn (str, "\r\n"); 392 }
465 if (str[len] == '\0') 393 len = strspn(str, "\r\n");
394 if (str[len] == '\0') {
466 return NULL; 395 return NULL;
396 }
467 str += len; 397 str += len;
468 if (strlen (str) == 0) 398 if (strlen(str) == 0) {
469 return NULL; 399 return NULL;
400 }
470 return str; 401 return str;
471} 402}
472 403
473
474/****************************************************************************** 404/******************************************************************************
475 * 405 *
476 * Like strscpy, except only the portion of the source string up to 406 * Like strscpy, except only the portion of the source string up to
@@ -487,29 +417,28 @@ strnl (char *str)
487 * 417 *
488 *****************************************************************************/ 418 *****************************************************************************/
489 419
490char * 420char *strpcpy(char *dest, const char *src, const char *str) {
491strpcpy (char *dest, const char *src, const char *str)
492{
493 size_t len; 421 size_t len;
494 422
495 if (src) 423 if (src) {
496 len = strcspn (src, str); 424 len = strcspn(src, str);
497 else 425 } else {
498 return NULL; 426 return NULL;
427 }
499 428
500 if (dest == NULL || strlen (dest) < len) 429 if (dest == NULL || strlen(dest) < len) {
501 dest = realloc (dest, len + 1); 430 dest = realloc(dest, len + 1);
502 if (dest == NULL) 431 }
503 die (STATE_UNKNOWN, _("failed realloc in strpcpy\n")); 432 if (dest == NULL) {
433 die(STATE_UNKNOWN, _("failed realloc in strpcpy\n"));
434 }
504 435
505 strncpy (dest, src, len); 436 strncpy(dest, src, len);
506 dest[len] = '\0'; 437 dest[len] = '\0';
507 438
508 return dest; 439 return dest;
509} 440}
510 441
511
512
513/****************************************************************************** 442/******************************************************************************
514 * 443 *
515 * Like strscat, except only the portion of the source string up to 444 * Like strscat, except only the portion of the source string up to
@@ -518,62 +447,57 @@ strpcpy (char *dest, const char *src, const char *str)
518 * str = strpcpy(str,"This is a line of text with no trailing newline","x"); 447 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
519 * str = strpcat(str,"This is a line of text with no trailing newline","x"); 448 * str = strpcat(str,"This is a line of text with no trailing newline","x");
520 * printf("%s\n",str); 449 * printf("%s\n",str);
521 * 450 *
522 *This is a line of texThis is a line of tex 451 *This is a line of texThis is a line of tex
523 * 452 *
524 *****************************************************************************/ 453 *****************************************************************************/
525 454
526char * 455char *strpcat(char *dest, const char *src, const char *str) {
527strpcat (char *dest, const char *src, const char *str)
528{
529 size_t len, l2; 456 size_t len, l2;
530 457
531 if (dest) 458 if (dest) {
532 len = strlen (dest); 459 len = strlen(dest);
533 else 460 } else {
534 len = 0; 461 len = 0;
462 }
535 463
536 if (src) { 464 if (src) {
537 l2 = strcspn (src, str); 465 l2 = strcspn(src, str);
538 } 466 } else {
539 else {
540 return dest; 467 return dest;
541 } 468 }
542 469
543 dest = realloc (dest, len + l2 + 1); 470 dest = realloc(dest, len + l2 + 1);
544 if (dest == NULL) 471 if (dest == NULL) {
545 die (STATE_UNKNOWN, _("failed malloc in strscat\n")); 472 die(STATE_UNKNOWN, _("failed malloc in strscat\n"));
473 }
546 474
547 strncpy (dest + len, src, l2); 475 strncpy(dest + len, src, l2);
548 dest[len + l2] = '\0'; 476 dest[len + l2] = '\0';
549 477
550 return dest; 478 return dest;
551} 479}
552 480
553
554/****************************************************************************** 481/******************************************************************************
555 * 482 *
556 * asprintf, but die on failure 483 * asprintf, but die on failure
557 * 484 *
558 ******************************************************************************/ 485 ******************************************************************************/
559 486
560int 487int xvasprintf(char **strp, const char *fmt, va_list ap) {
561xvasprintf (char **strp, const char *fmt, va_list ap) 488 int result = vasprintf(strp, fmt, ap);
562{ 489 if (result == -1 || *strp == NULL) {
563 int result = vasprintf (strp, fmt, ap); 490 die(STATE_UNKNOWN, _("failed malloc in xvasprintf\n"));
564 if (result == -1 || *strp == NULL) 491 }
565 die (STATE_UNKNOWN, _("failed malloc in xvasprintf\n"));
566 return result; 492 return result;
567} 493}
568 494
569int 495int xasprintf(char **strp, const char *fmt, ...) {
570xasprintf (char **strp, const char *fmt, ...)
571{
572 va_list ap; 496 va_list ap;
573 int result; 497 int result;
574 va_start (ap, fmt); 498 va_start(ap, fmt);
575 result = xvasprintf (strp, fmt, ap); 499 result = xvasprintf(strp, fmt, ap);
576 va_end (ap); 500 va_end(ap);
577 return result; 501 return result;
578} 502}
579 503
@@ -583,247 +507,219 @@ xasprintf (char **strp, const char *fmt, ...)
583 * 507 *
584 ******************************************************************************/ 508 ******************************************************************************/
585 509
586char *perfdata (const char *label, 510char *perfdata(const char *label, long int val, const char *uom, bool warnp, long int warn, bool critp, long int crit, bool minp,
587 long int val, 511 long int minv, bool maxp, long int maxv) {
588 const char *uom,
589 int warnp,
590 long int warn,
591 int critp,
592 long int crit,
593 int minp,
594 long int minv,
595 int maxp,
596 long int maxv)
597{
598 char *data = NULL; 512 char *data = NULL;
599 513
600 if (strpbrk (label, "'= ")) 514 if (strpbrk(label, "'= ")) {
601 xasprintf (&data, "'%s'=%ld%s;", label, val, uom); 515 xasprintf(&data, "'%s'=%ld%s;", label, val, uom);
602 else 516 } else {
603 xasprintf (&data, "%s=%ld%s;", label, val, uom); 517 xasprintf(&data, "%s=%ld%s;", label, val, uom);
518 }
604 519
605 if (warnp) 520 if (warnp) {
606 xasprintf (&data, "%s%ld;", data, warn); 521 xasprintf(&data, "%s%ld;", data, warn);
607 else 522 } else {
608 xasprintf (&data, "%s;", data); 523 xasprintf(&data, "%s;", data);
524 }
609 525
610 if (critp) 526 if (critp) {
611 xasprintf (&data, "%s%ld;", data, crit); 527 xasprintf(&data, "%s%ld;", data, crit);
612 else 528 } else {
613 xasprintf (&data, "%s;", data); 529 xasprintf(&data, "%s;", data);
530 }
614 531
615 if (minp) 532 if (minp) {
616 xasprintf (&data, "%s%ld;", data, minv); 533 xasprintf(&data, "%s%ld;", data, minv);
617 else 534 } else {
618 xasprintf (&data, "%s;", data); 535 xasprintf(&data, "%s;", data);
536 }
619 537
620 if (maxp) 538 if (maxp) {
621 xasprintf (&data, "%s%ld", data, maxv); 539 xasprintf(&data, "%s%ld", data, maxv);
540 }
622 541
623 return data; 542 return data;
624} 543}
625 544
626 545char *perfdata_uint64(const char *label, uint64_t val, const char *uom, bool warnp, /* Warning present */
627char *perfdata_uint64 (const char *label, 546 uint64_t warn, bool critp, /* Critical present */
628 uint64_t val, 547 uint64_t crit, bool minp, /* Minimum present */
629 const char *uom, 548 uint64_t minv, bool maxp, /* Maximum present */
630 int warnp, /* Warning present */ 549 uint64_t maxv) {
631 uint64_t warn,
632 int critp, /* Critical present */
633 uint64_t crit,
634 int minp, /* Minimum present */
635 uint64_t minv,
636 int maxp, /* Maximum present */
637 uint64_t maxv)
638{
639 char *data = NULL; 550 char *data = NULL;
640 551
641 if (strpbrk (label, "'= ")) 552 if (strpbrk(label, "'= ")) {
642 xasprintf (&data, "'%s'=%" PRIu64 "%s;", label, val, uom); 553 xasprintf(&data, "'%s'=%" PRIu64 "%s;", label, val, uom);
643 else 554 } else {
644 xasprintf (&data, "%s=%" PRIu64 "%s;", label, val, uom); 555 xasprintf(&data, "%s=%" PRIu64 "%s;", label, val, uom);
556 }
645 557
646 if (warnp) 558 if (warnp) {
647 xasprintf (&data, "%s%" PRIu64 ";", data, warn); 559 xasprintf(&data, "%s%" PRIu64 ";", data, warn);
648 else 560 } else {
649 xasprintf (&data, "%s;", data); 561 xasprintf(&data, "%s;", data);
562 }
650 563
651 if (critp) 564 if (critp) {
652 xasprintf (&data, "%s%" PRIu64 ";", data, crit); 565 xasprintf(&data, "%s%" PRIu64 ";", data, crit);
653 else 566 } else {
654 xasprintf (&data, "%s;", data); 567 xasprintf(&data, "%s;", data);
568 }
655 569
656 if (minp) 570 if (minp) {
657 xasprintf (&data, "%s%" PRIu64 ";", data, minv); 571 xasprintf(&data, "%s%" PRIu64 ";", data, minv);
658 else 572 } else {
659 xasprintf (&data, "%s;", data); 573 xasprintf(&data, "%s;", data);
574 }
660 575
661 if (maxp) 576 if (maxp) {
662 xasprintf (&data, "%s%" PRIu64, data, maxv); 577 xasprintf(&data, "%s%" PRIu64, data, maxv);
578 }
663 579
664 return data; 580 return data;
665} 581}
666 582
667 583char *perfdata_int64(const char *label, int64_t val, const char *uom, bool warnp, /* Warning present */
668char *perfdata_int64 (const char *label, 584 int64_t warn, bool critp, /* Critical present */
669 int64_t val, 585 int64_t crit, bool minp, /* Minimum present */
670 const char *uom, 586 int64_t minv, bool maxp, /* Maximum present */
671 int warnp, /* Warning present */ 587 int64_t maxv) {
672 int64_t warn,
673 int critp, /* Critical present */
674 int64_t crit,
675 int minp, /* Minimum present */
676 int64_t minv,
677 int maxp, /* Maximum present */
678 int64_t maxv)
679{
680 char *data = NULL; 588 char *data = NULL;
681 589
682 if (strpbrk (label, "'= ")) 590 if (strpbrk(label, "'= ")) {
683 xasprintf (&data, "'%s'=%" PRId64 "%s;", label, val, uom); 591 xasprintf(&data, "'%s'=%" PRId64 "%s;", label, val, uom);
684 else 592 } else {
685 xasprintf (&data, "%s=%" PRId64 "%s;", label, val, uom); 593 xasprintf(&data, "%s=%" PRId64 "%s;", label, val, uom);
594 }
686 595
687 if (warnp) 596 if (warnp) {
688 xasprintf (&data, "%s%" PRId64 ";", data, warn); 597 xasprintf(&data, "%s%" PRId64 ";", data, warn);
689 else 598 } else {
690 xasprintf (&data, "%s;", data); 599 xasprintf(&data, "%s;", data);
600 }
691 601
692 if (critp) 602 if (critp) {
693 xasprintf (&data, "%s%" PRId64 ";", data, crit); 603 xasprintf(&data, "%s%" PRId64 ";", data, crit);
694 else 604 } else {
695 xasprintf (&data, "%s;", data); 605 xasprintf(&data, "%s;", data);
606 }
696 607
697 if (minp) 608 if (minp) {
698 xasprintf (&data, "%s%" PRId64 ";", data, minv); 609 xasprintf(&data, "%s%" PRId64 ";", data, minv);
699 else 610 } else {
700 xasprintf (&data, "%s;", data); 611 xasprintf(&data, "%s;", data);
612 }
701 613
702 if (maxp) 614 if (maxp) {
703 xasprintf (&data, "%s%" PRId64, data, maxv); 615 xasprintf(&data, "%s%" PRId64, data, maxv);
616 }
704 617
705 return data; 618 return data;
706} 619}
707 620
708 621char *fperfdata(const char *label, double val, const char *uom, bool warnp, double warn, bool critp, double crit, bool minp, double minv,
709char *fperfdata (const char *label, 622 bool maxp, double maxv) {
710 double val,
711 const char *uom,
712 int warnp,
713 double warn,
714 int critp,
715 double crit,
716 int minp,
717 double minv,
718 int maxp,
719 double maxv)
720{
721 char *data = NULL; 623 char *data = NULL;
722 624
723 if (strpbrk (label, "'= ")) 625 if (strpbrk(label, "'= ")) {
724 xasprintf (&data, "'%s'=", label); 626 xasprintf(&data, "'%s'=", label);
725 else 627 } else {
726 xasprintf (&data, "%s=", label); 628 xasprintf(&data, "%s=", label);
629 }
727 630
728 xasprintf (&data, "%s%f", data, val); 631 xasprintf(&data, "%s%f", data, val);
729 xasprintf (&data, "%s%s;", data, uom); 632 xasprintf(&data, "%s%s;", data, uom);
730 633
731 if (warnp) 634 if (warnp) {
732 xasprintf (&data, "%s%f", data, warn); 635 xasprintf(&data, "%s%f", data, warn);
636 }
733 637
734 xasprintf (&data, "%s;", data); 638 xasprintf(&data, "%s;", data);
735 639
736 if (critp) 640 if (critp) {
737 xasprintf (&data, "%s%f", data, crit); 641 xasprintf(&data, "%s%f", data, crit);
642 }
738 643
739 xasprintf (&data, "%s;", data); 644 xasprintf(&data, "%s;", data);
740 645
741 if (minp) 646 if (minp) {
742 xasprintf (&data, "%s%f", data, minv); 647 xasprintf(&data, "%s%f", data, minv);
648 }
743 649
744 if (maxp) { 650 if (maxp) {
745 xasprintf (&data, "%s;", data); 651 xasprintf(&data, "%s;", data);
746 xasprintf (&data, "%s%f", data, maxv); 652 xasprintf(&data, "%s%f", data, maxv);
747 } 653 }
748 654
749 return data; 655 return data;
750} 656}
751 657
752char *sperfdata (const char *label, 658char *sperfdata(const char *label, double val, const char *uom, char *warn, char *crit, bool minp, double minv, bool maxp, double maxv) {
753 double val,
754 const char *uom,
755 char *warn,
756 char *crit,
757 int minp,
758 double minv,
759 int maxp,
760 double maxv)
761{
762 char *data = NULL; 659 char *data = NULL;
763 if (strpbrk (label, "'= ")) 660 if (strpbrk(label, "'= ")) {
764 xasprintf (&data, "'%s'=", label); 661 xasprintf(&data, "'%s'=", label);
765 else 662 } else {
766 xasprintf (&data, "%s=", label); 663 xasprintf(&data, "%s=", label);
664 }
767 665
768 xasprintf (&data, "%s%f", data, val); 666 xasprintf(&data, "%s%f", data, val);
769 xasprintf (&data, "%s%s;", data, uom); 667 xasprintf(&data, "%s%s;", data, uom);
770 668
771 if (warn!=NULL) 669 if (warn != NULL) {
772 xasprintf (&data, "%s%s", data, warn); 670 xasprintf(&data, "%s%s", data, warn);
671 }
773 672
774 xasprintf (&data, "%s;", data); 673 xasprintf(&data, "%s;", data);
775 674
776 if (crit!=NULL) 675 if (crit != NULL) {
777 xasprintf (&data, "%s%s", data, crit); 676 xasprintf(&data, "%s%s", data, crit);
677 }
778 678
779 xasprintf (&data, "%s;", data); 679 xasprintf(&data, "%s;", data);
780 680
781 if (minp) 681 if (minp) {
782 xasprintf (&data, "%s%f", data, minv); 682 xasprintf(&data, "%s%f", data, minv);
683 }
783 684
784 if (maxp) { 685 if (maxp) {
785 xasprintf (&data, "%s;", data); 686 xasprintf(&data, "%s;", data);
786 xasprintf (&data, "%s%f", data, maxv); 687 xasprintf(&data, "%s%f", data, maxv);
787 } 688 }
788 689
789 return data; 690 return data;
790} 691}
791 692
792char *sperfdata_int (const char *label, 693char *sperfdata_int(const char *label, int val, const char *uom, char *warn, char *crit, bool minp, int minv, bool maxp, int maxv) {
793 int val,
794 const char *uom,
795 char *warn,
796 char *crit,
797 int minp,
798 int minv,
799 int maxp,
800 int maxv)
801{
802 char *data = NULL; 694 char *data = NULL;
803 if (strpbrk (label, "'= ")) 695 if (strpbrk(label, "'= ")) {
804 xasprintf (&data, "'%s'=", label); 696 xasprintf(&data, "'%s'=", label);
805 else 697 } else {
806 xasprintf (&data, "%s=", label); 698 xasprintf(&data, "%s=", label);
699 }
807 700
808 xasprintf (&data, "%s%d", data, val); 701 xasprintf(&data, "%s%d", data, val);
809 xasprintf (&data, "%s%s;", data, uom); 702 xasprintf(&data, "%s%s;", data, uom);
810 703
811 if (warn!=NULL) 704 if (warn != NULL) {
812 xasprintf (&data, "%s%s", data, warn); 705 xasprintf(&data, "%s%s", data, warn);
706 }
813 707
814 xasprintf (&data, "%s;", data); 708 xasprintf(&data, "%s;", data);
815 709
816 if (crit!=NULL) 710 if (crit != NULL) {
817 xasprintf (&data, "%s%s", data, crit); 711 xasprintf(&data, "%s%s", data, crit);
712 }
818 713
819 xasprintf (&data, "%s;", data); 714 xasprintf(&data, "%s;", data);
820 715
821 if (minp) 716 if (minp) {
822 xasprintf (&data, "%s%d", data, minv); 717 xasprintf(&data, "%s%d", data, minv);
718 }
823 719
824 if (maxp) { 720 if (maxp) {
825 xasprintf (&data, "%s;", data); 721 xasprintf(&data, "%s;", data);
826 xasprintf (&data, "%s%d", data, maxv); 722 xasprintf(&data, "%s%d", data, maxv);
827 } 723 }
828 724
829 return data; 725 return data;
diff --git a/plugins/utils.h b/plugins/utils.h
index f939e337..1d3c153c 100644
--- a/plugins/utils.h
+++ b/plugins/utils.h
@@ -13,51 +13,51 @@ in order to resist overflow attacks. In addition, a few functions are
13provided to standardize version and error reporting across the entire 13provided to standardize version and error reporting across the entire
14suite of plugins. */ 14suite of plugins. */
15 15
16/* now some functions etc are being defined in ../lib/utils_base.c */ 16#include "../config.h"
17#include "utils_base.h"
18
19#include <stdbool.h> 17#include <stdbool.h>
20 18#include <stdint.h>
19#include <stdio.h>
20#include <time.h>
21 21
22#ifdef NP_EXTRA_OPTS 22#ifdef NP_EXTRA_OPTS
23/* Include extra-opts functions if compiled in */ 23/* Include extra-opts functions if compiled in */
24#include "extra_opts.h" 24# include "extra_opts.h"
25#else 25#else
26/* else, fake np_extra_opts */ 26/* else, fake np_extra_opts */
27#define np_extra_opts(acptr,av,pr) av 27# define np_extra_opts(acptr, av, pr) av
28#endif 28#endif
29 29
30/* Standardize version information, termination */ 30/* Standardize version information, termination */
31 31
32void support (void); 32void support(void);
33void print_revision (const char *, const char *); 33void print_revision(const char *, const char *);
34 34
35extern time_t start_time, end_time; 35extern time_t start_time, end_time;
36 36
37/* Test input types */ 37/* Test input types */
38 38
39bool is_integer (char *); 39bool is_integer(char *);
40bool is_intpos (char *); 40bool is_intpos(char *);
41bool is_intneg (char *); 41bool is_intneg(char *);
42bool is_intnonneg (char *); 42bool is_intnonneg(char *);
43bool is_intpercent (char *); 43bool is_intpercent(char *);
44bool is_uint64(char *number, uint64_t *target); 44bool is_uint64(char *number, uint64_t *target);
45bool is_int64(char *number, int64_t *target); 45bool is_int64(char *number, int64_t *target);
46 46
47bool is_numeric (char *); 47bool is_numeric(char *);
48bool is_positive (char *); 48bool is_positive(char *);
49bool is_negative (char *); 49bool is_negative(char *);
50bool is_nonnegative (char *); 50bool is_nonnegative(char *);
51bool is_percentage (char *); 51bool is_percentage(char *);
52bool is_percentage_expression (const char[]); 52bool is_percentage_expression(const char[]);
53 53
54bool is_option (char *); 54bool is_option(char *);
55 55
56/* Generalized timer that will do milliseconds if available */ 56/* Generalized timer that will do milliseconds if available */
57#ifndef HAVE_STRUCT_TIMEVAL 57#ifndef HAVE_STRUCT_TIMEVAL
58struct timeval { 58struct timeval {
59 long tv_sec; /* seconds */ 59 long tv_sec; /* seconds */
60 long tv_usec; /* microseconds */ 60 long tv_usec; /* microseconds */
61}; 61};
62#endif 62#endif
63 63
@@ -65,137 +65,143 @@ struct timeval {
65int gettimeofday(struct timeval *, struct timezone *); 65int gettimeofday(struct timeval *, struct timezone *);
66#endif 66#endif
67 67
68double delta_time (struct timeval tv); 68double delta_time(struct timeval tv);
69long deltime (struct timeval tv); 69long deltime(struct timeval tv);
70 70
71/* Handle strings safely */ 71/* Handle strings safely */
72 72
73void strip (char *); 73void strip(char *);
74char *strscpy (char *, const char *); 74char *strscpy(char *, const char *);
75char *strnl (char *); 75char *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
81int max_state (int a, int b); 81void usage(const char *) __attribute__((noreturn));
82int max_state_alt (int a, int b);
83
84void usage (const char *) __attribute__((noreturn));
85void usage2(const char *, const char *) __attribute__((noreturn)); 82void usage2(const char *, const char *) __attribute__((noreturn));
86void usage3(const char *, int) __attribute__((noreturn)); 83void usage3(const char *, int) __attribute__((noreturn));
87void usage4(const char *) __attribute__((noreturn)); 84void usage4(const char *) __attribute__((noreturn));
88void usage5(void) __attribute__((noreturn)); 85void usage5(void) __attribute__((noreturn));
89void usage_va(const char *fmt, ...) __attribute__((noreturn)); 86void usage_va(const char *fmt, ...) __attribute__((noreturn));
90 87
91#define max(a,b) (((a)>(b))?(a):(b)) 88#define max(a, b) (((a) > (b)) ? (a) : (b))
92#define min(a,b) (((a)<(b))?(a):(b)) 89#define min(a, b) (((a) < (b)) ? (a) : (b))
93 90
94char *perfdata (const char *, long int, const char *, int, long int, 91char *perfdata(const char *, long int, const char *, bool, long int, bool, long int, bool, long int, bool, long int);
95 int, long int, int, long int, int, long int);
96 92
97char *perfdata_uint64 (const char *, uint64_t , const char *, int, uint64_t, 93char *perfdata_uint64(const char *, uint64_t, const char *, bool, uint64_t, bool, uint64_t, bool, uint64_t, bool, uint64_t);
98 int, uint64_t, int, uint64_t, int, uint64_t);
99 94
100char *perfdata_int64 (const char *, int64_t, const char *, int, int64_t, 95char *perfdata_int64(const char *, int64_t, const char *, bool, int64_t, bool, int64_t, bool, int64_t, bool, int64_t);
101 int, int64_t, int, int64_t, int, int64_t);
102 96
103char *fperfdata (const char *, double, const char *, int, double, 97char *fperfdata(const char *, double, const char *, bool, double, bool, double, bool, double, bool, double);
104 int, double, int, double, int, double);
105 98
106char *sperfdata (const char *, double, const char *, char *, char *, 99char *sperfdata(const char *, double, const char *, char *, char *, bool, double, bool, double);
107 int, double, int, double);
108 100
109char *sperfdata_int (const char *, int, const char *, char *, char *, 101char *sperfdata_int(const char *, int, const char *, char *, char *, bool, int, bool, int);
110 int, int, int, int);
111 102
112/* The idea here is that, although not every plugin will use all of these, 103/* The idea here is that, although not every plugin will use all of these,
113 most will or should. Therefore, for consistency, these very common 104 most will or should. Therefore, for consistency, these very common
114 options should have only these meanings throughout the overall suite */ 105 options should have only these meanings throughout the overall suite */
115 106
116#define STD_LONG_OPTS \ 107#define STD_LONG_OPTS \
117{"version",no_argument,0,'V'},\ 108 {"version", no_argument, 0, 'V'}, {"verbose", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, \
118{"verbose",no_argument,0,'v'},\ 109 {"timeout", required_argument, 0, 't'}, {"critical", required_argument, 0, 'c'}, {"warning", required_argument, 0, 'w'}, \
119{"help",no_argument,0,'h'},\ 110 {"hostname", required_argument, 0, 'H'}
120{"timeout",required_argument,0,'t'},\
121{"critical",required_argument,0,'c'},\
122{"warning",required_argument,0,'w'},\
123{"hostname",required_argument,0,'H'}
124 111
125#define COPYRIGHT "Copyright (c) %s Monitoring Plugins Development Team\n\ 112#define COPYRIGHT \
113 "Copyright (c) %s Monitoring Plugins Development Team\n\
126\t<%s>\n\n" 114\t<%s>\n\n"
127 115
128#define UT_HLP_VRS _("\ 116#define UT_HLP_VRS \
117 _("\
129 %s (-h | --help) for detailed help\n\ 118 %s (-h | --help) for detailed help\n\
130 %s (-V | --version) for version information\n") 119 %s (-V | --version) for version information\n")
131 120
132#define UT_HELP_VRSN _("\ 121#define UT_HELP_VRSN \
122 _("\
133\nOptions:\n\ 123\nOptions:\n\
134 -h, --help\n\ 124 -h, --help\n\
135 Print detailed help screen\n\ 125 Print detailed help screen\n\
136 -V, --version\n\ 126 -V, --version\n\
137 Print version information\n") 127 Print version information\n")
138 128
139#define UT_HOST_PORT _("\ 129#define UT_HOST_PORT \
130 _("\
140 -H, --hostname=ADDRESS\n\ 131 -H, --hostname=ADDRESS\n\
141 Host name, IP Address, or unix socket (must be an absolute path)\n\ 132 Host name, IP Address, or unix socket (must be an absolute path)\n\
142 -%c, --port=INTEGER\n\ 133 -%c, --port=INTEGER\n\
143 Port number (default: %s)\n") 134 Port number (default: %s)\n")
144 135
145#define UT_IPv46 _("\ 136#define UT_IPv46 \
137 _("\
146 -4, --use-ipv4\n\ 138 -4, --use-ipv4\n\
147 Use IPv4 connection\n\ 139 Use IPv4 connection\n\
148 -6, --use-ipv6\n\ 140 -6, --use-ipv6\n\
149 Use IPv6 connection\n") 141 Use IPv6 connection\n")
150 142
151#define UT_VERBOSE _("\ 143#define UT_VERBOSE \
144 _("\
152 -v, --verbose\n\ 145 -v, --verbose\n\
153 Show details for command-line debugging (output may be truncated by\n\ 146 Show details for command-line debugging (output may be truncated by\n\
154 the monitoring system)\n") 147 the monitoring system)\n")
155 148
156#define UT_WARN_CRIT _("\ 149#define UT_WARN_CRIT \
150 _("\
157 -w, --warning=DOUBLE\n\ 151 -w, --warning=DOUBLE\n\
158 Response time to result in warning status (seconds)\n\ 152 Response time to result in warning status (seconds)\n\
159 -c, --critical=DOUBLE\n\ 153 -c, --critical=DOUBLE\n\
160 Response time to result in critical status (seconds)\n") 154 Response time to result in critical status (seconds)\n")
161 155
162#define UT_WARN_CRIT_RANGE _("\ 156#define UT_WARN_CRIT_RANGE \
157 _("\
163 -w, --warning=RANGE\n\ 158 -w, --warning=RANGE\n\
164 Warning range (format: start:end). Alert if outside this range\n\ 159 Warning range (format: start:end). Alert if outside this range\n\
165 -c, --critical=RANGE\n\ 160 -c, --critical=RANGE\n\
166 Critical range\n") 161 Critical range\n")
167 162
168#define UT_CONN_TIMEOUT _("\ 163#define UT_CONN_TIMEOUT \
164 _("\
169 -t, --timeout=INTEGER\n\ 165 -t, --timeout=INTEGER\n\
170 Seconds before connection times out (default: %d)\n") 166 Seconds before connection times out (default: %d)\n")
171 167
172#define UT_PLUG_TIMEOUT _("\ 168#define UT_PLUG_TIMEOUT \
169 _("\
173 -t, --timeout=INTEGER\n\ 170 -t, --timeout=INTEGER\n\
174 Seconds before plugin times out (default: %d)\n") 171 Seconds before plugin times out (default: %d)\n")
175 172
176#ifdef NP_EXTRA_OPTS 173#ifdef NP_EXTRA_OPTS
177#define UT_EXTRA_OPTS _("\ 174# define UT_EXTRA_OPTS \
175 _("\
178 --extra-opts=[section][@file]\n\ 176 --extra-opts=[section][@file]\n\
179 Read options from an ini file. See\n\ 177 Read options from an ini file. See\n\
180 https://www.monitoring-plugins.org/doc/extra-opts.html\n\ 178 https://www.monitoring-plugins.org/doc/extra-opts.html\n\
181 for usage and examples.\n") 179 for usage and examples.\n")
182#else 180#else
183#define UT_EXTRA_OPTS " \b" 181# define UT_EXTRA_OPTS " \b"
184#endif 182#endif
185 183
186#define UT_THRESHOLDS_NOTES _("\ 184#define UT_THRESHOLDS_NOTES \
185 _("\
187 See:\n\ 186 See:\n\
188 https://www.monitoring-plugins.org/doc/guidelines.html#THRESHOLDFORMAT\n\ 187 https://www.monitoring-plugins.org/doc/guidelines.html#THRESHOLDFORMAT\n\
189 for THRESHOLD format and examples.\n") 188 for THRESHOLD format and examples.\n")
190 189
191#define UT_SUPPORT _("\n\ 190#define UT_SUPPORT \
191 _("\n\
192Send email to help@monitoring-plugins.org if you have questions regarding\n\ 192Send 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\ 193use of this software. To submit patches or suggest improvements, send email\n\
194to devel@monitoring-plugins.org\n\n") 194to devel@monitoring-plugins.org\n\n")
195 195
196#define UT_NOWARRANTY _("\n\ 196#define UT_NOWARRANTY \
197 _("\n\
197The Monitoring Plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n\ 198The Monitoring Plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n\
198copies of the plugins under the terms of the GNU General Public License.\n\ 199copies of the plugins under the terms of the GNU General Public License.\n\
199For more information about these matters, see the file named COPYING.\n") 200For more information about these matters, see the file named COPYING.\n")
200 201
202#define UT_OUTPUT_FORMAT \
203 _("\
204 --output-format=OUTPUT_FORMAT\n\
205 Select output format. Valid values: \"multi-line\", \"mp-test-json\"\n")
206
201#endif /* NP_UTILS_H */ 207#endif /* NP_UTILS_H */
diff --git a/tap/tap.c b/tap/tap.c
index 97c20e96..00ceab27 100644
--- a/tap/tap.c
+++ b/tap/tap.c
@@ -35,8 +35,8 @@ static int no_plan = 0;
35static int skip_all = 0; 35static int skip_all = 0;
36static int have_plan = 0; 36static int have_plan = 0;
37static unsigned int test_count = 0; /* Number of tests that have been run */ 37static unsigned int test_count = 0; /* Number of tests that have been run */
38static unsigned int e_tests = 0; /* Expected number of tests to run */ 38static unsigned int e_tests = 0; /* Expected number of tests to run */
39static unsigned int failures = 0; /* Number of tests that failed */ 39static unsigned int failures = 0; /* Number of tests that failed */
40static char *todo_msg = NULL; 40static char *todo_msg = NULL;
41static char *todo_msg_fixed = "libtap malloc issue"; 41static char *todo_msg_fixed = "libtap malloc issue";
42static int todo = 0; 42static int todo = 0;
@@ -45,13 +45,13 @@ static int test_died = 0;
45/* Encapsulate the pthread code in a conditional. In the absence of 45/* Encapsulate the pthread code in a conditional. In the absence of
46 libpthread the code does nothing */ 46 libpthread the code does nothing */
47#ifdef HAVE_LIBPTHREAD 47#ifdef HAVE_LIBPTHREAD
48#include <pthread.h> 48# include <pthread.h>
49static pthread_mutex_t M = PTHREAD_MUTEX_INITIALIZER; 49static pthread_mutex_t M = PTHREAD_MUTEX_INITIALIZER;
50# define LOCK pthread_mutex_lock(&M); 50# define LOCK pthread_mutex_lock(&M);
51# define UNLOCK pthread_mutex_unlock(&M); 51# define UNLOCK pthread_mutex_unlock(&M);
52#else 52#else
53# define LOCK 53# define LOCK
54# define UNLOCK 54# define UNLOCK
55#endif 55#endif
56 56
57static void _expected_tests(unsigned int); 57static void _expected_tests(unsigned int);
@@ -65,10 +65,7 @@ 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 68unsigned int _gen_result(int ok, const char *func, char *file, unsigned int line, char *test_name, ...) {
69_gen_result(int ok, const char *func, char *file, unsigned int line,
70 char *test_name, ...)
71{
72 va_list ap; 69 va_list ap;
73 char *local_test_name = NULL; 70 char *local_test_name = NULL;
74 char *c; 71 char *c;
@@ -80,7 +77,7 @@ _gen_result(int ok, const char *func, char *file, unsigned int line,
80 77
81 /* Start by taking the test name and performing any printf() 78 /* Start by taking the test name and performing any printf()
82 expansions on it */ 79 expansions on it */
83 if(test_name != NULL) { 80 if (test_name != NULL) {
84 va_start(ap, test_name); 81 va_start(ap, test_name);
85 vasprintf(&local_test_name, test_name, ap); 82 vasprintf(&local_test_name, test_name, ap);
86 va_end(ap); 83 va_end(ap);
@@ -88,43 +85,43 @@ _gen_result(int ok, const char *func, char *file, unsigned int line,
88 /* Make sure the test name contains more than digits 85 /* Make sure the test name contains more than digits
89 and spaces. Emit an error message and exit if it 86 and spaces. Emit an error message and exit if it
90 does */ 87 does */
91 if(local_test_name) { 88 if (local_test_name) {
92 name_is_digits = 1; 89 name_is_digits = 1;
93 for(c = local_test_name; *c != '\0'; c++) { 90 for (c = local_test_name; *c != '\0'; c++) {
94 if(!isdigit(*c) && !isspace(*c)) { 91 if (!isdigit(*c) && !isspace(*c)) {
95 name_is_digits = 0; 92 name_is_digits = 0;
96 break; 93 break;
97 } 94 }
98 } 95 }
99 96
100 if(name_is_digits) { 97 if (name_is_digits) {
101 diag(" You named your test '%s'. You shouldn't use numbers for your test names.", local_test_name); 98 diag(" You named your test '%s'. You shouldn't use numbers for your test names.", local_test_name);
102 diag(" Very confusing."); 99 diag(" Very confusing.");
103 } 100 }
104 } 101 }
105 } 102 }
106 103
107 if(!ok) { 104 if (!ok) {
108 printf("not "); 105 printf("not ");
109 failures++; 106 failures++;
110 } 107 }
111 108
112 printf("ok %d", test_count); 109 printf("ok %d", test_count);
113 110
114 if(test_name != NULL) { 111 if (test_name != NULL) {
115 printf(" - "); 112 printf(" - ");
116 113
117 /* Print the test name, escaping any '#' characters it 114 /* Print the test name, escaping any '#' characters it
118 might contain */ 115 might contain */
119 if(local_test_name != NULL) { 116 if (local_test_name != NULL) {
120 flockfile(stdout); 117 flockfile(stdout);
121 for(c = local_test_name; *c != '\0'; c++) { 118 for (c = local_test_name; *c != '\0'; c++) {
122 if(*c == '#') 119 if (*c == '#')
123 fputc('\\', stdout); 120 fputc('\\', stdout);
124 fputc((int)*c, stdout); 121 fputc((int)*c, stdout);
125 } 122 }
126 funlockfile(stdout); 123 funlockfile(stdout);
127 } else { /* vasprintf() failed, use a fixed message */ 124 } else { /* vasprintf() failed, use a fixed message */
128 printf("%s", todo_msg_fixed); 125 printf("%s", todo_msg_fixed);
129 } 126 }
130 } 127 }
@@ -136,17 +133,16 @@ _gen_result(int ok, const char *func, char *file, unsigned int line,
136 133
137 This is not counted as a failure, so decrement the counter if 134 This is not counted as a failure, so decrement the counter if
138 the test failed. */ 135 the test failed. */
139 if(todo) { 136 if (todo) {
140 printf(" # TODO %s", todo_msg ? todo_msg : todo_msg_fixed); 137 printf(" # TODO %s", todo_msg ? todo_msg : todo_msg_fixed);
141 if(!ok) 138 if (!ok)
142 failures--; 139 failures--;
143 } 140 }
144 141
145 printf("\n"); 142 printf("\n");
146 143
147 if(!ok) 144 if (!ok)
148 diag(" Failed %stest (%s:%s() at line %d)", 145 diag(" Failed %stest (%s:%s() at line %d)", todo ? "(TODO) " : "", file, func, line);
149 todo ? "(TODO) " : "", file, func, line);
150 146
151 free(local_test_name); 147 free(local_test_name);
152 148
@@ -161,18 +157,16 @@ _gen_result(int ok, const char *func, char *file, unsigned int line,
161 * Initialise the TAP library. Will only do so once, however many times it's 157 * Initialise the TAP library. Will only do so once, however many times it's
162 * called. 158 * called.
163 */ 159 */
164void 160void _tap_init(void) {
165_tap_init(void)
166{
167 static int run_once = 0; 161 static int run_once = 0;
168 162
169 LOCK; 163 LOCK;
170 164
171 if(!run_once) { 165 if (!run_once) {
172 atexit(_cleanup); 166 atexit(_cleanup);
173 167
174 /* stdout needs to be unbuffered so that the output appears 168 /* stdout needs to be unbuffered so that the output appears
175 in the same place relative to stderr output as it does 169 in the same place relative to stderr output as it does
176 with Test::Harness */ 170 with Test::Harness */
177 setbuf(stdout, 0); 171 setbuf(stdout, 0);
178 run_once = 1; 172 run_once = 1;
@@ -184,15 +178,13 @@ _tap_init(void)
184/* 178/*
185 * Note that there's no plan. 179 * Note that there's no plan.
186 */ 180 */
187int 181int plan_no_plan(void) {
188plan_no_plan(void)
189{
190 182
191 LOCK; 183 LOCK;
192 184
193 _tap_init(); 185 _tap_init();
194 186
195 if(have_plan != 0) { 187 if (have_plan != 0) {
196 fprintf(stderr, "You tried to plan twice!\n"); 188 fprintf(stderr, "You tried to plan twice!\n");
197 test_died = 1; 189 test_died = 1;
198 UNLOCK; 190 UNLOCK;
@@ -210,9 +202,7 @@ plan_no_plan(void)
210/* 202/*
211 * Note that the plan is to skip all tests 203 * Note that the plan is to skip all tests
212 */ 204 */
213int 205int plan_skip_all(char *reason) {
214plan_skip_all(char *reason)
215{
216 206
217 LOCK; 207 LOCK;
218 208
@@ -222,7 +212,7 @@ plan_skip_all(char *reason)
222 212
223 printf("1..0"); 213 printf("1..0");
224 214
225 if(reason != NULL) 215 if (reason != NULL)
226 printf(" # Skip %s", reason); 216 printf(" # Skip %s", reason);
227 217
228 printf("\n"); 218 printf("\n");
@@ -235,22 +225,20 @@ plan_skip_all(char *reason)
235/* 225/*
236 * Note the number of tests that will be run. 226 * Note the number of tests that will be run.
237 */ 227 */
238int 228int plan_tests(unsigned int tests) {
239plan_tests(unsigned int tests)
240{
241 229
242 LOCK; 230 LOCK;
243 231
244 _tap_init(); 232 _tap_init();
245 233
246 if(have_plan != 0) { 234 if (have_plan != 0) {
247 fprintf(stderr, "You tried to plan twice!\n"); 235 fprintf(stderr, "You tried to plan twice!\n");
248 test_died = 1; 236 test_died = 1;
249 UNLOCK; 237 UNLOCK;
250 exit(255); 238 exit(255);
251 } 239 }
252 240
253 if(tests == 0) { 241 if (tests == 0) {
254 fprintf(stderr, "You said to run 0 tests! You've got to run something.\n"); 242 fprintf(stderr, "You said to run 0 tests! You've got to run something.\n");
255 test_died = 1; 243 test_died = 1;
256 UNLOCK; 244 UNLOCK;
@@ -266,9 +254,7 @@ plan_tests(unsigned int tests)
266 return 0; 254 return 0;
267} 255}
268 256
269unsigned int 257unsigned int diag(char *fmt, ...) {
270diag(char *fmt, ...)
271{
272 va_list ap; 258 va_list ap;
273 259
274 LOCK; 260 LOCK;
@@ -286,9 +272,7 @@ diag(char *fmt, ...)
286 return 0; 272 return 0;
287} 273}
288 274
289void 275void _expected_tests(unsigned int tests) {
290_expected_tests(unsigned int tests)
291{
292 276
293 LOCK; 277 LOCK;
294 278
@@ -298,9 +282,7 @@ _expected_tests(unsigned int tests)
298 UNLOCK; 282 UNLOCK;
299} 283}
300 284
301int 285int skip(unsigned int n, char *fmt, ...) {
302skip(unsigned int n, char *fmt, ...)
303{
304 va_list ap; 286 va_list ap;
305 char *skip_msg; 287 char *skip_msg;
306 288
@@ -310,11 +292,9 @@ skip(unsigned int n, char *fmt, ...)
310 asprintf(&skip_msg, fmt, ap); 292 asprintf(&skip_msg, fmt, ap);
311 va_end(ap); 293 va_end(ap);
312 294
313 while(n-- > 0) { 295 while (n-- > 0) {
314 test_count++; 296 test_count++;
315 printf("ok %d # skip %s\n", test_count, 297 printf("ok %d # skip %s\n", test_count, skip_msg != NULL ? skip_msg : "libtap():malloc() failed");
316 skip_msg != NULL ?
317 skip_msg : "libtap():malloc() failed");
318 } 298 }
319 299
320 free(skip_msg); 300 free(skip_msg);
@@ -324,9 +304,7 @@ skip(unsigned int n, char *fmt, ...)
324 return 1; 304 return 1;
325} 305}
326 306
327void 307void todo_start(char *fmt, ...) {
328todo_start(char *fmt, ...)
329{
330 va_list ap; 308 va_list ap;
331 309
332 LOCK; 310 LOCK;
@@ -340,9 +318,7 @@ todo_start(char *fmt, ...)
340 UNLOCK; 318 UNLOCK;
341} 319}
342 320
343void 321void todo_end(void) {
344todo_end(void)
345{
346 322
347 LOCK; 323 LOCK;
348 324
@@ -352,28 +328,26 @@ todo_end(void)
352 UNLOCK; 328 UNLOCK;
353} 329}
354 330
355int 331int exit_status(void) {
356exit_status(void)
357{
358 int r; 332 int r;
359 333
360 LOCK; 334 LOCK;
361 335
362 /* If there's no plan, just return the number of failures */ 336 /* If there's no plan, just return the number of failures */
363 if(no_plan || !have_plan) { 337 if (no_plan || !have_plan) {
364 UNLOCK; 338 UNLOCK;
365 return failures; 339 return failures;
366 } 340 }
367 341
368 /* Ran too many tests? Return the number of tests that were run 342 /* Ran too many tests? Return the number of tests that were run
369 that shouldn't have been */ 343 that shouldn't have been */
370 if(e_tests < test_count) { 344 if (e_tests < test_count) {
371 r = test_count - e_tests; 345 r = test_count - e_tests;
372 UNLOCK; 346 UNLOCK;
373 return r; 347 return r;
374 } 348 }
375 349
376 /* Return the number of tests that failed + the number of tests 350 /* Return the number of tests that failed + the number of tests
377 that weren't run */ 351 that weren't run */
378 r = failures + e_tests - test_count; 352 r = failures + e_tests - test_count;
379 UNLOCK; 353 UNLOCK;
@@ -385,51 +359,45 @@ exit_status(void)
385 * Cleanup at the end of the run, produce any final output that might be 359 * Cleanup at the end of the run, produce any final output that might be
386 * required. 360 * required.
387 */ 361 */
388void 362void _cleanup(void) {
389_cleanup(void)
390{
391 363
392 LOCK; 364 LOCK;
393 365
394 /* If plan_no_plan() wasn't called, and we don't have a plan, 366 /* If plan_no_plan() wasn't called, and we don't have a plan,
395 and we're not skipping everything, then something happened 367 and we're not skipping everything, then something happened
396 before we could produce any output */ 368 before we could produce any output */
397 if(!no_plan && !have_plan && !skip_all) { 369 if (!no_plan && !have_plan && !skip_all) {
398 diag("Looks like your test died before it could output anything."); 370 diag("Looks like your test died before it could output anything.");
399 UNLOCK; 371 UNLOCK;
400 return; 372 return;
401 } 373 }
402 374
403 if(test_died) { 375 if (test_died) {
404 diag("Looks like your test died just after %d.", test_count); 376 diag("Looks like your test died just after %d.", test_count);
405 UNLOCK; 377 UNLOCK;
406 return; 378 return;
407 } 379 }
408 380
409
410 /* No plan provided, but now we know how many tests were run, and can 381 /* No plan provided, but now we know how many tests were run, and can
411 print the header at the end */ 382 print the header at the end */
412 if(!skip_all && (no_plan || !have_plan)) { 383 if (!skip_all && (no_plan || !have_plan)) {
413 printf("1..%d\n", test_count); 384 printf("1..%d\n", test_count);
414 } 385 }
415 386
416 if((have_plan && !no_plan) && e_tests < test_count) { 387 if ((have_plan && !no_plan) && e_tests < test_count) {
417 diag("Looks like you planned %d tests but ran %d extra.", 388 diag("Looks like you planned %d tests but ran %d extra.", e_tests, test_count - e_tests);
418 e_tests, test_count - e_tests);
419 UNLOCK; 389 UNLOCK;
420 return; 390 return;
421 } 391 }
422 392
423 if((have_plan || !no_plan) && e_tests > test_count) { 393 if ((have_plan || !no_plan) && e_tests > test_count) {
424 diag("Looks like you planned %d tests but only ran %d.", 394 diag("Looks like you planned %d tests but only ran %d.", e_tests, test_count);
425 e_tests, test_count);
426 UNLOCK; 395 UNLOCK;
427 return; 396 return;
428 } 397 }
429 398
430 if(failures) 399 if (failures)
431 diag("Looks like you failed %d tests of %d.", 400 diag("Looks like you failed %d tests of %d.", failures, test_count);
432 failures, test_count);
433 401
434 UNLOCK; 402 UNLOCK;
435} 403}
diff --git a/tap/tap.h b/tap/tap.h
index 8ee525c8..5abbd76a 100644
--- a/tap/tap.h
+++ b/tap/tap.h
@@ -28,52 +28,46 @@
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, ...) ((e) ? \ 31# define ok(e, test, ...) \
32 _gen_result(1, __func__, __FILE__, __LINE__, \ 32 ((e) ? _gen_result(1, __func__, __FILE__, __LINE__, test, ##__VA_ARGS__) \
33 test, ## __VA_ARGS__) : \ 33 : _gen_result(0, __func__, __FILE__, __LINE__, test, ##__VA_ARGS__))
34 _gen_result(0, __func__, __FILE__, __LINE__, \
35 test, ## __VA_ARGS__))
36 34
37# define ok1(e) ((e) ? \ 35# define ok1(e) ((e) ? _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e))
38 _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : \
39 _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e))
40 36
41# define pass(test, ...) ok(1, test, ## __VA_ARGS__); 37# define pass(test, ...) ok(1, test, ##__VA_ARGS__);
42# define fail(test, ...) ok(0, test, ## __VA_ARGS__); 38# define fail(test, ...) ok(0, test, ##__VA_ARGS__);
43 39
44# define skip_start(test, n, fmt, ...) \ 40# define skip_start(test, n, fmt, ...) \
45 do { \ 41 do { \
46 if((test)) { \ 42 if ((test)) { \
47 skip(n, fmt, ## __VA_ARGS__); \ 43 skip(n, fmt, ##__VA_ARGS__); \
48 continue; \ 44 continue; \
49 } 45 }
50#else /* __GNUC__ */ 46#else /* __GNUC__ */
51/* The original tap.h used to test if __STDC_VERSION__ >= 199901L here. This 47/* The original tap.h used to test if __STDC_VERSION__ >= 199901L here. This
52 * doesn't seem to work on HP-UX even though the code compile fine. I'm not 48 * doesn't seem to work on HP-UX even though the code compile fine. I'm not
53 * sure how to add an exception here for HP-UX so I just removed the check 49 * sure how to add an exception here for HP-UX so I just removed the check
54 * for now */ 50 * for now */
55# define ok(e, ...) ((e) ? \ 51# define ok(e, ...) \
56 _gen_result(1, __func__, __FILE__, __LINE__, \ 52 ((e) ? _gen_result(1, __func__, __FILE__, __LINE__, __VA_ARGS__) : _gen_result(0, __func__, __FILE__, __LINE__, __VA_ARGS__))
57 __VA_ARGS__) : \
58 _gen_result(0, __func__, __FILE__, __LINE__, \
59 __VA_ARGS__))
60 53
61# define ok1(e) ((e) ? \ 54# define ok1(e) ((e) ? _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e))
62 _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : \
63 _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e))
64 55
65# define pass(...) ok(1, __VA_ARGS__); 56# define pass(...) ok(1, __VA_ARGS__);
66# define fail(...) ok(0, __VA_ARGS__); 57# define fail(...) ok(0, __VA_ARGS__);
67 58
68# define skip_start(test, n, ...) \ 59# define skip_start(test, n, ...) \
69 do { \ 60 do { \
70 if((test)) { \ 61 if ((test)) { \
71 skip(n, __VA_ARGS__); \ 62 skip(n, __VA_ARGS__); \
72 continue; \ 63 continue; \
73 } 64 }
74#endif /* __GNUC__ */ 65#endif /* __GNUC__ */
75 66
76# define skip_end } while(0); 67#define skip_end \
68 } \
69 while (0) \
70 ;
77 71
78unsigned int _gen_result(int, const char *, char *, unsigned int, char *, ...); 72unsigned int _gen_result(int, const char *, char *, unsigned int, char *, ...);
79 73
diff --git a/tap/tests/diag/test.c b/tap/tests/diag/test.c
index 401db647..b0a5a4f5 100644
--- a/tap/tests/diag/test.c
+++ b/tap/tests/diag/test.c
@@ -28,9 +28,7 @@
28 28
29#include "tap.h" 29#include "tap.h"
30 30
31int 31int main(int argc, char *argv[]) {
32main(int argc, char *argv[])
33{
34 unsigned int rc = 0; 32 unsigned int rc = 0;
35 33
36 plan_tests(2); 34 plan_tests(2);
diff --git a/tap/tests/fail/test.c b/tap/tests/fail/test.c
index 621b6c29..18e16954 100644
--- a/tap/tests/fail/test.c
+++ b/tap/tests/fail/test.c
@@ -28,9 +28,7 @@
28 28
29#include "tap.h" 29#include "tap.h"
30 30
31int 31int main(int argc, char *argv[]) {
32main(int argc, char *argv[])
33{
34 unsigned int rc = 0; 32 unsigned int rc = 0;
35 33
36 rc = plan_tests(2); 34 rc = plan_tests(2);
diff --git a/tap/tests/ok/ok-hash/test.c b/tap/tests/ok/ok-hash/test.c
index 16be137a..82f65b08 100644
--- a/tap/tests/ok/ok-hash/test.c
+++ b/tap/tests/ok/ok-hash/test.c
@@ -28,9 +28,7 @@
28 28
29#include "tap.h" 29#include "tap.h"
30 30
31int 31int main(int argc, char *argv[]) {
32main(int argc, char *argv[])
33{
34 unsigned int rc = 0; 32 unsigned int rc = 0;
35 33
36 rc = plan_tests(4); 34 rc = plan_tests(4);
@@ -42,11 +40,11 @@ main(int argc, char *argv[])
42 rc = ok(1, "Test with one # hash"); 40 rc = ok(1, "Test with one # hash");
43 diag("Returned: %d", rc); 41 diag("Returned: %d", rc);
44 42
45 rc = ok(1, "Test with # two # hashes"); 43 rc = ok(1, "Test with # two # hashes");
46 diag("Returned: %d", rc); 44 diag("Returned: %d", rc);
47 45
48 rc = ok(1, "Test with ## back to back hashes"); 46 rc = ok(1, "Test with ## back to back hashes");
49 diag("Returned: %d", rc); 47 diag("Returned: %d", rc);
50 48
51 return exit_status(); 49 return exit_status();
52} 50}
diff --git a/tap/tests/ok/ok-numeric/test.c b/tap/tests/ok/ok-numeric/test.c
index 0e33a748..46113f49 100644
--- a/tap/tests/ok/ok-numeric/test.c
+++ b/tap/tests/ok/ok-numeric/test.c
@@ -28,9 +28,7 @@
28 28
29#include "tap.h" 29#include "tap.h"
30 30
31int 31int main(int argc, char *argv[]) {
32main(int argc, char *argv[])
33{
34 unsigned int rc = 0; 32 unsigned int rc = 0;
35 33
36 rc = plan_tests(3); 34 rc = plan_tests(3);
diff --git a/tap/tests/ok/ok/test.c b/tap/tests/ok/ok/test.c
index ae04f2e4..8ef0bcd8 100644
--- a/tap/tests/ok/ok/test.c
+++ b/tap/tests/ok/ok/test.c
@@ -28,9 +28,7 @@
28 28
29#include "tap.h" 29#include "tap.h"
30 30
31int 31int main(int argc, char *argv[]) {
32main(int argc, char *argv[])
33{
34 unsigned int rc = 0; 32 unsigned int rc = 0;
35 33
36 rc = plan_tests(5); 34 rc = plan_tests(5);
diff --git a/tap/tests/pass/test.c b/tap/tests/pass/test.c
index 39d8a7c1..73df20cb 100644
--- a/tap/tests/pass/test.c
+++ b/tap/tests/pass/test.c
@@ -28,9 +28,7 @@
28 28
29#include "tap.h" 29#include "tap.h"
30 30
31int 31int main(int argc, char *argv[]) {
32main(int argc, char *argv[])
33{
34 unsigned int rc = 0; 32 unsigned int rc = 0;
35 33
36 rc = plan_tests(2); 34 rc = plan_tests(2);
diff --git a/tap/tests/plan/no-tests/test.c b/tap/tests/plan/no-tests/test.c
index 78c5d371..f70ec8d3 100644
--- a/tap/tests/plan/no-tests/test.c
+++ b/tap/tests/plan/no-tests/test.c
@@ -28,9 +28,7 @@
28 28
29#include "tap.h" 29#include "tap.h"
30 30
31int 31int main(int argc, char *argv[]) {
32main(int argc, char *argv[])
33{
34 unsigned int rc = 0; 32 unsigned int rc = 0;
35 33
36 rc = plan_tests(0); 34 rc = plan_tests(0);
diff --git a/tap/tests/plan/no_plan/test.c b/tap/tests/plan/no_plan/test.c
index 5cffbdc2..4c25d5f2 100644
--- a/tap/tests/plan/no_plan/test.c
+++ b/tap/tests/plan/no_plan/test.c
@@ -28,9 +28,7 @@
28 28
29#include "tap.h" 29#include "tap.h"
30 30
31int 31int main(int argc, char *argv[]) {
32main(int argc, char *argv[])
33{
34 unsigned int rc = 0; 32 unsigned int rc = 0;
35 33
36 rc = plan_no_plan(); 34 rc = plan_no_plan();
diff --git a/tap/tests/plan/not-enough-tests/test.c b/tap/tests/plan/not-enough-tests/test.c
index a9ec64f2..eacc07eb 100644
--- a/tap/tests/plan/not-enough-tests/test.c
+++ b/tap/tests/plan/not-enough-tests/test.c
@@ -28,9 +28,7 @@
28 28
29#include "tap.h" 29#include "tap.h"
30 30
31int 31int main(int argc, char *argv[]) {
32main(int argc, char *argv[])
33{
34 unsigned int rc = 0; 32 unsigned int rc = 0;
35 33
36 rc = plan_tests(1); 34 rc = plan_tests(1);
diff --git a/tap/tests/plan/sane/test.c b/tap/tests/plan/sane/test.c
index 0843d3af..17bf8d16 100644
--- a/tap/tests/plan/sane/test.c
+++ b/tap/tests/plan/sane/test.c
@@ -28,9 +28,7 @@
28 28
29#include "tap.h" 29#include "tap.h"
30 30
31int 31int main(int argc, char *argv[]) {
32main(int argc, char *argv[])
33{
34 unsigned int rc = 0; 32 unsigned int rc = 0;
35 33
36 rc = plan_tests(1); 34 rc = plan_tests(1);
diff --git a/tap/tests/plan/skip_all/test.c b/tap/tests/plan/skip_all/test.c
index 31722da9..4e37e1ae 100644
--- a/tap/tests/plan/skip_all/test.c
+++ b/tap/tests/plan/skip_all/test.c
@@ -26,9 +26,7 @@
26 26
27#include "tap.h" 27#include "tap.h"
28 28
29int 29int main(int argc, char *argv[]) {
30main(int argc, char *argv[])
31{
32 unsigned int rc = 0; 30 unsigned int rc = 0;
33 31
34 rc = plan_skip_all("No good reason"); 32 rc = plan_skip_all("No good reason");
diff --git a/tap/tests/plan/too-many-plans/test.c b/tap/tests/plan/too-many-plans/test.c
index b189cb72..5f45bc48 100644
--- a/tap/tests/plan/too-many-plans/test.c
+++ b/tap/tests/plan/too-many-plans/test.c
@@ -28,9 +28,7 @@
28 28
29#include "tap.h" 29#include "tap.h"
30 30
31int 31int main(int argc, char *argv[]) {
32main(int argc, char *argv[])
33{
34 unsigned int rc = 0; 32 unsigned int rc = 0;
35 33
36 rc = plan_tests(1); 34 rc = plan_tests(1);
diff --git a/tap/tests/plan/too-many-tests/test.c b/tap/tests/plan/too-many-tests/test.c
index 0f724104..0b2ee161 100644
--- a/tap/tests/plan/too-many-tests/test.c
+++ b/tap/tests/plan/too-many-tests/test.c
@@ -28,9 +28,7 @@
28 28
29#include "tap.h" 29#include "tap.h"
30 30
31int 31int main(int argc, char *argv[]) {
32main(int argc, char *argv[])
33{
34 unsigned int rc = 0; 32 unsigned int rc = 0;
35 33
36 rc = plan_tests(5); 34 rc = plan_tests(5);
diff --git a/tap/tests/skip/test.c b/tap/tests/skip/test.c
index d8f3eafd..789812e2 100644
--- a/tap/tests/skip/test.c
+++ b/tap/tests/skip/test.c
@@ -28,29 +28,27 @@
28 28
29#include "tap.h" 29#include "tap.h"
30 30
31int 31int main(int argc, char *argv[]) {
32main(int argc, char *argv[])
33{
34 unsigned int rc = 0; 32 unsigned int rc = 0;
35 unsigned int side_effect = 0; 33 unsigned int side_effect = 0;
36 34
37 rc = plan_tests(4); 35 rc = plan_tests(4);
38 diag("Returned: %d", rc); 36 diag("Returned: %d", rc);
39 37
40 rc = ok(1 == 1, "1 equals 1"); /* Should always work */ 38 rc = ok(1 == 1, "1 equals 1"); /* Should always work */
41 diag("Returned: %d", rc); 39 diag("Returned: %d", rc);
42 40
43 do { 41 do {
44 if(1) { 42 if (1) {
45 rc = skip(1, "Testing skipping"); 43 rc = skip(1, "Testing skipping");
46 continue; 44 continue;
47 } 45 }
48 46
49 side_effect++; 47 side_effect++;
50 48
51 ok(side_effect == 1, "side_effect checked out"); 49 ok(side_effect == 1, "side_effect checked out");
52 50
53 } while(0); 51 } while (0);
54 52
55 diag("Returned: %d", rc); 53 diag("Returned: %d", rc);
56 54
diff --git a/tap/tests/todo/test.c b/tap/tests/todo/test.c
index ac6339a7..0cd2fb3f 100644
--- a/tap/tests/todo/test.c
+++ b/tap/tests/todo/test.c
@@ -28,16 +28,14 @@
28 28
29#include "tap.h" 29#include "tap.h"
30 30
31int 31int main(int argc, char *argv[]) {
32main(int argc, char *argv[])
33{
34 unsigned int rc = 0; 32 unsigned int rc = 0;
35 unsigned int side_effect = 0; 33 unsigned int side_effect = 0;
36 34
37 rc = plan_tests(5); 35 rc = plan_tests(5);
38 diag("Returned: %d", rc); 36 diag("Returned: %d", rc);
39 37
40 rc = ok(1 == 1, "1 equals 1"); /* Should always work */ 38 rc = ok(1 == 1, "1 equals 1"); /* Should always work */
41 diag("Returned: %d", rc); 39 diag("Returned: %d", rc);
42 40
43 todo_start("For testing purposes"); 41 todo_start("For testing purposes");
diff --git a/tools/opttest.pl b/tools/opttest.pl
new file mode 100755
index 00000000..98213082
--- /dev/null
+++ b/tools/opttest.pl
@@ -0,0 +1,74 @@
1#!/usr/bin/perl -w
2use strict;
3use warnings;
4use Test;
5
6# This script (when executed from the monitoring plugins top level directory)
7# executes all the plugins with -h, --help, -V and --version to verify that
8# all of them exit properly with the state UNKNOWN (3)
9
10use vars qw($dir $file $prog $idx $state $output %progs @dirs);
11
12my $tests = 0;
13
14@dirs = qw(plugins plugins-scripts);
15
16foreach my $dir (@dirs) {
17 opendir(DIR, $dir) || die "can't opendir $dir: $!";
18 while ($file = readdir(DIR)) {
19 if (-x "$dir/$file" && -f "$dir/$file") {
20 $tests++;
21 $progs{"$dir/$file"} = $file;
22 }
23 }
24 closedir DIR;
25}
26
27plan tests => $tests;
28
29for my $prog (keys %progs) {
30 $state = 0;
31 $file = `basename $prog`;
32
33 $idx = 1;
34 $output = `$prog -h 2>&1`;
35 if(($? >> 8) != 3) {
36 $state++;
37 print "$prog failed test $idx (help exit code (short form))\n";
38 exit(1);
39 }
40
41 unless ($output =~ m/$progs{$prog}/ms) {
42 $idx++;
43 $state++;
44 print "$output\n$prog failed test $idx\n";
45 }
46
47 $idx++;
48 `$prog --help 2>&1 > /dev/null`;
49 if(($? >> 8) != 3) {
50 $state++;
51 print "$prog failed test $idx (help exit code (long form))\n";
52 exit(1);
53 }
54
55 $idx++;
56 `$prog -V 2>&1 > /dev/null`;
57 if(($? >> 8) != 3) {
58 $state++;
59 print "$prog failed test $idx (version exit code (short form))\n";
60 exit(1);
61 }
62
63 $idx++;
64 `$prog --version 2>&1 > /dev/null`;
65 if(($? >> 8) != 3) {
66 $state++;
67 print "$prog failed test $idx (version exit code (long form))\n";
68 exit(1);
69 }
70
71 print "$prog ($idx tests) ";
72 ok $state,0;
73}
74
diff --git a/tools/tinderbox_build b/tools/tinderbox_build
deleted file mode 100755
index 1a41f577..00000000
--- a/tools/tinderbox_build
+++ /dev/null
@@ -1,290 +0,0 @@
1#!/usr/bin/perl
2# tinderbox_build.pl
3# This script builds the monitoringplugins and then sends
4# logs back to the master tinderbox server
5#
6# This script is based on mozilla-unix.pl which comes with tinderbox2
7#
8# See http://tinderbox.altinity.org for more details
9
10require 5.000;
11
12use strict;
13use Sys::Hostname;
14use Cwd;
15use Time::Local;
16
17my $Version = `git describe --abbrev=4 HEAD`;
18
19my $myhost = hostname;
20chomp($myhost);
21my ($host, $junk) = split(/\./, $myhost);
22
23my $BuildAdministrator = $ENV{TINDERBOX_BUILD_ADMIN} || "$ENV{'USER'}\@$myhost";
24my $TmpDir = $ENV{TMPDIR} || "/tmp";
25
26#Default values of cmdline opts
27my $ReportStatus = 0; # Do not send results to server
28
29# Set these to what makes sense for your system
30
31# Set these proper values for your tinderbox server
32# Have the StrictHostKeyChecking=no so that a new host will automatically add hostkey without
33# prompting. If host key changes, then will get error, so this should still be secure
34my $Tinderbox_server = '-p 1022 -o StrictHostKeyChecking=no tinderbox2@tinderbox.opsera.com';
35
36# These shouldn't really need to be changed
37my $BuildTree = 'monitoringplug';
38my $BuildName = '';
39my $ConfigureArgs = $ENV{CONFIGURE_ARGS};
40
41my $OS = `uname -s`;
42my $OSVer = `uname -r`;
43
44chop($OS, $OSVer);
45
46if ( $OS eq 'AIX' ) {
47 $OSVer = `uname -v`;
48 chop($OSVer);
49 $OSVer = $OSVer . "." . `uname -r`;
50 chop($OSVer);
51}
52
53if ( $OS eq 'IRIX64' ) {
54 $OS = 'IRIX';
55}
56
57if ( $OS eq 'SCO_SV' ) {
58 $OS = 'SCOOS';
59 $OSVer = '5.0';
60}
61
62if ( "$host" ne "" ) {
63 $BuildName = $host . ' ';
64}
65$BuildName .= $OS . ' ' . $OSVer;
66$_ = $BuildName;
67s/ /_/g;
68
69my $logfile = "$_.log";
70
71sub BuildIt {
72 my ($fe, @felist, $EarlyExit, $LastTime);
73
74 my $StartDir = getcwd();
75 $LastTime = 0;
76
77 print "Starting dir is : $StartDir\n";
78
79 my $EarlyExit = 0;
80
81 chdir("$StartDir");
82
83 my $StartTime = time;
84 if (-e (my $file = "monitoring-plugins.spec")) {
85 open F, $file;
86 while (<F>) {
87 if (/^Version: trunk-(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/) {
88 $StartTime = timegm(0, $5, $4, $3, ($2 - 1), ($1 - 1900));
89 last;
90 }
91 }
92 }
93
94 print "Start time is $StartTime",$/;
95
96 my $CurrentDir = getcwd();
97 if ( $CurrentDir ne $StartDir ) {
98 print "startdir: $StartDir, curdir $CurrentDir\n";
99 die "curdir != startdir";
100 }
101
102 unlink( "$logfile" );
103
104 print "opening $logfile\n";
105 open( LOG, ">$logfile" ) || print "can't open $?\n";
106 print LOG "current dir is -- $host:$CurrentDir\n";
107 print LOG "Build Administrator is $BuildAdministrator\n";
108 &PrintEnv;
109
110 my $BuildStatus;
111 if (&configure) {
112 if (&make) {
113 if (&maketest) {
114 $BuildStatus = "success";
115 } else {
116 $BuildStatus = "test_failed";
117 }
118 } else {
119 $BuildStatus = "build_failed";
120 }
121 } else {
122 $BuildStatus = "busted";
123 }
124
125 print LOG "\nBuild Status = $BuildStatus\n";
126
127 close(LOG);
128 chdir("$StartDir");
129
130# TV: Leaving this in, because process mail program probably has some
131# limitation retained
132
133# this fun line added on 2/5/98. do not remove. Translated to english,
134# that's "take any line longer than 1000 characters, and split it into less
135# than 1000 char lines. If any of the resulting lines is
136# a dot on a line by itself, replace that with a blank line."
137# This is to prevent cases where a <cr>.<cr> occurs in the log file. Sendmail
138# interprets that as the end of the mail, and truncates the log before
139# it gets to Tinderbox. (terry weismann, chris yeh)
140#
141# This was replaced by a perl 'port' of the above, written by
142# preed@netscape.com; good things: no need for system() call, and now it's
143# all in perl, so we don't have to do OS checking like before.
144
145 open(LOG, "$logfile") || die "Couldn't open logfile: $!\n";
146 open(OUTLOG, ">${logfile}.last") || die "Couldn't open logfile: $!\n";
147
148 print OUTLOG $/;
149 print OUTLOG "tinderbox: tree: $BuildTree\n";
150 print OUTLOG "tinderbox: builddate: $StartTime\n";
151 print OUTLOG "tinderbox: status: $BuildStatus\n";
152 print OUTLOG "tinderbox: build: $BuildName $fe\n";
153 print OUTLOG "tinderbox: errorparser: unix\n";
154 print OUTLOG "tinderbox: buildfamily: unix\n";
155 print OUTLOG "tinderbox: END\n";
156 print OUTLOG $/;
157
158 while (<LOG>) {
159 my $q = 0;
160
161 for (;;) {
162 my $val = $q * 1000;
163 my $Output = substr($_, $val, 1000);
164
165 last if $Output eq undef;
166
167 $Output =~ s/^\.$//g;
168 $Output =~ s/\n//g;
169 print OUTLOG "$Output\n";
170 $q++;
171 } #EndFor
172
173 } #EndWhile
174
175 close(LOG);
176 close(OUTLOG);
177
178 if ($ReportStatus) {
179 system( "ssh $Tinderbox_server tinderbox_receive < ${logfile}.last" )
180 } else {
181 print <<"EOF"
182Not sending logs to http://tinderbox.altinity.org
183If you have SSH keys setup on the tinderbox server, you can manually send
184with 'ssh $Tinderbox_server tinderbox_receive < ${logfile}.last'
185EOF
186 }
187
188 unlink("$logfile");
189 print "Finished building for tinderbox",$/;
190
191} #EndSub-BuildIt
192
193sub ParseArgs {
194 my($i);
195
196 $i = 0;
197 while( $i < @ARGV ) {
198 if ($ARGV[$i] eq '--version' || $ARGV[$i] eq '-v') {
199 die "$0: version $Version\n";
200 } elsif ($ARGV[$i] eq '-y') {
201 $ReportStatus = 1;
202 } else {
203 &PrintUsage;
204 }
205
206 $i++;
207 } #EndWhile
208
209} #EndSub-ParseArgs
210
211sub PrintUsage {
212 die "usage: $0 [-v | --version ] [-t do not send report to tinderbox server]\n";
213}
214
215sub PrintEnv {
216 my ($key);
217 foreach $key (keys %ENV) {
218 print LOG "$key = $ENV{$key}\n";
219 print "$key = $ENV{$key}\n";
220 }
221
222 # Print the NPTest variables
223 if (-e "/var/tmp/NPTest.cache") {
224 open F, "/var/tmp/NPTest.cache";
225 print LOG "NPTest variables:\n";
226 print LOG <F>;
227 close F;
228 }
229
230} #EndSub-PrintEnv
231
232sub SetupPath {
233 my($Path);
234 $Path = $ENV{PATH};
235 print "Path before: $Path\n";
236
237 # Don't alter path if we're building off a repository tree;
238 # SunOS make will be used only for snapshots and releases.
239 if ( $OS eq 'SunOS' && !( -e '.svn' || -e '.git' )) {
240 $ENV{'PATH'} = '/usr/ccs/bin:' . $ENV{'PATH'};
241 }
242
243 $Path = $ENV{PATH};
244 print "Path After: $Path\n";
245} #EndSub-SetupPath
246
247sub configure {
248 # Configure
249 print LOG "./configure --enable-extra-opts --enable-libtap $ConfigureArgs 2>&1\n";
250 open (CONFIGURE, "./configure --enable-extra-opts --enable-libtap $ConfigureArgs 2>&1 |") || die "../configure: $!\n";
251 while (<CONFIGURE>) {
252 print $_;
253 print LOG $_;
254 }
255 close(CONFIGURE);
256 return ! $?;
257}
258
259sub make {
260 # Building
261 print LOG "make 2>&1\n";
262 open( MAKE, "make 2>&1 |");
263 while ( <MAKE> ) {
264 print $_;
265 print LOG $_;
266 }
267 close( MAKE);
268 return ! $?;
269}
270
271sub maketest {
272 # Tests
273 print LOG "LANG=C make test 2>&1 && make install DESTDIR=$TmpDir/tinderbox_build.$$ 2>&1 && make install-strip DESTDIR=$TmpDir/tinderbox_build2.$$ 2>&1\n";
274 open( MAKE, "LANG=C make test 2>&1 && make install DESTDIR=$TmpDir/tinderbox_build.$$ 2>&1 && make install-strip DESTDIR=$TmpDir/tinderbox_build2.$$ 2>&1 |");
275 while ( <MAKE> ) {
276 print $_;
277 print LOG $_;
278 }
279 close( MAKE);
280 my $rc = $?;
281 system("rm -fr $TmpDir/tinderbox_build.$$ $TmpDir/tinderbox_build2.$$");
282 return ! $rc;
283}
284
285# Main function
286&ParseArgs;
287&SetupPath;
288&BuildIt;
289
2901;