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.spec31
-rw-r--r--.github/os_detect.sh10
-rwxr-xr-x.github/prepare_debian.sh11
-rw-r--r--.github/workflows/codeql-analysis.yml24
-rw-r--r--.github/workflows/spellcheck.yml3
-rw-r--r--.github/workflows/test-next.yml90
-rw-r--r--.github/workflows/test.yml20
-rw-r--r--.gitignore28
-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.ac182
-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.am19
-rw-r--r--lib/extra_opts.c172
-rw-r--r--lib/extra_opts.h1
-rw-r--r--lib/maxfd.c38
-rw-r--r--lib/maxfd.h6
-rw-r--r--lib/monitoringplug.h7
-rw-r--r--lib/output.c636
-rw-r--r--lib/output.h117
-rw-r--r--lib/parse_ini.c342
-rw-r--r--lib/parse_ini.h1
-rw-r--r--lib/perfdata.c649
-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.c359
-rw-r--r--lib/tests/test_cmd.c282
-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.c317
-rw-r--r--lib/tests/test_generic_output.t6
-rw-r--r--lib/tests/test_ini1.c132
-rw-r--r--lib/tests/test_ini3.c37
-rw-r--r--lib/tests/test_opts1.c128
-rw-r--r--lib/tests/test_opts2.c148
-rw-r--r--lib/tests/test_opts3.c37
-rw-r--r--lib/tests/test_tcp.c62
-rw-r--r--lib/tests/test_utils.c549
-rw-r--r--lib/thresholds.c71
-rw-r--r--lib/thresholds.h31
-rw-r--r--lib/utils_base.c643
-rw-r--r--lib/utils_base.h74
-rw-r--r--lib/utils_cmd.c398
-rw-r--r--lib/utils_cmd.h26
-rw-r--r--lib/utils_disk.c270
-rw-r--r--lib/utils_disk.h52
-rw-r--r--lib/utils_tcp.c101
-rw-r--r--lib/utils_tcp.h13
-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.c1648
-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/pst3.c441
-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.am93
-rw-r--r--plugins/check_apt.c824
-rw-r--r--plugins/check_apt.d/config.h46
-rw-r--r--plugins/check_by_ssh.c699
-rw-r--r--plugins/check_by_ssh.d/config.h58
-rw-r--r--plugins/check_cluster.c351
-rw-r--r--plugins/check_cluster.d/config.h33
-rw-r--r--plugins/check_curl.c4203
-rw-r--r--plugins/check_curl.d/check_curl_helpers.c1267
-rw-r--r--plugins/check_curl.d/check_curl_helpers.h124
-rw-r--r--plugins/check_curl.d/config.h116
-rw-r--r--plugins/check_dbi.c1080
-rw-r--r--plugins/check_dbi.d/config.h63
-rw-r--r--plugins/check_dig.c667
-rw-r--r--plugins/check_dig.d/config.h40
-rw-r--r--plugins/check_disk.c2341
-rw-r--r--plugins/check_disk.d/utils_disk.c528
-rw-r--r--plugins/check_disk.d/utils_disk.h160
-rw-r--r--plugins/check_dns.c1205
-rw-r--r--plugins/check_dns.d/config.h34
-rw-r--r--plugins/check_dummy.c198
-rw-r--r--plugins/check_fping.c1050
-rw-r--r--plugins/check_fping.d/config.h81
-rw-r--r--plugins/check_game.c604
-rw-r--r--plugins/check_game.d/config.h30
-rw-r--r--plugins/check_hpjd.c543
-rw-r--r--plugins/check_hpjd.d/config.h25
-rw-r--r--plugins/check_http.c3583
-rw-r--r--plugins/check_ide_smart.c580
-rw-r--r--plugins/check_ldap.c618
-rw-r--r--plugins/check_ldap.d/config.h60
-rw-r--r--plugins/check_load.c662
-rw-r--r--plugins/check_load.d/config.h30
-rw-r--r--plugins/check_mrtg.c552
-rw-r--r--plugins/check_mrtg.d/config.h36
-rw-r--r--plugins/check_mrtgtraf.c511
-rw-r--r--plugins/check_mrtgtraf.d/config.h30
-rw-r--r--plugins/check_mysql.c868
-rw-r--r--plugins/check_mysql.d/config.h58
-rw-r--r--plugins/check_mysql_query.c470
-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.c1218
-rw-r--r--plugins/check_nt.d/config.h53
-rw-r--r--plugins/check_ntp.c762
-rw-r--r--plugins/check_ntp_peer.c869
-rw-r--r--plugins/check_ntp_peer.d/config.h67
-rw-r--r--plugins/check_ntp_time.c711
-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.c794
-rw-r--r--plugins/check_pgsql.d/config.h61
-rw-r--r--plugins/check_ping.c903
-rw-r--r--plugins/check_ping.d/config.h46
-rw-r--r--plugins/check_procs.c1186
-rw-r--r--plugins/check_procs.d/config.h75
-rw-r--r--plugins/check_radius.c557
-rw-r--r--plugins/check_radius.d/config.h42
-rw-r--r--plugins/check_real.c579
-rw-r--r--plugins/check_real.d/config.h37
-rw-r--r--plugins/check_smtp.c1196
-rw-r--r--plugins/check_smtp.d/config.h92
-rw-r--r--plugins/check_snmp.c2072
-rw-r--r--plugins/check_snmp.d/check_snmp_helpers.c934
-rw-r--r--plugins/check_snmp.d/check_snmp_helpers.h71
-rw-r--r--plugins/check_snmp.d/config.h81
-rw-r--r--plugins/check_ssh.c523
-rw-r--r--plugins/check_ssh.d/config.h29
-rw-r--r--plugins/check_swap.c844
-rw-r--r--plugins/check_swap.d/check_swap.h49
-rw-r--r--plugins/check_swap.d/swap.c471
-rw-r--r--plugins/check_tcp.c1124
-rw-r--r--plugins/check_tcp.d/config.h84
-rw-r--r--plugins/check_time.c527
-rw-r--r--plugins/check_time.d/config.h42
-rw-r--r--plugins/check_ups.c377
-rw-r--r--plugins/check_ups.d/config.h54
-rw-r--r--plugins/check_users.c433
-rw-r--r--plugins/check_users.d/config.h20
-rw-r--r--plugins/check_users.d/users.c169
-rw-r--r--plugins/check_users.d/users.h18
-rw-r--r--plugins/common.h200
-rw-r--r--plugins/negate.c364
-rw-r--r--plugins/negate.d/config.h24
-rw-r--r--plugins/netutils.c447
-rw-r--r--plugins/netutils.h152
-rw-r--r--plugins/picohttpparser/picohttpparser.c1140
-rw-r--r--plugins/picohttpparser/picohttpparser.h31
-rw-r--r--plugins/popen.c322
-rw-r--r--plugins/popen.h20
-rw-r--r--plugins/runcmd.c278
-rw-r--r--plugins/runcmd.h47
-rw-r--r--plugins/sslutils.c444
-rw-r--r--plugins/t/check_apt.t14
-rw-r--r--plugins/t/check_curl.t49
-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_snmp.t103
-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/t/check_users.t4
-rwxr-xr-xplugins/tests/check_curl.t89
-rwxr-xr-xplugins/tests/check_snmp.t159
-rw-r--r--plugins/tests/check_snmp_agent.pl78
-rw-r--r--plugins/tests/conf/snmpd.conf2
-rw-r--r--plugins/tests/test_check_disk.c213
-rwxr-xr-xplugins/tests/test_check_disk.t6
-rw-r--r--plugins/tests/test_check_snmp.c175
-rwxr-xr-xplugins/tests/test_check_snmp.t6
-rw-r--r--plugins/tests/test_check_swap.c21
-rwxr-xr-xplugins/tests/test_check_swap.t6
-rw-r--r--plugins/tests/var/proc_meminfo55
-rw-r--r--plugins/urlize.c219
-rw-r--r--plugins/utils.c729
-rw-r--r--plugins/utils.h159
-rw-r--r--tap/tap.c151
-rw-r--r--tap/tap.h65
-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
-rw-r--r--tools/mini_epn.c96
-rwxr-xr-xtools/opttest.pl74
-rwxr-xr-xtools/tinderbox_build290
622 files changed, 47795 insertions, 32410 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..ce22606b 100644
--- a/.github/monitoring-plugins.spec
+++ b/.github/monitoring-plugins.spec
@@ -88,6 +88,9 @@ BuildRequires: postgresql-devel
88# check_radius 88# check_radius
89BuildRequires: radcli-devel 89BuildRequires: radcli-devel
90 90
91# check_snmp
92BuildRequires: net-snmp-devel
93
91%description 94%description
92Common files for Monitoring Plugins 95Common files for Monitoring Plugins
93 96
@@ -191,9 +194,7 @@ Requires: %{name}-nt
191Requires: %{name}-ntp 194Requires: %{name}-ntp
192Requires: %{name}-ntp_peer 195Requires: %{name}-ntp_peer
193Requires: %{name}-ntp_time 196Requires: %{name}-ntp_time
194Requires: %{name}-nwstat
195Requires: %{name}-oracle 197Requires: %{name}-oracle
196Requires: %{name}-overcr
197Requires: %{name}-pgsql 198Requires: %{name}-pgsql
198Requires: %{name}-ping 199Requires: %{name}-ping
199Requires: %{name}-procs 200Requires: %{name}-procs
@@ -703,19 +704,6 @@ Provides check_ntp_time of the Monitoring Plugins.
703 704
704 705
705 706
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 707# check_oracle
720%package oracle 708%package oracle
721Summary: Monitoring Plugins - check_oracle 709Summary: Monitoring Plugins - check_oracle
@@ -729,19 +717,6 @@ Provides check_oracle of the Monitoring Plugins.
729 717
730 718
731 719
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 720# check_pgsql
746%package pgsql 721%package pgsql
747Summary: Monitoring Plugins - check_pgsql 722Summary: Monitoring Plugins - check_pgsql
diff --git a/.github/os_detect.sh b/.github/os_detect.sh
index ee9c145d..3c5956de 100644
--- a/.github/os_detect.sh
+++ b/.github/os_detect.sh
@@ -1,10 +1,17 @@
1#!/bin/sh -e 1#!/bin/sh -e
2
3. /etc/os-release
4
2# workaround for really bare-bones Archlinux containers: 5# workaround for really bare-bones Archlinux containers:
3if [ -x "$(command -v pacman)" ]; then 6if [ -x "$(command -v pacman)" ]; then
4 pacman --noconfirm -Sy 7 pacman --noconfirm -Sy
5 pacman --noconfirm -S grep gawk sed 8 pacman --noconfirm -S grep gawk sed
6fi 9fi
7 10
11if [ ${ID} == "fedora" -a ${VERSION_ID} -gt 41 ]; then
12 dnf install -y gawk
13fi
14
8os_release_file= 15os_release_file=
9if [ -s "/etc/os-release" ]; then 16if [ -s "/etc/os-release" ]; then
10 os_release_file="/etc/os-release" 17 os_release_file="/etc/os-release"
@@ -15,4 +22,7 @@ else
15 return 1 22 return 1
16fi 23fi
17export distro_id=$(grep '^ID=' $os_release_file|awk -F = '{print $2}'|sed 's/\"//g') 24export distro_id=$(grep '^ID=' $os_release_file|awk -F = '{print $2}'|sed 's/\"//g')
25export version_id=$(grep '^VERSION_ID=' $os_release_file|awk -F = '{print $2}'|sed 's/\"//g')
18export platform_id=$(grep '^PLATFORM_ID=' /etc/os-release|awk -F = '{print $2}'|sed 's/\"//g'| cut -d":" -f2) 26export platform_id=$(grep '^PLATFORM_ID=' /etc/os-release|awk -F = '{print $2}'|sed 's/\"//g'| cut -d":" -f2)
27# Fedora dropped PLATFORM_ID: https://fedoraproject.org/wiki/Changes/Drop_PLATFORM_ID?#Drop_PLATFORM_ID
28if [ -z $platform_id ]; then export platform_id=$(echo ${distro_id:0:1}${version_id}); fi
diff --git a/.github/prepare_debian.sh b/.github/prepare_debian.sh
index 3f4674a2..cffe98c5 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
@@ -24,6 +24,7 @@ apt-get -y install perl \
24 libpq-dev \ 24 libpq-dev \
25 libradcli-dev \ 25 libradcli-dev \
26 libnet-snmp-perl \ 26 libnet-snmp-perl \
27 libsnmp-dev \
27 procps \ 28 procps \
28 libdbi0-dev \ 29 libdbi0-dev \
29 libdbd-sqlite3 \ 30 libdbd-sqlite3 \
@@ -59,9 +60,11 @@ apt-get -y install perl \
59 mariadb-server \ 60 mariadb-server \
60 mariadb-client \ 61 mariadb-client \
61 libmariadb-dev \ 62 libmariadb-dev \
63 libmariadb-dev-compat \
62 cron \ 64 cron \
63 iputils-ping \ 65 iputils-ping \
64 iproute2 66 iproute2 \
67 libjson-perl
65 68
66# remove ipv6 interface from hosts 69# remove ipv6 interface from hosts
67sed '/^::1/d' /etc/hosts > /tmp/hosts 70sed '/^::1/d' /etc/hosts > /tmp/hosts
@@ -109,6 +112,8 @@ mkdir -p /var/lib/snmp/mib_indexes
109sed -e 's/^agentaddress.*/agentaddress 127.0.0.1/' -i /etc/snmp/snmpd.conf 112sed -e 's/^agentaddress.*/agentaddress 127.0.0.1/' -i /etc/snmp/snmpd.conf
110service snmpd start 113service snmpd start
111 114
115sed 's/^mibs ://' -i /etc/snmp/snmp.conf
116
112# start cron, will be used by check_nagios 117# start cron, will be used by check_nagios
113cron 118cron
114 119
@@ -127,5 +132,5 @@ sed "/NP_HOST_TLS_CERT/s/.*/'NP_HOST_TLS_CERT' => '$(hostname)',/" -i /src/.gith
127 132
128# create some test files to lower inodes 133# create some test files to lower inodes
129for i in $(seq 10); do 134for i in $(seq 10); do
130 touch /media/ramdisk2/test.$1 135 touch /media/ramdisk2/test.$i
131done 136done
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index c402e0cf..8f191037 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -13,6 +13,7 @@
13name: "CodeQL" 13name: "CodeQL"
14 14
15on: 15on:
16 workflow_dispatch: {}
16 push: 17 push:
17 branches: [master] 18 branches: [master]
18 pull_request: 19 pull_request:
@@ -40,11 +41,11 @@ jobs:
40 41
41 steps: 42 steps:
42 - name: Checkout repository 43 - name: Checkout repository
43 uses: actions/checkout@v4 44 uses: actions/checkout@v5
44 45
45 # Initializes the CodeQL tools for scanning. 46 # Initializes the CodeQL tools for scanning.
46 - name: Initialize CodeQL 47 - name: Initialize CodeQL
47 uses: github/codeql-action/init@v3 48 uses: github/codeql-action/init@v4
48 with: 49 with:
49 languages: ${{ matrix.language }} 50 languages: ${{ matrix.language }}
50 # If you wish to specify custom queries, you can do so here or in a config file. 51 # If you wish to specify custom queries, you can do so here or in a config file.
@@ -56,9 +57,20 @@ jobs:
56 run: | 57 run: |
57 sudo apt update 58 sudo apt update
58 sudo apt-get install -y --no-install-recommends m4 gettext automake autoconf make build-essential 59 sudo apt-get install -y --no-install-recommends m4 gettext automake autoconf make build-essential
59 sudo apt-get install -y --no-install-recommends perl autotools-dev libdbi-dev libldap2-dev libpq-dev \ 60 sudo apt-get install -y --no-install-recommends perl \
60 libmysqlclient-dev libradcli-dev libkrb5-dev libdbi0-dev \ 61 autotools-dev \
61 libdbd-sqlite3 libssl-dev libcurl4-openssl-dev liburiparser-dev 62 libdbi-dev \
63 libldap2-dev \
64 libpq-dev \
65 libmysqlclient-dev \
66 libradcli-dev \
67 libkrb5-dev \
68 libdbi0-dev \
69 libdbd-sqlite3 \
70 libssl-dev \
71 libcurl4-openssl-dev \
72 liburiparser-dev \
73 libsnmp-dev
62 74
63 - name: Configure build 75 - name: Configure build
64 run: | 76 run: |
@@ -70,4 +82,4 @@ jobs:
70 make 82 make
71 83
72 - name: Perform CodeQL Analysis 84 - name: Perform CodeQL Analysis
73 uses: github/codeql-action/analyze@v3 85 uses: github/codeql-action/analyze@v4
diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml
index 72f7c7eb..14b82781 100644
--- a/.github/workflows/spellcheck.yml
+++ b/.github/workflows/spellcheck.yml
@@ -2,6 +2,7 @@
2name: Spellcheck 2name: Spellcheck
3 3
4on: 4on:
5 workflow_dispatch: {}
5 # Run for pushes on any branch 6 # Run for pushes on any branch
6 push: 7 push:
7 branches: 8 branches:
@@ -17,7 +18,7 @@ jobs:
17 runs-on: ubuntu-latest 18 runs-on: ubuntu-latest
18 steps: 19 steps:
19 - name: Checkout 20 - name: Checkout
20 uses: actions/checkout@v4 21 uses: actions/checkout@v5
21 - name: Codespell 22 - name: Codespell
22 uses: codespell-project/actions-codespell@v2 23 uses: codespell-project/actions-codespell@v2
23 with: 24 with:
diff --git a/.github/workflows/test-next.yml b/.github/workflows/test-next.yml
new file mode 100644
index 00000000..0e69c251
--- /dev/null
+++ b/.github/workflows/test-next.yml
@@ -0,0 +1,90 @@
1---
2name: Tests Debian:Testing and Fedora:Rawhide
3
4on:
5 workflow_dispatch:
6 inputs:
7 debug_enabled:
8 type: boolean
9 description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
10 required: false
11 default: false
12 push:
13 branches-ignore:
14 - '*'
15 schedule:
16 # Run every week on Monday at 9:00 AM (UTC)
17 - cron: '0 9 * * 1'
18
19jobs:
20 full-test:
21 name: Running unit and integrationt tests
22 runs-on: ubuntu-latest
23 strategy:
24 fail-fast: false
25 matrix:
26 distro:
27 - 'debian:testing'
28 include:
29 - distro: 'debian:testing'
30 prepare: .github/prepare_debian.sh
31 steps:
32 - name: Git clone repository
33 uses: actions/checkout@v5
34 - name: Setup tmate session, see https://github.com/marketplace/actions/debugging-with-tmate
35 uses: mxschmitt/action-tmate@v3
36 if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
37 - name: Run the tests on ${{ matrix.distro }}
38 run: |
39 docker volume create --driver local --opt type=tmpfs --opt device=tmpfs --opt o=size=100m,uid=1000 tmp-vol
40 docker run \
41 -e NPTEST_ACCEPTDEFAULT=1 \
42 -e NPTEST_CACHE="/src/.github/NPTest.cache" \
43 -w /src -v ${PWD}:/src \
44 --tmpfs /media/ramdisk1 \
45 -v /var/run/utmp:/var/run/utmp \
46 --mount source=tmp-vol,destination=/src,target=/media/ramdisk2 \
47 ${{ matrix.distro }} \
48 /bin/sh -c '${{ matrix.prepare }} && \
49 tools/setup && \
50 ./configure --enable-libtap && \
51 make && \
52 make test && \
53 make dist && \
54 tar zxf monitoring-plugins-*.tar.gz && \
55 cd monitoring-plugins-*/ && \
56 ./configure && \
57 make'
58 docker container prune -f
59 docker volume prune -f
60
61 build-test:
62 name: Running rpm build test on ${{ matrix.distro }}
63 runs-on: ubuntu-latest
64 strategy:
65 fail-fast: false
66 matrix:
67 include:
68 - {"distro": "fedora:rawhide", "build": ".github/mock.sh"}
69 steps:
70 - name: Git clone repository
71 uses: actions/checkout@v5
72 - name: Setup tmate session, see https://github.com/marketplace/actions/debugging-with-tmate
73 uses: mxschmitt/action-tmate@v3
74 if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
75 - name: Run the tests on ${{ matrix.distro }}
76 run: |
77 docker volume create --driver local --opt type=tmpfs --opt device=tmpfs --opt o=size=100m,uid=1000 tmp-vol
78 docker run \
79 --privileged=true \
80 -e NPTEST_ACCEPTDEFAULT=1 \
81 -e NPTEST_CACHE="/src/.github/NPTest.cache" \
82 -w /src -v ${PWD}:/src \
83 --tmpfs /media/ramdisk1 \
84 -v /var/run/utmp:/var/run/utmp \
85 --mount source=tmp-vol,destination=/src,target=/media/ramdisk2 \
86 ${{ matrix.distro }} \
87 /bin/sh -c '${{ matrix.build }} && \
88 ls -la'
89 docker container prune -f
90 docker volume prune -f
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 33220d6d..1ac8aaf3 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -2,6 +2,13 @@
2name: Tests 2name: Tests
3 3
4on: 4on:
5 workflow_dispatch:
6 inputs:
7 debug_enabled:
8 type: boolean
9 description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
10 required: false
11 default: false
5 push: 12 push:
6 branches: 13 branches:
7 - '*' 14 - '*'
@@ -21,7 +28,10 @@ jobs:
21 prepare: .github/prepare_debian.sh 28 prepare: .github/prepare_debian.sh
22 steps: 29 steps:
23 - name: Git clone repository 30 - name: Git clone repository
24 uses: actions/checkout@v4 31 uses: actions/checkout@v5
32 - name: Setup tmate session, see https://github.com/marketplace/actions/debugging-with-tmate
33 uses: mxschmitt/action-tmate@v3
34 if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
25 - name: Run the tests on ${{ matrix.distro }} 35 - name: Run the tests on ${{ matrix.distro }}
26 run: | 36 run: |
27 docker volume create --driver local --opt type=tmpfs --opt device=tmpfs --opt o=size=100m,uid=1000 tmp-vol 37 docker volume create --driver local --opt type=tmpfs --opt device=tmpfs --opt o=size=100m,uid=1000 tmp-vol
@@ -35,7 +45,7 @@ jobs:
35 ${{ matrix.distro }} \ 45 ${{ matrix.distro }} \
36 /bin/sh -c '${{ matrix.prepare }} && \ 46 /bin/sh -c '${{ matrix.prepare }} && \
37 tools/setup && \ 47 tools/setup && \
38 ./configure --enable-libtap --with-ipv6=no && \ 48 ./configure --enable-libtap && \
39 make && \ 49 make && \
40 make test && \ 50 make test && \
41 make dist && \ 51 make dist && \
@@ -54,13 +64,15 @@ jobs:
54 matrix: 64 matrix:
55 include: 65 include:
56 - {"distro": "fedora:latest", "build": ".github/mock.sh"} 66 - {"distro": "fedora:latest", "build": ".github/mock.sh"}
57 - {"distro": "fedora:rawhide", "build": ".github/mock.sh"}
58 - {"distro": "rockylinux:8", "build": ".github/mock.sh"} 67 - {"distro": "rockylinux:8", "build": ".github/mock.sh"}
59 - {"distro": "almalinux:9", "build": ".github/mock.sh"} 68 - {"distro": "almalinux:9", "build": ".github/mock.sh"}
60# - {"distro": "oraclelinux:9", "build": ".github/mock.sh"} 69# - {"distro": "oraclelinux:9", "build": ".github/mock.sh"}
61 steps: 70 steps:
62 - name: Git clone repository 71 - name: Git clone repository
63 uses: actions/checkout@v4 72 uses: actions/checkout@v5
73 - name: Setup tmate session, see https://github.com/marketplace/actions/debugging-with-tmate
74 uses: mxschmitt/action-tmate@v3
75 if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
64 - name: Run the tests on ${{ matrix.distro }} 76 - name: Run the tests on ${{ matrix.distro }}
65 run: | 77 run: |
66 docker volume create --driver local --opt type=tmpfs --opt device=tmpfs --opt o=size=100m,uid=1000 tmp-vol 78 docker volume create --driver local --opt type=tmpfs --opt device=tmpfs --opt o=size=100m,uid=1000 tmp-vol
diff --git a/.gitignore b/.gitignore
index 6f903d61..00e19d52 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
@@ -195,6 +197,8 @@ NP-VERSION-FILE
195/plugins/check_udp 197/plugins/check_udp
196/plugins/check_ups 198/plugins/check_ups
197/plugins/check_users 199/plugins/check_users
200/plugins/check_users.d/.deps
201/plugins/check_users.d/.dirstamp
198/plugins/check_vsz 202/plugins/check_vsz
199/plugins/config.h 203/plugins/config.h
200/plugins/config.h.in 204/plugins/config.h.in
@@ -220,8 +224,22 @@ NP-VERSION-FILE
220/plugins/tests/Makefile 224/plugins/tests/Makefile
221/plugins/tests/Makefile.in 225/plugins/tests/Makefile.in
222/plugins/tests/test_utils 226/plugins/tests/test_utils
223/plugins/tests/test_disk 227/plugins/tests/test_check_disk
228/plugins/tests/test_check_swap
224/plugins/tests/.deps 229/plugins/tests/.deps
230/plugins/tests/.dirstamp
231
232# /plugins/check_swap.d
233/plugins/check_swap.d/.deps
234/plugins/check_swap.d/.dirstamp
235
236# /plugins/check_snmp.d
237/plugins/check_snmp.d/.deps
238/plugins/check_snmp.d/.dirstamp
239
240# /plugins/check_curl.d
241/plugins/check_curl.d/.deps
242/plugins/check_curl.d/.dirstamp
225 243
226# /plugins-root/ 244# /plugins-root/
227/plugins-root/.deps 245/plugins-root/.deps
@@ -231,6 +249,8 @@ NP-VERSION-FILE
231/plugins-root/check_dhcp 249/plugins-root/check_dhcp
232/plugins-root/check_icmp 250/plugins-root/check_icmp
233/plugins-root/pst3 251/plugins-root/pst3
252/plugins-root/check_icmp.d/.dirstamp
253/plugins-root/check_icmp.d/.deps
234 254
235# /plugins-scripts/ 255# /plugins-scripts/
236/plugins-scripts/Makefile 256/plugins-scripts/Makefile
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..705183a2 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,19 @@ 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 AC_MSG_WARN([Get snmpget from https://net-snmp.sourceforge.io/ to build the check_hpjd and check_snmp plugins])
1475])
1502 1476
1503if ( $PERL -M"Net::SNMP 3.6" -e 'exit' 2>/dev/null ) 1477if ( $PERL -M"Net::SNMP 3.6" -e 'exit' 2>/dev/null )
1504then 1478then
@@ -1508,6 +1482,16 @@ else
1508 AC_MSG_WARN([Tried $PERL - install Net::SNMP perl module if you want to use the perl snmp plugins]) 1482 AC_MSG_WARN([Tried $PERL - install Net::SNMP perl module if you want to use the perl snmp plugins])
1509fi 1483fi
1510 1484
1485dnl Check whether DES encryption is available (might not on RHEL)
1486AC_COMPILE_IFELSE(
1487 [AC_LANG_PROGRAM(
1488 [[#include <net-snmp/net-snmp-config.h>
1489 #include <net-snmp/net-snmp-includes.h>]], [[oid *foo = usmDESPrivProtocol;]]
1490 )],
1491 [AC_DEFINE(HAVE_USM_DES_PRIV_PROTOCOL,1,Define whether we have DES Privacy Protocol)],
1492 []
1493)
1494
1511AC_PATH_PROG(PATH_TO_QUAKESTAT,quakestat) 1495AC_PATH_PROG(PATH_TO_QUAKESTAT,quakestat)
1512AC_PATH_PROG(PATH_TO_QSTAT,qstat) 1496AC_PATH_PROG(PATH_TO_QSTAT,qstat)
1513AC_ARG_WITH(qstat_command, 1497AC_ARG_WITH(qstat_command,
@@ -1534,21 +1518,47 @@ then
1534fi 1518fi
1535 1519
1536AC_PATH_PROG(PATH_TO_FPING,fping) 1520AC_PATH_PROG(PATH_TO_FPING,fping)
1537AC_PATH_PROG(PATH_TO_FPING6,fping6)
1538 1521
1539AC_ARG_WITH(fping_command, 1522AC_ARG_WITH(fping_command,
1540 ACX_HELP_STRING([--with-fping-command=PATH], 1523 ACX_HELP_STRING([--with-fping-command=PATH],
1541 [Path to fping command]), PATH_TO_FPING=$withval) 1524 [Path to fping command]), PATH_TO_FPING=$withval)
1542AC_ARG_WITH(fping6_command, 1525if 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]) 1526 AC_DEFINE_UNQUOTED(PATH_TO_FPING,"$PATH_TO_FPING",[path to fping])
1549 EXTRAS="$EXTRAS check_fping\$(EXEEXT)" 1527 EXTRAS="$EXTRAS check_fping\$(EXEEXT)"
1550 if test x"$with_ipv6" != xno && test -n "$PATH_TO_FPING6"; then 1528
1551 AC_DEFINE_UNQUOTED(PATH_TO_FPING6,"$PATH_TO_FPING6",[path to fping6]) 1529 if test -z "$($PATH_TO_FPING --version)" ; then
1530 AC_MSG_NOTICE([failed to get version of fping])
1531 else
1532 FPING_MAJOR_VERSION="$($PATH_TO_FPING --version | sed 's/.*fping: Version //' | sed 's/\..*//')"
1533 FPING_MINOR_VERSION="$($PATH_TO_FPING --version | sed 's/.*fping: Version //' | sed 's/.*\.//')"
1534
1535 if test $FPING_MAJOR_VERSION -eq 5 ; then
1536 if test $FPING_MINOR_VERSION -ge 3 ; then
1537 AC_DEFINE(FPING_VERSION_5_3_OR_HIGHER, "true", [fping is of version 5.3 or higher])
1538 AC_MSG_NOTICE([fping is of version 5.3 or higher])
1539 AC_DEFINE(FPING_VERSION_5_2_OR_HIGHER, "true", [fping is of version 5.2 or higher])
1540 AC_MSG_NOTICE([fping is of version 5.2 or higher])
1541 elif test $FPING_MINOR_VERSION -ge 2 ; then
1542 AC_DEFINE(FPING_VERSION_5_2_OR_HIGHER, "true", [fping is of version 5.2 or higher])
1543 AC_MSG_NOTICE([fping is of version 5.2 or higher])
1544 else
1545 AC_MSG_NOTICE([fping is of a version lower then 5.2])
1546 fi
1547
1548 elif $FPING_MAJOR_VERSION > 5 ; then
1549 AC_DEFINE(FPING_VERSION_5_2_OR_HIGHER, "true", [fping is of version 5.2 or higher])
1550 AC_MSG_NOTICE([fping is of version 5.2 or higher])
1551 AC_DEFINE(FPING_VERSION_5_3_OR_HIGHER, "true", [fping is of version 5.2 or higher])
1552 AC_MSG_NOTICE([fping is of version 5.3 or higher])
1553 fi
1554
1555 if test "`fping --version | sed 's/.*fping: Version //'`" = "5.2" ; then
1556 AC_DEFINE(FPING_VERSION, "5.2", [the version of fping available])
1557 AC_MSG_NOTICE([fping version: 5.2])
1558 elif test "`fping --version | sed 's/.*fping: Version //'`" = "5.3"; then
1559 AC_DEFINE(FPING_VERSION, "5.3", [the version of fping available])
1560 AC_MSG_NOTICE([fping version: 5.3])
1561 fi
1552 fi 1562 fi
1553else 1563else
1554 AC_MSG_WARN([Get fping from http://www.fping.com in order to make check_fping plugin]) 1564 AC_MSG_WARN([Get fping from http://www.fping.com in order to make check_fping plugin])
@@ -1850,8 +1860,8 @@ AC_SUBST(EXTRAS_ROOT)
1850AC_SUBST(EXTRA_NETOBJS) 1860AC_SUBST(EXTRA_NETOBJS)
1851AC_SUBST(DEPLIBS) 1861AC_SUBST(DEPLIBS)
1852 1862
1853AM_GNU_GETTEXT([external], [need-ngettext]) 1863dnl AM_GNU_GETTEXT([external], [need-ngettext])
1854AM_GNU_GETTEXT_VERSION(0.15) 1864dnl AM_GNU_GETTEXT_VERSION(0.15)
1855 1865
1856dnl Check for Redhat spopen problem 1866dnl Check for Redhat spopen problem
1857dnl Weird problem where ECHILD is returned from a wait call in error 1867dnl Weird problem where ECHILD is returned from a wait call in error
@@ -1861,8 +1871,7 @@ dnl We patch plugins/popen.c
1861dnl Need to add smp because uname different on those 1871dnl Need to add smp because uname different on those
1862dnl Can force patch to be applied with --enable-redhat-pthread-workaround 1872dnl Can force patch to be applied with --enable-redhat-pthread-workaround
1863AC_ARG_ENABLE(redhat-pthread-workaround, 1873AC_ARG_ENABLE(redhat-pthread-workaround,
1864 AC_HELP_STRING([--enable-redhat-pthread-workaround], 1874 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], 1875 [ac_cv_enable_redhat_pthread_workaround=$enableval],
1867 [ac_cv_enable_redhat_pthread_workaround=test]) 1876 [ac_cv_enable_redhat_pthread_workaround=test])
1868if test "$ac_cv_enable_redhat_pthread_workaround" = "test" ; then 1877if test "$ac_cv_enable_redhat_pthread_workaround" = "test" ; then
@@ -1883,8 +1892,7 @@ fi
1883 1892
1884dnl Perl modules 1893dnl Perl modules
1885AC_ARG_ENABLE(perl-modules, 1894AC_ARG_ENABLE(perl-modules,
1886 AC_HELP_STRING([--enable-perl-modules], 1895 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], 1896 [enable_perl_modules=$enableval],
1889 [enable_perl_modules=no]) 1897 [enable_perl_modules=no])
1890if test "$enable_perl_modules" = "yes" ; then 1898if test "$enable_perl_modules" = "yes" ; then
@@ -1911,8 +1919,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?) 1919 AC_MSG_ERROR(No ar found for Solaris - is /usr/ccs/bin in PATH?)
1912fi 1920fi
1913 1921
1914AC_OUTPUT( 1922AC_CONFIG_FILES([Makefile
1915 Makefile
1916 tap/Makefile 1923 tap/Makefile
1917 lib/Makefile 1924 lib/Makefile
1918 plugins/Makefile 1925 plugins/Makefile
@@ -1924,7 +1931,8 @@ AC_OUTPUT(
1924 perlmods/Makefile 1931 perlmods/Makefile
1925 test.pl 1932 test.pl
1926 pkg/solaris/pkginfo 1933 pkg/solaris/pkginfo
1927) 1934])
1935AC_OUTPUT
1928 1936
1929 1937
1930dnl the ones below that are commented out need to be cleaned up 1938dnl 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..27a08278 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -4,11 +4,23 @@ SUBDIRS = . tests
4 4
5noinst_LIBRARIES = libmonitoringplug.a 5noinst_LIBRARIES = libmonitoringplug.a
6 6
7AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \ 7AM_CPPFLAGS = \
8 -I$(srcdir) -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins 8 -I$(srcdir) -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins
9 9
10libmonitoringplug_a_SOURCES = utils_base.c utils_disk.c utils_tcp.c utils_cmd.c maxfd.c 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..3fe69014 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,130 @@
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{ 30 if (!str) {
31 if (!str)
32 return false; 31 return false;
33 else if (strspn (str, "-") == 1 || strspn (str, "-") == 2) 32 }
33
34 if (strspn(str, "-") == 1 || strspn(str, "-") == 2) {
34 return true; 35 return true;
35 else 36 }
36 return false; 37
38 return false;
37} 39}
38 40
39/* this is the externally visible function used by plugins */ 41/* this is the externally visible function used by plugins */
40char **np_extra_opts(int *argc, char **argv, const char *plugin_name){ 42char **np_extra_opts(int *argc, char **argv, const char *plugin_name) {
41 np_arg_list *extra_args=NULL, *ea1=NULL, *ea_tmp=NULL; 43 if (*argc < 2) {
42 char **argv_new=NULL;
43 char *argptr=NULL;
44 int i, j, optfound, argc_new, ea_num=*argc;
45
46 if(*argc<2) {
47 /* No arguments provided */ 44 /* No arguments provided */
48 return argv; 45 return argv;
49 } 46 }
50 47
51 for(i=1; i<*argc; i++){ 48 np_arg_list *extra_args = NULL;
52 argptr=NULL; 49 np_arg_list *ea1 = NULL;
53 optfound=0; 50 np_arg_list *ea_tmp = NULL;
51 char *argptr = NULL;
52 int optfound;
53 size_t ea_num = (size_t)*argc;
54
55 for (int i = 1; i < *argc; i++) {
56 argptr = NULL;
57 optfound = 0;
54 58
55 /* Do we have an extra-opts parameter? */ 59 /* Do we have an extra-opts parameter? */
56 if(strncmp(argv[i], "--extra-opts=", 13)==0){ 60 if (strncmp(argv[i], "--extra-opts=", 13) == 0) {
57 /* It is a single argument with value */ 61 /* It is a single argument with value */
58 argptr=argv[i]+13; 62 argptr = argv[i] + 13;
59 /* Delete the extra opts argument */ 63 /* Delete the extra opts argument */
60 for(j=i;j<*argc;j++) argv[j]=argv[j+1]; 64 for (int j = i; j < *argc; j++) {
65 argv[j] = argv[j + 1];
66 }
67
61 i--; 68 i--;
62 *argc-=1; 69 *argc -= 1;
63 }else if(strcmp(argv[i], "--extra-opts")==0){ 70 } else if (strcmp(argv[i], "--extra-opts") == 0) {
64 if((i+1<*argc)&&!is_option2(argv[i+1])){ 71 if ((i + 1 < *argc) && !is_option2(argv[i + 1])) {
65 /* It is a argument with separate value */ 72 /* It is a argument with separate value */
66 argptr=argv[i+1]; 73 argptr = argv[i + 1];
67 /* Delete the extra-opts argument/value */ 74 /* Delete the extra-opts argument/value */
68 for(j=i;j<*argc-1;j++) argv[j]=argv[j+2]; 75 for (int j = i; j < *argc - 1; j++) {
69 i-=2; 76 argv[j] = argv[j + 2];
70 *argc-=2; 77 }
78
79 i -= 2;
80 *argc -= 2;
71 ea_num--; 81 ea_num--;
72 }else{ 82 } else {
73 /* It has no value */ 83 /* It has no value */
74 optfound=1; 84 optfound = 1;
75 /* Delete the extra opts argument */ 85 /* Delete the extra opts argument */
76 for(j=i;j<*argc;j++) argv[j]=argv[j+1]; 86 for (int j = i; j < *argc; j++) {
87 argv[j] = argv[j + 1];
88 }
89
77 i--; 90 i--;
78 *argc-=1; 91 *argc -= 1;
79 } 92 }
80 } 93 }
81 94
82 /* If we found extra-opts, expand them and store them for later*/ 95 /* If we found extra-opts, expand them and store them for later*/
83 if(argptr||optfound){ 96 if (argptr || optfound) {
84 /* Process ini section, returning a linked list of arguments */ 97 /* Process ini section, returning a linked list of arguments */
85 ea1=np_get_defaults(argptr, plugin_name); 98 ea1 = np_get_defaults(argptr, plugin_name);
86 if(ea1==NULL) { 99 if (ea1 == NULL) {
87 /* no extra args (empty section)? */ 100 /* no extra args (empty section)? */
88 ea_num--; 101 ea_num--;
89 continue; 102 continue;
90 } 103 }
91 104
92 /* append the list to extra_args */ 105 /* append the list to extra_args */
93 if(extra_args==NULL){ 106 if (extra_args == NULL) {
94 extra_args=ea1; 107 extra_args = ea1;
95 while((ea1 = ea1->next)) ea_num++; 108 while ((ea1 = ea1->next)) {
96 }else{ 109 ea_num++;
97 ea_tmp=extra_args; 110 }
98 while(ea_tmp->next) { 111 } else {
99 ea_tmp=ea_tmp->next; 112 ea_tmp = extra_args;
113 while (ea_tmp->next) {
114 ea_tmp = ea_tmp->next;
115 }
116 ea_tmp->next = ea1;
117 while ((ea1 = ea1->next)) {
118 ea_num++;
100 } 119 }
101 ea_tmp->next=ea1;
102 while((ea1 = ea1->next)) ea_num++;
103 } 120 }
104 ea1=ea_tmp=NULL; 121 ea1 = ea_tmp = NULL;
105 } 122 }
106 } /* lather, rince, repeat */ 123 } /* lather, rince, repeat */
107 124
108 if(ea_num==*argc && extra_args==NULL){ 125 if (ea_num == (size_t)*argc && extra_args == NULL) {
109 /* No extra-opts */ 126 /* No extra-opts */
110 return argv; 127 return argv;
111 } 128 }
112 129
113 /* done processing arguments. now create a new argv array... */ 130 /* done processing arguments. now create a new argv array... */
114 argv_new=(char**)malloc((ea_num+1)*sizeof(char**)); 131 char **argv_new = (char **)malloc((ea_num + 1) * sizeof(char **));
115 if(argv_new==NULL) die(STATE_UNKNOWN, _("malloc() failed!\n")); 132 if (argv_new == NULL) {
133 die(STATE_UNKNOWN, _("malloc() failed!\n"));
134 }
116 135
117 /* starting with program name */ 136 /* starting with program name */
118 argv_new[0]=argv[0]; 137 argv_new[0] = argv[0];
119 argc_new=1; 138 int argc_new = 1;
120 /* then parsed ini opts (frying them up in the same run) */ 139 /* then parsed ini opts (frying them up in the same run) */
121 while(extra_args){ 140 while (extra_args) {
122 argv_new[argc_new++]=extra_args->arg; 141 argv_new[argc_new++] = extra_args->arg;
123 ea1=extra_args; 142 ea1 = extra_args;
124 extra_args=extra_args->next; 143 extra_args = extra_args->next;
125 free(ea1); 144 free(ea1);
126 } 145 }
127 /* finally the rest of the argv array */ 146 /* finally the rest of the argv array */
128 for (i=1; i<*argc; i++) argv_new[argc_new++]=argv[i]; 147 for (int i = 1; i < *argc; i++) {
129 *argc=argc_new; 148 argv_new[argc_new++] = argv[i];
149 }
150 *argc = argc_new;
130 /* and terminate. */ 151 /* and terminate. */
131 argv_new[argc_new]=NULL; 152 argv_new[argc_new] = NULL;
132 153
133 return argv_new; 154 return argv_new;
134} 155}
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..a0f79949 100644
--- a/lib/maxfd.c
+++ b/lib/maxfd.c
@@ -1,7 +1,26 @@
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>
3 22
4long mp_open_max (void) { 23long mp_open_max(void) {
5 long maxfd = 0L; 24 long maxfd = 0L;
6 /* Try sysconf(_SC_OPEN_MAX) first, as it can be higher than OPEN_MAX. 25 /* 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 26 * If that fails and the macro isn't defined, we fall back to an educated
@@ -10,17 +29,18 @@ long mp_open_max (void) {
10 29
11#ifdef _SC_OPEN_MAX 30#ifdef _SC_OPEN_MAX
12 errno = 0; 31 errno = 0;
13 if ((maxfd = sysconf (_SC_OPEN_MAX)) < 0) { 32 if ((maxfd = sysconf(_SC_OPEN_MAX)) < 0) {
14 if (errno == 0) 33 if (errno == 0) {
15 maxfd = DEFAULT_MAXFD; /* it's indeterminate */ 34 maxfd = DEFAULT_MAXFD; /* it's indeterminate */
16 else 35 } else {
17 die (STATE_UNKNOWN, _("sysconf error for _SC_OPEN_MAX\n")); 36 die(STATE_UNKNOWN, _("sysconf error for _SC_OPEN_MAX\n"));
37 }
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..f283969f
--- /dev/null
+++ b/lib/output.c
@@ -0,0 +1,636 @@
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,
381 generate_indentation_string(
382 indentation + 1)); // one more indentation to make it look better
383
384 if (*(tmp_string + 1) != '\0') {
385 check.output = tmp_string + 1;
386 have_residual_chars = true;
387 } else {
388 // Null after the \n, so this is the end
389 have_residual_chars = false;
390 break;
391 }
392
393 tmp_string = strchr(check.output, '\n');
394 }
395
396 // add the rest (if any)
397 if (have_residual_chars) {
398 char *tmp = check.output;
399 xasprintf(&check.output, "%s\n%s%s", intermediate_string,
400 generate_indentation_string(indentation + 1), tmp);
401 } else {
402 check.output = intermediate_string;
403 }
404 }
405 asprintf(&result, "%s\\_[%s] - %s", generate_indentation_string(indentation),
406 state_text(mp_compute_subcheck_state(check)), check.output);
407
408 subchecks = check.subchecks;
409
410 while (subchecks != NULL) {
411 asprintf(&result, "%s\n%s", result,
412 fmt_subcheck_output(output_format, subchecks->subcheck, indentation + 1));
413 subchecks = subchecks->next;
414 }
415 return result;
416 }
417 default:
418 die(STATE_UNKNOWN, "Invalid format");
419 }
420}
421
422static inline cJSON *json_serialise_pd_value(mp_perfdata_value value) {
423 cJSON *result = cJSON_CreateObject();
424
425 switch (value.type) {
426 case PD_TYPE_DOUBLE:
427 cJSON_AddStringToObject(result, "type", "double");
428 break;
429 case PD_TYPE_INT:
430 cJSON_AddStringToObject(result, "type", "int");
431 break;
432 case PD_TYPE_UINT:
433 cJSON_AddStringToObject(result, "type", "uint");
434 break;
435 case PD_TYPE_NONE:
436 die(STATE_UNKNOWN, "Perfdata type was None in json_serialise_pd_value");
437 }
438 cJSON_AddStringToObject(result, "value", pd_value_to_string(value));
439
440 return result;
441}
442
443static inline cJSON *json_serialise_range(mp_range range) {
444 cJSON *result = cJSON_CreateObject();
445
446 if (range.alert_on_inside_range) {
447 cJSON_AddBoolToObject(result, "alert_on_inside", true);
448 } else {
449 cJSON_AddBoolToObject(result, "alert_on_inside", false);
450 }
451
452 if (range.end_infinity) {
453 cJSON_AddStringToObject(result, "end", "inf");
454 } else {
455 cJSON_AddItemToObject(result, "end", json_serialise_pd_value(range.end));
456 }
457
458 if (range.start_infinity) {
459 cJSON_AddStringToObject(result, "start", "inf");
460 } else {
461 cJSON_AddItemToObject(result, "start", json_serialise_pd_value(range.end));
462 }
463
464 return result;
465}
466
467static inline cJSON *json_serialise_pd(mp_perfdata pd_val) {
468 cJSON *result = cJSON_CreateObject();
469
470 // Label
471 cJSON_AddStringToObject(result, "label", pd_val.label);
472
473 // Value
474 cJSON_AddItemToObject(result, "value", json_serialise_pd_value(pd_val.value));
475
476 // Uom
477 cJSON_AddStringToObject(result, "uom", pd_val.uom);
478
479 // Warn/Crit
480 if (pd_val.warn_present) {
481 cJSON *warn = json_serialise_range(pd_val.warn);
482 cJSON_AddItemToObject(result, "warn", warn);
483 }
484 if (pd_val.crit_present) {
485 cJSON *crit = json_serialise_range(pd_val.crit);
486 cJSON_AddItemToObject(result, "crit", crit);
487 }
488
489 if (pd_val.min_present) {
490 cJSON_AddItemToObject(result, "min", json_serialise_pd_value(pd_val.min));
491 }
492 if (pd_val.max_present) {
493 cJSON_AddItemToObject(result, "max", json_serialise_pd_value(pd_val.max));
494 }
495
496 return result;
497}
498
499static inline cJSON *json_serialise_pd_list(pd_list *list) {
500 cJSON *result = cJSON_CreateArray();
501
502 do {
503 cJSON *pd_value = json_serialise_pd(list->data);
504 cJSON_AddItemToArray(result, pd_value);
505 list = list->next;
506 } while (list != NULL);
507
508 return result;
509}
510
511static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck) {
512 cJSON *result = cJSON_CreateObject();
513
514 // Human readable output
515 cJSON *output = cJSON_CreateString(subcheck.output);
516 cJSON_AddItemToObject(result, "output", output);
517
518 // Test state (aka Exit Code)
519 cJSON *state = cJSON_CreateString(state_text(mp_compute_subcheck_state(subcheck)));
520 cJSON_AddItemToObject(result, "state", state);
521
522 // Perfdata
523 if (subcheck.perfdata != NULL) {
524 cJSON *perfdata = json_serialise_pd_list(subcheck.perfdata);
525 cJSON_AddItemToObject(result, "perfdata", perfdata);
526 }
527
528 if (subcheck.subchecks != NULL) {
529 cJSON *subchecks = cJSON_CreateArray();
530
531 mp_subcheck_list *sc = subcheck.subchecks;
532
533 while (sc != NULL) {
534 cJSON *sc_json = json_serialize_subcheck(sc->subcheck);
535 cJSON_AddItemToArray(subchecks, sc_json);
536 sc = sc->next;
537 }
538
539 cJSON_AddItemToObject(result, "checks", subchecks);
540 }
541
542 return result;
543}
544
545/*
546 * Wrapper function to print the output string of a mp_check object
547 * Use this in concrete plugins.
548 */
549void mp_print_output(mp_check check) { puts(mp_fmt_output(check)); }
550
551/*
552 * Convenience function to print the output string of a mp_check object and exit
553 * the program with the resulting state.
554 * Intended to be used to exit a monitoring plugin.
555 */
556void mp_exit(mp_check check) {
557 mp_print_output(check);
558 if (output_format == MP_FORMAT_TEST_JSON) {
559 exit(0);
560 }
561
562 exit(mp_compute_check_state(check));
563}
564
565/*
566 * Function to set the result state of a mp_subcheck object explicitly.
567 * This will overwrite the default state AND states derived from it's subchecks
568 */
569mp_subcheck mp_set_subcheck_state(mp_subcheck check, mp_state_enum state) {
570 check.state = state;
571 check.state_set_explicitly = true;
572 return check;
573}
574
575/*
576 * Function to set the default result state of a mp_subcheck object. This state
577 * will be used if neither an explicit state is set (see *mp_set_subcheck_state*)
578 * nor does it include other subchecks
579 */
580mp_subcheck mp_set_subcheck_default_state(mp_subcheck check, mp_state_enum state) {
581 check.default_state = state;
582 return check;
583}
584
585char *mp_output_format_map[] = {
586 [MP_FORMAT_MULTI_LINE] = "multi-line",
587 [MP_FORMAT_TEST_JSON] = "mp-test-json",
588};
589
590/*
591 * Function to parse the output from a string
592 */
593parsed_output_format mp_parse_output_format(char *format_string) {
594 parsed_output_format result = {
595 .parsing_success = false,
596 .output_format = MP_FORMAT_DEFAULT,
597 };
598
599 for (mp_output_format i = 0; i < (sizeof(mp_output_format_map) / sizeof(char *)); i++) {
600 if (strcasecmp(mp_output_format_map[i], format_string) == 0) {
601 result.parsing_success = true;
602 result.output_format = i;
603 break;
604 }
605 }
606
607 return result;
608}
609
610void mp_set_format(mp_output_format format) { output_format = format; }
611
612mp_output_format mp_get_format(void) { return output_format; }
613
614void mp_set_level_of_detail(mp_output_detail_level level) { level_of_detail = level; }
615
616mp_output_detail_level mp_get_level_of_detail(void) { return level_of_detail; }
617
618mp_state_enum mp_eval_ok(mp_check overall) {
619 (void)overall;
620 return STATE_OK;
621}
622
623mp_state_enum mp_eval_warning(mp_check overall) {
624 (void)overall;
625 return STATE_WARNING;
626}
627
628mp_state_enum mp_eval_critical(mp_check overall) {
629 (void)overall;
630 return STATE_CRITICAL;
631}
632
633mp_state_enum mp_eval_unknown(mp_check overall) {
634 (void)overall;
635 return STATE_UNKNOWN;
636}
diff --git a/lib/output.h b/lib/output.h
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..db337622 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,37 +40,29 @@ typedef struct {
40 char *stanza; 40 char *stanza;
41} np_ini_info; 41} np_ini_info;
42 42
43static char *default_ini_file_names[] = { 43static char *default_ini_file_names[] = {"monitoring-plugins.ini", "plugins.ini",
44 "monitoring-plugins.ini", 44 "nagios-plugins.ini", NULL};
45 "plugins.ini",
46 "nagios-plugins.ini",
47 NULL
48};
49 45
50static char *default_ini_path_names[] = { 46static char *default_ini_path_names[] = {
51 "/usr/local/etc/monitoring-plugins/monitoring-plugins.ini", 47 "/usr/local/etc/monitoring-plugins/monitoring-plugins.ini",
52 "/usr/local/etc/monitoring-plugins.ini", 48 "/usr/local/etc/monitoring-plugins.ini", "/etc/monitoring-plugins/monitoring-plugins.ini",
53 "/etc/monitoring-plugins/monitoring-plugins.ini",
54 "/etc/monitoring-plugins.ini", 49 "/etc/monitoring-plugins.ini",
55 /* deprecated path names (for backward compatibility): */ 50 /* deprecated path names (for backward compatibility): */
56 "/etc/nagios/plugins.ini", 51 "/etc/nagios/plugins.ini", "/usr/local/nagios/etc/plugins.ini",
57 "/usr/local/nagios/etc/plugins.ini", 52 "/usr/local/etc/nagios/plugins.ini", "/etc/opt/nagios/plugins.ini", "/etc/nagios-plugins.ini",
58 "/usr/local/etc/nagios/plugins.ini", 53 "/usr/local/etc/nagios-plugins.ini", "/etc/opt/nagios-plugins.ini", NULL};
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 54
66/* eat all characters from a FILE pointer until n is encountered */ 55/* 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)) 56#define GOBBLE_TO(f, c, n) \
57 do { \
58 (c) = fgetc((f)); \
59 } while ((c) != EOF && (c) != (n))
68 60
69/* internal function that returns the constructed defaults options */ 61/* internal function that returns the constructed defaults options */
70static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts); 62static bool read_defaults(FILE *defaults_file, const char *stanza, np_arg_list **opts);
71 63
72/* internal function that converts a single line into options format */ 64/* internal function that converts a single line into options format */
73static int add_option(FILE *f, np_arg_list **optlst); 65static int add_option(FILE *filePointer, np_arg_list **optlst);
74 66
75/* internal functions to find default file */ 67/* internal functions to find default file */
76static char *default_file(void); 68static char *default_file(void);
@@ -81,10 +73,9 @@ static char *default_file_in_path(void);
81 * [stanza][@filename] 73 * [stanza][@filename]
82 * into its separate parts. 74 * into its separate parts.
83 */ 75 */
84static void 76static 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) 77 size_t locator_len = 0;
86{ 78 size_t stanza_len = 0;
87 size_t locator_len = 0, stanza_len = 0;
88 79
89 /* if locator is NULL we'll use default values */ 80 /* if locator is NULL we'll use default values */
90 if (locator != NULL) { 81 if (locator != NULL) {
@@ -96,63 +87,63 @@ parse_locator(const char *locator, const char *def_stanza, np_ini_info *i)
96 i->stanza = malloc(sizeof(char) * (stanza_len + 1)); 87 i->stanza = malloc(sizeof(char) * (stanza_len + 1));
97 strncpy(i->stanza, locator, stanza_len); 88 strncpy(i->stanza, locator, stanza_len);
98 i->stanza[stanza_len] = '\0'; 89 i->stanza[stanza_len] = '\0';
99 } else {/* otherwise we use the default stanza */ 90 } else { /* otherwise we use the default stanza */
100 i->stanza = strdup(def_stanza); 91 i->stanza = strdup(def_stanza);
101 } 92 }
102 93
103 if (i->stanza == NULL) 94 if (i->stanza == NULL) {
104 die(STATE_UNKNOWN, _("malloc() failed!\n")); 95 die(STATE_UNKNOWN, _("malloc() failed!\n"));
96 }
105 97
106 /* check whether there's an @file part */ 98 /* check whether there's an @file part */
107 if (stanza_len == locator_len) { 99 if (stanza_len == locator_len) {
108 i->file = default_file(); 100 i->file = default_file();
109 i->file_string_on_heap = false; 101 i->file_string_on_heap = false;
110 } else { 102 } else {
111 i->file = strdup(&(locator[stanza_len + 1])); 103 i->file = strdup(&(locator[stanza_len + 1]));
112 i->file_string_on_heap = true; 104 i->file_string_on_heap = true;
113 } 105 }
114 106
115 if (i->file == NULL || i->file[0] == '\0') 107 if (i->file == NULL || i->file[0] == '\0') {
116 die(STATE_UNKNOWN, 108 die(STATE_UNKNOWN, _("Cannot find config file in any standard location.\n"));
117 _("Cannot find config file in any standard location.\n")); 109 }
118} 110}
119 111
120/* 112/*
121 * This is the externally visible function used by extra_opts. 113 * This is the externally visible function used by extra_opts.
122 */ 114 */
123np_arg_list * 115np_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;
127 np_arg_list *defaults = NULL;
128 np_ini_info i;
129 int is_suid_plugin = mp_suid(); 116 int is_suid_plugin = mp_suid();
130 117
131 if (is_suid_plugin && idpriv_temp_drop() == -1) 118 if (is_suid_plugin && idpriv_temp_drop() == -1) {
132 die(STATE_UNKNOWN, _("Cannot drop privileges: %s\n"), 119 die(STATE_UNKNOWN, _("Cannot drop privileges: %s\n"), strerror(errno));
133 strerror(errno)); 120 }
121
122 FILE *inifile = NULL;
123 np_ini_info ini_info;
124 parse_locator(locator, default_section, &ini_info);
125 inifile = strcmp(ini_info.file, "-") == 0 ? stdin : fopen(ini_info.file, "r");
134 126
135 parse_locator(locator, default_section, &i); 127 if (inifile == NULL) {
136 inifile = strcmp(i.file, "-") == 0 ? stdin : fopen(i.file, "r"); 128 die(STATE_UNKNOWN, _("Can't read config file: %s\n"), strerror(errno));
129 }
137 130
138 if (inifile == NULL) 131 np_arg_list *defaults = NULL;
139 die(STATE_UNKNOWN, _("Can't read config file: %s\n"), 132 if (!read_defaults(inifile, ini_info.stanza, &defaults)) {
140 strerror(errno)); 133 die(STATE_UNKNOWN, _("Invalid section '%s' in config file '%s'\n"), ini_info.stanza, ini_info.file);
141 if (!read_defaults(inifile, i.stanza, &defaults)) 134 }
142 die(STATE_UNKNOWN,
143 _("Invalid section '%s' in config file '%s'\n"), i.stanza,
144 i.file);
145 135
146 if (i.file_string_on_heap) { 136 if (ini_info.file_string_on_heap) {
147 free(i.file); 137 free(ini_info.file);
148 } 138 }
149 139
150 if (inifile != stdin) 140 if (inifile != stdin) {
151 fclose(inifile); 141 fclose(inifile);
152 free(i.stanza); 142 }
153 if (is_suid_plugin && idpriv_temp_restore() == -1) 143 free(ini_info.stanza);
154 die(STATE_UNKNOWN, _("Cannot restore privileges: %s\n"), 144 if (is_suid_plugin && idpriv_temp_restore() == -1) {
155 strerror(errno)); 145 die(STATE_UNKNOWN, _("Cannot restore privileges: %s\n"), strerror(errno));
146 }
156 147
157 return defaults; 148 return defaults;
158} 149}
@@ -164,52 +155,58 @@ np_get_defaults(const char *locator, const char *default_section)
164 * be extra careful about user-supplied input (i.e. avoiding possible 155 * be extra careful about user-supplied input (i.e. avoiding possible
165 * format string vulnerabilities, etc). 156 * format string vulnerabilities, etc).
166 */ 157 */
167static int 158static bool read_defaults(FILE *defaults_file, const char *stanza, np_arg_list **opts) {
168read_defaults(FILE *f, const char *stanza, np_arg_list **opts)
169{
170 int c = 0;
171 bool status = false; 159 bool status = false;
172 size_t i, stanza_len; 160 enum {
173 enum { NOSTANZA, WRONGSTANZA, RIGHTSTANZA } stanzastate = NOSTANZA; 161 NOSTANZA,
162 WRONGSTANZA,
163 RIGHTSTANZA
164 } stanzastate = NOSTANZA;
174 165
175 stanza_len = strlen(stanza); 166 size_t stanza_len = strlen(stanza);
176 167
177 /* our little stanza-parsing state machine */ 168 /* our little stanza-parsing state machine */
178 while ((c = fgetc(f)) != EOF) { 169 int current_char = 0;
170 while ((current_char = fgetc(defaults_file)) != EOF) {
179 /* gobble up leading whitespace */ 171 /* gobble up leading whitespace */
180 if (isspace(c)) 172 if (isspace(current_char)) {
181 continue; 173 continue;
182 switch (c) { 174 }
175 switch (current_char) {
183 /* globble up comment lines */ 176 /* globble up comment lines */
184 case ';': 177 case ';':
185 case '#': 178 case '#':
186 GOBBLE_TO(f, c, '\n'); 179 GOBBLE_TO(defaults_file, current_char, '\n');
187 break; 180 break;
188 /* start of a stanza, check to see if it matches */ 181 /* start of a stanza, check to see if it matches */
189 case '[': 182 case '[': {
190 stanzastate = WRONGSTANZA; 183 stanzastate = WRONGSTANZA;
184 size_t i;
191 for (i = 0; i < stanza_len; i++) { 185 for (i = 0; i < stanza_len; i++) {
192 c = fgetc(f); 186 current_char = fgetc(defaults_file);
193 /* strip leading whitespace */ 187 /* strip leading whitespace */
194 if (i == 0) 188 if (i == 0) {
195 for (; isspace(c); c = fgetc(f)) 189 for (; isspace(current_char); current_char = fgetc(defaults_file)) {
196 continue; 190 }
191 }
197 /* nope, read to the end of the line */ 192 /* nope, read to the end of the line */
198 if (c != stanza[i]) { 193 if (current_char != stanza[i]) {
199 GOBBLE_TO(f, c, '\n'); 194 GOBBLE_TO(defaults_file, current_char, '\n');
200 break; 195 break;
201 } 196 }
202 } 197 }
198
203 /* if it matched up to here and the next char is ']'... */ 199 /* if it matched up to here and the next char is ']'... */
204 if (i == stanza_len) { 200 if (i == stanza_len) {
205 c = fgetc(f); 201 current_char = fgetc(defaults_file);
206 /* strip trailing whitespace */ 202 /* strip trailing whitespace */
207 for (; isspace(c); c = fgetc(f)) 203 for (; isspace(current_char); current_char = fgetc(defaults_file)) {
208 continue; 204 }
209 if (c == ']') 205 if (current_char == ']') {
210 stanzastate = RIGHTSTANZA; 206 stanzastate = RIGHTSTANZA;
207 }
211 } 208 }
212 break; 209 } break;
213 /* otherwise, we're in the body of a stanza or a parse error */ 210 /* otherwise, we're in the body of a stanza or a parse error */
214 default: 211 default:
215 switch (stanzastate) { 212 switch (stanzastate) {
@@ -217,18 +214,16 @@ read_defaults(FILE *f, const char *stanza, np_arg_list **opts)
217 * we're dealing with a config error 214 * we're dealing with a config error
218 */ 215 */
219 case NOSTANZA: 216 case NOSTANZA:
220 die(STATE_UNKNOWN, "%s\n", 217 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
221 _("Config file error"));
222 /* we're in a stanza, but for a different plugin */ 218 /* we're in a stanza, but for a different plugin */
223 case WRONGSTANZA: 219 case WRONGSTANZA:
224 GOBBLE_TO(f, c, '\n'); 220 GOBBLE_TO(defaults_file, current_char, '\n');
225 break; 221 break;
226 /* okay, this is where we start taking the config */ 222 /* okay, this is where we start taking the config */
227 case RIGHTSTANZA: 223 case RIGHTSTANZA:
228 ungetc(c, f); 224 ungetc(current_char, defaults_file);
229 if (add_option(f, opts)) { 225 if (add_option(defaults_file, opts)) {
230 die(STATE_UNKNOWN, "%s\n", 226 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
231 _("Config file error"));
232 } 227 }
233 status = true; 228 status = true;
234 break; 229 break;
@@ -246,15 +241,12 @@ read_defaults(FILE *f, const char *stanza, np_arg_list **opts)
246 * --option[=value] 241 * --option[=value]
247 * appending it to the linked list optbuf. 242 * appending it to the linked list optbuf.
248 */ 243 */
249static int 244static int add_option(FILE *filePointer, np_arg_list **optlst) {
250add_option(FILE *f, np_arg_list **optlst) 245 char *linebuf = NULL;
251{ 246 bool done_reading = false;
252 np_arg_list *opttmp = *optlst, *optnew; 247 const size_t read_sz = 8;
253 char *linebuf = NULL, *lineend = NULL, *optptr = NULL, *optend = NULL; 248 size_t linebuf_sz = 0;
254 char *eqptr = NULL, *valptr = NULL, *valend = NULL; 249 size_t read_pos = 0;
255 short done_reading = 0, equals = 0, value = 0;
256 size_t cfg_len = 0, read_sz = 8, linebuf_sz = 0, read_pos = 0;
257 size_t opt_len = 0, val_len = 0;
258 250
259 /* read one line from the file */ 251 /* read one line from the file */
260 while (!done_reading) { 252 while (!done_reading) {
@@ -262,75 +254,101 @@ add_option(FILE *f, np_arg_list **optlst)
262 if (linebuf == NULL || read_pos + read_sz >= linebuf_sz) { 254 if (linebuf == NULL || read_pos + read_sz >= linebuf_sz) {
263 linebuf_sz = linebuf_sz > 0 ? linebuf_sz << 1 : read_sz; 255 linebuf_sz = linebuf_sz > 0 ? linebuf_sz << 1 : read_sz;
264 linebuf = realloc(linebuf, linebuf_sz); 256 linebuf = realloc(linebuf, linebuf_sz);
265 if (linebuf == NULL) 257 if (linebuf == NULL) {
266 die(STATE_UNKNOWN, _("malloc() failed!\n")); 258 die(STATE_UNKNOWN, _("malloc() failed!\n"));
259 }
267 } 260 }
268 if (fgets(&linebuf[read_pos], (int)read_sz, f) == NULL) 261
269 done_reading = 1; 262 if (fgets(&linebuf[read_pos], (int)read_sz, filePointer) == NULL) {
270 else { 263 done_reading = true;
264 } else {
271 read_pos = strlen(linebuf); 265 read_pos = strlen(linebuf);
272 if (linebuf[read_pos - 1] == '\n') { 266 if (linebuf[read_pos - 1] == '\n') {
273 linebuf[--read_pos] = '\0'; 267 linebuf[--read_pos] = '\0';
274 done_reading = 1; 268 done_reading = true;
275 } 269 }
276 } 270 }
277 } 271 }
278 lineend = &linebuf[read_pos]; 272
273 char *lineend = &linebuf[read_pos];
279 /* all that to read one line, isn't C fun? :) now comes the parsing :/ */ 274 /* all that to read one line, isn't C fun? :) now comes the parsing :/ */
280 275
281 /* skip leading whitespace */ 276 /* skip leading whitespace */
282 for (optptr = linebuf; optptr < lineend && isspace(*optptr); optptr++) 277 char *optptr = NULL;
283 continue; 278 for (optptr = linebuf; optptr < lineend && isspace(*optptr); optptr++) {
279 }
280
284 /* continue to '=' or EOL, watching for spaces that might precede it */ 281 /* continue to '=' or EOL, watching for spaces that might precede it */
282 char *eqptr = NULL;
283 char *optend = NULL;
285 for (eqptr = optptr; eqptr < lineend && *eqptr != '='; eqptr++) { 284 for (eqptr = optptr; eqptr < lineend && *eqptr != '='; eqptr++) {
286 if (isspace(*eqptr) && optend == NULL) 285 if (isspace(*eqptr) && optend == NULL) {
287 optend = eqptr; 286 optend = eqptr;
288 else 287 } else {
289 optend = NULL; 288 optend = NULL;
289 }
290 } 290 }
291 if (optend == NULL) 291
292 if (optend == NULL) {
292 optend = eqptr; 293 optend = eqptr;
294 }
295
293 --optend; 296 --optend;
297
294 /* ^[[:space:]]*=foo is a syntax error */ 298 /* ^[[:space:]]*=foo is a syntax error */
295 if (optptr == eqptr) 299 if (optptr == eqptr) {
296 die(STATE_UNKNOWN, "%s\n", _("Config file error")); 300 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
301 }
302
297 /* continue from '=' to start of value or EOL */ 303 /* continue from '=' to start of value or EOL */
298 for (valptr = eqptr + 1; valptr < lineend && isspace(*valptr); 304 char *valptr = NULL;
299 valptr++) 305 for (valptr = eqptr + 1; valptr < lineend && isspace(*valptr); valptr++) {
300 continue; 306 }
307
301 /* continue to the end of value */ 308 /* continue to the end of value */
302 for (valend = valptr; valend < lineend; valend++) 309 char *valend = NULL;
303 continue; 310 for (valend = valptr; valend < lineend; valend++) {
311 }
312
304 --valend; 313 --valend;
314
305 /* finally trim off trailing spaces */ 315 /* finally trim off trailing spaces */
306 for (; isspace(*valend); valend--) 316 for (; isspace(*valend); valend--) {
307 continue; 317 }
318
308 /* calculate the length of "--foo" */ 319 /* calculate the length of "--foo" */
309 opt_len = (size_t)(1 + optend - optptr); 320 size_t opt_len = (size_t)(1 + optend - optptr);
310 /* 1-character params needs only one dash */ 321 /* 1-character params needs only one dash */
311 if (opt_len == 1) 322 size_t cfg_len = 0;
323 if (opt_len == 1) {
312 cfg_len = 1 + (opt_len); 324 cfg_len = 1 + (opt_len);
313 else 325 } else {
314 cfg_len = 2 + (opt_len); 326 cfg_len = 2 + (opt_len);
327 }
328
329 size_t val_len = 0;
330 bool equals = false;
331 bool value = false;
315 /* if valptr<lineend then we have to also allocate space for "=bar" */ 332 /* if valptr<lineend then we have to also allocate space for "=bar" */
316 if (valptr < lineend) { 333 if (valptr < lineend) {
317 equals = value = 1; 334 equals = value = true;
318 val_len = (size_t)(1 + valend - valptr); 335 val_len = (size_t)(1 + valend - valptr);
319 cfg_len += 1 + val_len; 336 cfg_len += 1 + val_len;
320 } 337 } else if (valptr == lineend) {
321 /* if valptr==valend then we have "=" but no "bar" */ 338 /* if valptr==valend then we have "=" but no "bar" */
322 else if (valptr == lineend) { 339 equals = true;
323 equals = 1;
324 cfg_len += 1; 340 cfg_len += 1;
325 } 341 }
342
326 /* a line with no equal sign isn't valid */ 343 /* a line with no equal sign isn't valid */
327 if (equals == 0) 344 if (!equals) {
328 die(STATE_UNKNOWN, "%s\n", _("Config file error")); 345 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
346 }
329 347
330 /* okay, now we have all the info we need, so we create a new np_arg_list 348 /* okay, now we have all the info we need, so we create a new np_arg_list
331 * element and set the argument... 349 * element and set the argument...
332 */ 350 */
333 optnew = malloc(sizeof(np_arg_list)); 351 np_arg_list *optnew = malloc(sizeof(np_arg_list));
334 optnew->next = NULL; 352 optnew->next = NULL;
335 353
336 read_pos = 0; 354 read_pos = 0;
@@ -353,11 +371,13 @@ add_option(FILE *f, np_arg_list **optlst)
353 optnew->arg[read_pos] = '\0'; 371 optnew->arg[read_pos] = '\0';
354 372
355 /* ...and put that to the end of the list */ 373 /* ...and put that to the end of the list */
356 if (*optlst == NULL) 374 if (*optlst == NULL) {
357 *optlst = optnew; 375 *optlst = optnew;
358 else { 376 } else {
359 while (opttmp->next != NULL) 377 np_arg_list *opttmp = *optlst;
378 while (opttmp->next != NULL) {
360 opttmp = opttmp->next; 379 opttmp = opttmp->next;
380 }
361 opttmp->next = optnew; 381 opttmp->next = optnew;
362 } 382 }
363 383
@@ -365,13 +385,11 @@ add_option(FILE *f, np_arg_list **optlst)
365 return 0; 385 return 0;
366} 386}
367 387
368static char * 388static char *default_file(void) {
369default_file(void) 389 char *ini_file;
370{
371 char *ini_file;
372 390
373 if ((ini_file = getenv("MP_CONFIG_FILE")) != NULL || 391 if ((ini_file = getenv("MP_CONFIG_FILE")) != NULL ||
374 (ini_file = default_file_in_path()) != NULL) { 392 (ini_file = default_file_in_path()) != NULL) {
375 return ini_file; 393 return ini_file;
376 } 394 }
377 395
@@ -383,22 +401,26 @@ default_file(void)
383 return NULL; 401 return NULL;
384} 402}
385 403
386static char * 404static char *default_file_in_path(void) {
387default_file_in_path(void) 405 char *config_path;
388{ 406 char **file;
389 char *config_path, **file; 407 char *dir;
390 char *dir, *ini_file, *tokens; 408 char *ini_file;
409 char *tokens;
391 410
392 if ((config_path = getenv("NAGIOS_CONFIG_PATH")) == NULL) 411 if ((config_path = getenv("NAGIOS_CONFIG_PATH")) == NULL) {
393 return NULL; 412 return NULL;
413 }
394 /* shall we spit out a warning that NAGIOS_CONFIG_PATH is deprecated? */ 414 /* shall we spit out a warning that NAGIOS_CONFIG_PATH is deprecated? */
395 415
396 if ((tokens = strdup(config_path)) == NULL) 416 if ((tokens = strdup(config_path)) == NULL) {
397 die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory")); 417 die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory"));
418 }
398 for (dir = strtok(tokens, ":"); dir != NULL; dir = strtok(NULL, ":")) { 419 for (dir = strtok(tokens, ":"); dir != NULL; dir = strtok(NULL, ":")) {
399 for (file = default_ini_file_names; *file != NULL; file++) { 420 for (file = default_ini_file_names; *file != NULL; file++) {
400 if ((asprintf(&ini_file, "%s/%s", dir, *file)) < 0) 421 if ((asprintf(&ini_file, "%s/%s", dir, *file)) < 0) {
401 die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory")); 422 die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory"));
423 }
402 if (access(ini_file, F_OK) == 0) { 424 if (access(ini_file, F_OK) == 0) {
403 free(tokens); 425 free(tokens);
404 return ini_file; 426 return ini_file;
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..2930a8bc
--- /dev/null
+++ b/lib/perfdata.c
@@ -0,0 +1,649 @@
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
37 if (strchr(pd.label, '\'') == NULL) {
38 asprintf(&result, "'%s'=", pd.label);
39 } else {
40 // we have a illegal single quote in the string
41 // replace it silently instead of complaining
42 for (char *ptr = pd.label; *ptr == '\0'; ptr++) {
43 if (*ptr == '\'') {
44 *ptr = '_';
45 }
46 }
47 }
48
49 asprintf(&result, "%s%s", result, pd_value_to_string(pd.value));
50
51 if (pd.uom != NULL) {
52 asprintf(&result, "%s%s", result, pd.uom);
53 }
54
55 if (pd.warn_present) {
56 asprintf(&result, "%s;%s", result, mp_range_to_string(pd.warn));
57 } else {
58 asprintf(&result, "%s;", result);
59 }
60
61 if (pd.crit_present) {
62 asprintf(&result, "%s;%s", result, mp_range_to_string(pd.crit));
63 } else {
64 asprintf(&result, "%s;", result);
65 }
66 if (pd.min_present) {
67 asprintf(&result, "%s;%s", result, pd_value_to_string(pd.min));
68 } else {
69 asprintf(&result, "%s;", result);
70 }
71
72 if (pd.max_present) {
73 asprintf(&result, "%s;%s", result, pd_value_to_string(pd.max));
74 }
75
76 /*printf("pd_to_string: %s\n", result); */
77
78 return result;
79}
80
81char *pd_list_to_string(const pd_list pd) {
82 char *result = pd_to_string(pd.data);
83
84 for (pd_list *elem = pd.next; elem != NULL; elem = elem->next) {
85 asprintf(&result, "%s %s", result, pd_to_string(elem->data));
86 }
87
88 return result;
89}
90
91mp_perfdata perfdata_init() {
92 mp_perfdata pd = {};
93 return pd;
94}
95
96pd_list *pd_list_init() {
97 pd_list *tmp = (pd_list *)calloc(1, sizeof(pd_list));
98 if (tmp == NULL) {
99 die(STATE_UNKNOWN, "calloc failed\n");
100 }
101 tmp->next = NULL;
102 return tmp;
103}
104
105mp_range mp_range_init() {
106 mp_range result = {
107 .alert_on_inside_range = OUTSIDE,
108 .start = {},
109 .start_infinity = true,
110 .end = {},
111 .end_infinity = true,
112 };
113
114 return result;
115}
116
117mp_range mp_range_set_start(mp_range input, mp_perfdata_value perf_val) {
118 input.start = perf_val;
119 input.start_infinity = false;
120 return input;
121}
122
123mp_range mp_range_set_end(mp_range input, mp_perfdata_value perf_val) {
124 input.end = perf_val;
125 input.end_infinity = false;
126 return input;
127}
128
129void pd_list_append(pd_list pdl[1], const mp_perfdata pd) {
130 assert(pdl != NULL);
131
132 if (pdl->data.value.type == PD_TYPE_NONE) {
133 // first entry is still empty
134 pdl->data = pd;
135 } else {
136 // find last element in the list
137 pd_list *curr = pdl;
138 pd_list *next = pdl->next;
139
140 while (next != NULL) {
141 curr = next;
142 next = next->next;
143 }
144
145 if (curr->data.value.type == PD_TYPE_NONE) {
146 // still empty
147 curr->data = pd;
148 } else {
149 // new a new one
150 curr->next = pd_list_init();
151 curr->next->data = pd;
152 }
153 }
154}
155
156void pd_list_free(pd_list pdl[1]) {
157 while (pdl != NULL) {
158 pd_list *old = pdl;
159 pdl = pdl->next;
160 free(old);
161 }
162}
163
164/*
165 * returns -1 if a < b, 0 if a == b, 1 if a > b
166 */
167int cmp_perfdata_value(const mp_perfdata_value a, const mp_perfdata_value b) {
168 // Test if types are different
169 if (a.type == b.type) {
170
171 switch (a.type) {
172 case PD_TYPE_UINT:
173 if (a.pd_uint < b.pd_uint) {
174 return -1;
175 } else if (a.pd_uint == b.pd_uint) {
176 return 0;
177 } else {
178 return 1;
179 }
180 break;
181 case PD_TYPE_INT:
182 if (a.pd_int < b.pd_int) {
183 return -1;
184 } else if (a.pd_int == b.pd_int) {
185 return 0;
186 } else {
187 return 1;
188 }
189 break;
190 case PD_TYPE_DOUBLE:
191 if (a.pd_int < b.pd_int) {
192 return -1;
193 } else if (a.pd_int == b.pd_int) {
194 return 0;
195 } else {
196 return 1;
197 }
198 break;
199 default:
200 die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__);
201 }
202 }
203
204 // Get dirty here
205 long double floating_a = 0;
206
207 switch (a.type) {
208 case PD_TYPE_UINT:
209 floating_a = a.pd_uint;
210 break;
211 case PD_TYPE_INT:
212 floating_a = a.pd_int;
213 break;
214 case PD_TYPE_DOUBLE:
215 floating_a = a.pd_double;
216 break;
217 default:
218 die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__);
219 }
220
221 long double floating_b = 0;
222 switch (b.type) {
223 case PD_TYPE_UINT:
224 floating_b = b.pd_uint;
225 break;
226 case PD_TYPE_INT:
227 floating_b = b.pd_int;
228 break;
229 case PD_TYPE_DOUBLE:
230 floating_b = b.pd_double;
231 break;
232 default:
233 die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__);
234 }
235
236 if (floating_a < floating_b) {
237 return -1;
238 }
239 if (floating_a == floating_b) {
240 return 0;
241 }
242 return 1;
243}
244
245char *mp_range_to_string(const mp_range input) {
246 char *result = "";
247 if (input.alert_on_inside_range == INSIDE) {
248 asprintf(&result, "@");
249 }
250
251 if (input.start_infinity) {
252 asprintf(&result, "%s~:", result);
253 } else {
254 asprintf(&result, "%s%s:", result, pd_value_to_string(input.start));
255 }
256
257 if (!input.end_infinity) {
258 asprintf(&result, "%s%s", result, pd_value_to_string(input.end));
259 }
260 return result;
261}
262
263mp_perfdata mp_set_pd_value_float(mp_perfdata pd, float value) {
264 return mp_set_pd_value_double(pd, value);
265}
266
267mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) {
268 pd.value.pd_double = value;
269 pd.value.type = PD_TYPE_DOUBLE;
270 return pd;
271}
272
273mp_perfdata mp_set_pd_value_char(mp_perfdata pd, char value) {
274 return mp_set_pd_value_long_long(pd, (long long)value);
275}
276
277mp_perfdata mp_set_pd_value_u_char(mp_perfdata pd, unsigned char value) {
278 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value);
279}
280
281mp_perfdata mp_set_pd_value_int(mp_perfdata pd, int value) {
282 return mp_set_pd_value_long_long(pd, (long long)value);
283}
284
285mp_perfdata mp_set_pd_value_u_int(mp_perfdata pd, unsigned int value) {
286 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value);
287}
288
289mp_perfdata mp_set_pd_value_long(mp_perfdata pd, long value) {
290 return mp_set_pd_value_long_long(pd, (long long)value);
291}
292
293mp_perfdata mp_set_pd_value_u_long(mp_perfdata pd, unsigned long value) {
294 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value);
295}
296
297mp_perfdata mp_set_pd_value_long_long(mp_perfdata pd, long long value) {
298 pd.value.pd_int = value;
299 pd.value.type = PD_TYPE_INT;
300 return pd;
301}
302
303mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata pd, unsigned long long value) {
304 pd.value.pd_uint = value;
305 pd.value.type = PD_TYPE_UINT;
306 return pd;
307}
308
309mp_perfdata_value mp_create_pd_value_double(double value) {
310 mp_perfdata_value res = {0};
311 res.type = PD_TYPE_DOUBLE;
312 res.pd_double = value;
313 return res;
314}
315
316mp_perfdata_value mp_create_pd_value_float(float value) {
317 return mp_create_pd_value_double((double)value);
318}
319
320mp_perfdata_value mp_create_pd_value_char(char value) {
321 return mp_create_pd_value_long_long((long long)value);
322}
323
324mp_perfdata_value mp_create_pd_value_u_char(unsigned char value) {
325 return mp_create_pd_value_u_long_long((unsigned long long)value);
326}
327
328mp_perfdata_value mp_create_pd_value_int(int value) {
329 return mp_create_pd_value_long_long((long long)value);
330}
331
332mp_perfdata_value mp_create_pd_value_u_int(unsigned int value) {
333 return mp_create_pd_value_u_long_long((unsigned long long)value);
334}
335
336mp_perfdata_value mp_create_pd_value_long(long value) {
337 return mp_create_pd_value_long_long((long long)value);
338}
339
340mp_perfdata_value mp_create_pd_value_u_long(unsigned long value) {
341 return mp_create_pd_value_u_long_long((unsigned long long)value);
342}
343
344mp_perfdata_value mp_create_pd_value_long_long(long long value) {
345 mp_perfdata_value res = {0};
346 res.type = PD_TYPE_INT;
347 res.pd_int = value;
348 return res;
349}
350
351mp_perfdata_value mp_create_pd_value_u_long_long(unsigned long long value) {
352 mp_perfdata_value res = {0};
353 res.type = PD_TYPE_UINT;
354 res.pd_uint = value;
355 return res;
356}
357
358char *fmt_range(range foo) { return foo.text; }
359
360typedef struct integer_parser_wrapper {
361 int error;
362 mp_perfdata_value value;
363} integer_parser_wrapper;
364
365typedef struct double_parser_wrapper {
366 int error;
367 mp_perfdata_value value;
368} double_parser_wrapper;
369
370typedef struct perfdata_value_parser_wrapper {
371 int error;
372 mp_perfdata_value value;
373} perfdata_value_parser_wrapper;
374
375double_parser_wrapper parse_double(const char *input);
376integer_parser_wrapper parse_integer(const char *input);
377perfdata_value_parser_wrapper parse_pd_value(const char *input);
378
379mp_range_parsed mp_parse_range_string(const char *input) {
380 if (input == NULL) {
381 mp_range_parsed result = {
382 .error = MP_RANGE_PARSING_FAILURE,
383 };
384 return result;
385 }
386
387 if (strlen(input) == 0) {
388 mp_range_parsed result = {
389 .error = MP_RANGE_PARSING_FAILURE,
390 };
391 return result;
392 }
393
394 mp_range_parsed result = {
395 .range = mp_range_init(),
396 .error = MP_PARSING_SUCCES,
397 };
398
399 if (input[0] == '@') {
400 // found an '@' at beginning, so invert the range logic
401 result.range.alert_on_inside_range = INSIDE;
402
403 // advance the pointer one symbol
404 input++;
405 }
406
407 char *working_copy = strdup(input);
408 if (working_copy == NULL) {
409 // strdup error, probably
410 mp_range_parsed result = {
411 .error = MP_RANGE_PARSING_FAILURE,
412 };
413 return result;
414 }
415 input = working_copy;
416
417 char *separator = index(working_copy, ':');
418 if (separator != NULL) {
419 // Found a separator
420 // set the separator to 0, so we have two different strings
421 *separator = '\0';
422
423 if (input[0] == '~') {
424 // the beginning starts with '~', so it might be infinity
425 if (&input[1] != separator) {
426 // the next symbol after '~' is not the separator!
427 // so input is probably wrong
428 result.error = MP_RANGE_PARSING_FAILURE;
429 free(working_copy);
430 return result;
431 }
432
433 result.range.start_infinity = true;
434 } else {
435 // No '~' at the beginning, so this should be a number
436 result.range.start_infinity = false;
437 perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input);
438
439 if (parsed_pd.error != MP_PARSING_SUCCES) {
440 result.error = parsed_pd.error;
441 free(working_copy);
442 return result;
443 }
444
445 result.range.start = parsed_pd.value;
446 result.range.start_infinity = false;
447 }
448 // got the first part now
449 // advance the pointer
450 input = separator + 1;
451 }
452
453 // End part or no separator
454 if (input[0] == '\0') {
455 // the end is infinite
456 result.range.end_infinity = true;
457 } else {
458 perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input);
459
460 if (parsed_pd.error != MP_PARSING_SUCCES) {
461 result.error = parsed_pd.error;
462 return result;
463 }
464 result.range.end = parsed_pd.value;
465 result.range.end_infinity = false;
466 }
467 free(working_copy);
468 return result;
469}
470
471double_parser_wrapper parse_double(const char *input) {
472 double_parser_wrapper result = {
473 .error = MP_PARSING_SUCCES,
474 };
475
476 if (input == NULL) {
477 result.error = MP_PARSING_FAILURE;
478 return result;
479 }
480
481 char *endptr = NULL;
482 errno = 0;
483 double tmp = strtod(input, &endptr);
484
485 if (input == endptr) {
486 // man 3 strtod says, no conversion performed
487 result.error = MP_PARSING_FAILURE;
488 return result;
489 }
490
491 if (errno) {
492 // some other error
493 // TODO maybe differentiate a little bit
494 result.error = MP_PARSING_FAILURE;
495 return result;
496 }
497
498 result.value = mp_create_pd_value(tmp);
499 return result;
500}
501
502integer_parser_wrapper parse_integer(const char *input) {
503 integer_parser_wrapper result = {
504 .error = MP_PARSING_SUCCES,
505 };
506
507 if (input == NULL) {
508 result.error = MP_PARSING_FAILURE;
509 return result;
510 }
511
512 char *endptr = NULL;
513 errno = 0;
514 long long tmp = strtoll(input, &endptr, 0);
515
516 // validating *sigh*
517 if (*endptr != '\0') {
518 // something went wrong in strtoll
519 if (tmp == LLONG_MIN) {
520 // underflow
521 result.error = MP_RANGE_PARSING_UNDERFLOW;
522 return result;
523 }
524
525 if (tmp == LLONG_MAX) {
526 // overflow
527 result.error = MP_RANGE_PARSING_OVERFLOW;
528 return result;
529 }
530
531 // still wrong, but not sure why, probably invalid characters
532 if (errno == EINVAL) {
533 result.error = MP_RANGE_PARSING_INVALID_CHAR;
534 return result;
535 }
536
537 // some other error, do catch all here
538 result.error = MP_RANGE_PARSING_FAILURE;
539 return result;
540 }
541
542 // no error, should be fine
543 result.value = mp_create_pd_value(tmp);
544 return result;
545}
546
547perfdata_value_parser_wrapper parse_pd_value(const char *input) {
548 // try integer first
549 integer_parser_wrapper tmp_int = parse_integer(input);
550
551 if (tmp_int.error == MP_PARSING_SUCCES) {
552 perfdata_value_parser_wrapper result = {
553 .error = tmp_int.error,
554 .value = tmp_int.value,
555 };
556 return result;
557 }
558
559 double_parser_wrapper tmp_double = parse_double(input);
560 perfdata_value_parser_wrapper result = {};
561 if (tmp_double.error == MP_PARSING_SUCCES) {
562 result.error = tmp_double.error;
563 result.value = tmp_double.value;
564 } else {
565 result.error = tmp_double.error;
566 }
567 return result;
568}
569
570mp_perfdata mp_set_pd_max_value(mp_perfdata perfdata, mp_perfdata_value value) {
571 perfdata.max = value;
572 perfdata.max_present = true;
573 return perfdata;
574}
575
576mp_perfdata mp_set_pd_min_value(mp_perfdata perfdata, mp_perfdata_value value) {
577 perfdata.min = value;
578 perfdata.min_present = true;
579 return perfdata;
580}
581
582double mp_get_pd_value(mp_perfdata_value value) {
583 assert(value.type != PD_TYPE_NONE);
584 switch (value.type) {
585 case PD_TYPE_DOUBLE:
586 return value.pd_double;
587 case PD_TYPE_INT:
588 return (double)value.pd_int;
589 case PD_TYPE_UINT:
590 return (double)value.pd_uint;
591 default:
592 return 0; // just to make the compiler happy
593 }
594}
595
596mp_perfdata_value mp_pd_value_multiply(mp_perfdata_value left, mp_perfdata_value right) {
597 if (left.type == right.type) {
598 switch (left.type) {
599 case PD_TYPE_DOUBLE:
600 left.pd_double *= right.pd_double;
601 return left;
602 case PD_TYPE_INT:
603 left.pd_int *= right.pd_int;
604 return left;
605 case PD_TYPE_UINT:
606 left.pd_uint *= right.pd_uint;
607 return left;
608 default:
609 // what to here?
610 return left;
611 }
612 }
613
614 // Different types, oh boy, just do the lazy thing for now and switch to double
615 switch (left.type) {
616 case PD_TYPE_INT:
617 left.pd_double = (double)left.pd_int;
618 left.type = PD_TYPE_DOUBLE;
619 break;
620 case PD_TYPE_UINT:
621 left.pd_double = (double)left.pd_uint;
622 left.type = PD_TYPE_DOUBLE;
623 break;
624 }
625
626 switch (right.type) {
627 case PD_TYPE_INT:
628 right.pd_double = (double)right.pd_int;
629 right.type = PD_TYPE_DOUBLE;
630 break;
631 case PD_TYPE_UINT:
632 right.pd_double = (double)right.pd_uint;
633 right.type = PD_TYPE_DOUBLE;
634 break;
635 }
636
637 left.pd_double *= right.pd_double;
638 return left;
639}
640
641mp_range mp_range_multiply(mp_range range, mp_perfdata_value factor) {
642 if (!range.end_infinity) {
643 range.end = mp_pd_value_multiply(range.end, factor);
644 }
645 if (!range.start_infinity) {
646 range.start = mp_pd_value_multiply(range.start, factor);
647 }
648 return range;
649}
diff --git a/lib/perfdata.h b/lib/perfdata.h
new file mode 100644
index 00000000..e51ef5fd
--- /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 {
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 {
45 double start;
46 bool start_infinity;
47 double end;
48 bool 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 {
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..798244da 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,175 @@ 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,
186 0x50,0x66,0x34,0x37,0x0b,0x45,0x4b,0x38,0x32,0x06,0x7a,0x3e,0x7f,0x0c,0x40,0x18, 184 0x08, 0x50, 0x66, 0x34, 0x37, 0x0b, 0x45, 0x4b, 0x38, 0x32, 0x06, 0x7a, 0x3e, 0x7f, 0x0c,
187 0x6b,0x2d,0x60,0x4c,0x60,0x0c,0x23,0x43,0x3b,0x3e,0x1b,0x16,0x04,0x46,0x58,0x3f, 185 0x40, 0x18, 0x6b, 0x2d, 0x60, 0x4c, 0x60, 0x0c, 0x23, 0x43, 0x3b, 0x3e, 0x1b, 0x16, 0x04,
188 0x40,0x6a,0x11,0x05,0x63,0x71,0x14,0x35,0x47,0x79,0x13,0x6f,0x6b,0x27,0x18,0x5b, 186 0x46, 0x58, 0x3f, 0x40, 0x6a, 0x11, 0x05, 0x63, 0x71, 0x14, 0x35, 0x47, 0x79, 0x13, 0x6f,
189 0x48,0x27,0x3e,0x6f,0x15,0x33,0x4f,0x3e,0x5e,0x51,0x73,0x68,0x25,0x0f,0x06,0x5b, 187 0x6b, 0x27, 0x18, 0x5b, 0x48, 0x27, 0x3e, 0x6f, 0x15, 0x33, 0x4f, 0x3e, 0x5e, 0x51, 0x73,
190 0x7c,0x72,0x75,0x3e,0x3f,0x1b,0x5c,0x6d,0x6a,0x39,0x7c,0x63,0x63,0x60,0x6c,0x7a, 188 0x68, 0x25, 0x0f, 0x06, 0x5b, 0x7c, 0x72, 0x75, 0x3e, 0x3f, 0x1b, 0x5c, 0x6d, 0x6a, 0x39,
191 0x33,0x76,0x52,0x13,0x25,0x33,0x7d,0x65,0x23,0x27,0x11,0x06,0x06,0x47,0x71,0x1e, 189 0x7c, 0x63, 0x63, 0x60, 0x6c, 0x7a, 0x33, 0x76, 0x52, 0x13, 0x25, 0x33, 0x7d, 0x65, 0x23,
192 0x14,0x74,0x63,0x70,0x2d,0x15,0x27,0x18,0x51,0x06,0x05,0x33,0x11,0x2c,0x6b,0x00, 190 0x27, 0x11, 0x06, 0x06, 0x47, 0x71, 0x1e, 0x14, 0x74, 0x63, 0x70, 0x2d, 0x15, 0x27, 0x18,
193 0x2d,0x77,0x20,0x48,0x0d,0x73,0x51,0x45,0x25,0x7f,0x7f,0x35,0x26,0x2e,0x26,0x53, 191 0x51, 0x06, 0x05, 0x33, 0x11, 0x2c, 0x6b, 0x00, 0x2d, 0x77, 0x20, 0x48, 0x0d, 0x73, 0x51,
194 0x24,0x68,0x1e,0x0e,0x58,0x3a,0x59,0x50,0x56,0x37,0x5f,0x66,0x01,0x4c,0x5a,0x64, 192 0x45, 0x25, 0x7f, 0x7f, 0x35, 0x26, 0x2e, 0x26, 0x53, 0x24, 0x68, 0x1e, 0x0e, 0x58, 0x3a,
195 0x32,0x50,0x7b,0x6a,0x20,0x72,0x2b,0x1d,0x7e,0x43,0x7b,0x61,0x42,0x0b,0x61,0x73, 193 0x59, 0x50, 0x56, 0x37, 0x5f, 0x66, 0x01, 0x4c, 0x5a, 0x64, 0x32, 0x50, 0x7b, 0x6a, 0x20,
196 0x24,0x79,0x3a,0x6b,0x4a,0x79,0x6e,0x09,0x0f,0x27,0x2d,0x0c,0x5e,0x32,0x4b,0x0d, 194 0x72, 0x2b, 0x1d, 0x7e, 0x43, 0x7b, 0x61, 0x42, 0x0b, 0x61, 0x73, 0x24, 0x79, 0x3a, 0x6b,
197 0x79,0x46,0x39,0x21,0x0a,0x26,0x5f,0x3a,0x00,0x26,0x3f,0x13,0x2e,0x7e,0x50,0x2b, 195 0x4a, 0x79, 0x6e, 0x09, 0x0f, 0x27, 0x2d, 0x0c, 0x5e, 0x32, 0x4b, 0x0d, 0x79, 0x46, 0x39,
198 0x67,0x46,0x72,0x3f,0x3b,0x01,0x46,0x1b,0x0b,0x35,0x49,0x39,0x19,0x70,0x3d,0x02, 196 0x21, 0x0a, 0x26, 0x5f, 0x3a, 0x00, 0x26, 0x3f, 0x13, 0x2e, 0x7e, 0x50, 0x2b, 0x67, 0x46,
199 0x41,0x0e,0x38,0x05,0x76,0x65,0x4f,0x31,0x6c,0x5e,0x17,0x04,0x15,0x36,0x26,0x64, 197 0x72, 0x3f, 0x3b, 0x01, 0x46, 0x1b, 0x0b, 0x35, 0x49, 0x39, 0x19, 0x70, 0x3d, 0x02, 0x41,
200 0x34,0x14,0x17,0x7c,0x0e,0x0b,0x5b,0x55,0x53,0x6b,0x00,0x42,0x41,0x4f,0x02,0x5c, 198 0x0e, 0x38, 0x05, 0x76, 0x65, 0x4f, 0x31, 0x6c, 0x5e, 0x17, 0x04, 0x15, 0x36, 0x26, 0x64,
201 0x13,0x0a,0x2c,0x2c,0x3e,0x10,0x14,0x33,0x45,0x7c,0x7a,0x5a,0x31,0x61,0x39,0x08, 199 0x34, 0x14, 0x17, 0x7c, 0x0e, 0x0b, 0x5b, 0x55, 0x53, 0x6b, 0x00, 0x42, 0x41, 0x4f, 0x02,
202 0x22,0x6a,0x1e,0x0f,0x6f,0x1b,0x6c,0x13,0x5e,0x79,0x20,0x79,0x50,0x62,0x06,0x2c, 200 0x5c, 0x13, 0x0a, 0x2c, 0x2c, 0x3e, 0x10, 0x14, 0x33, 0x45, 0x7c, 0x7a, 0x5a, 0x31, 0x61,
203 0x76,0x17,0x04,0x2b,0x2a,0x75,0x1f,0x0c,0x37,0x4e,0x0f,0x7b,0x2d,0x34,0x75,0x60, 201 0x39, 0x08, 0x22, 0x6a, 0x1e, 0x0f, 0x6f, 0x1b, 0x6c, 0x13, 0x5e, 0x79, 0x20, 0x79, 0x50,
204 0x31,0x74,0x2e,0x0a,0x4a,0x11,0x6c,0x49,0x25,0x01,0x3a,0x3d,0x22,0x1e,0x6d,0x18, 202 0x62, 0x06, 0x2c, 0x76, 0x17, 0x04, 0x2b, 0x2a, 0x75, 0x1f, 0x0c, 0x37, 0x4e, 0x0f, 0x7b,
205 0x51,0x78,0x2d,0x62,0x31,0x4c,0x50,0x40,0x17,0x4b,0x6f,0x22,0x00,0x7f,0x61,0x2a, 203 0x2d, 0x34, 0x75, 0x60, 0x31, 0x74, 0x2e, 0x0a, 0x4a, 0x11, 0x6c, 0x49, 0x25, 0x01, 0x3a,
206 0x34,0x3e,0x00,0x5f,0x2f,0x5f,0x2f,0x14,0x2a,0x55,0x27,0x1f,0x46,0x1f,0x12,0x46, 204 0x3d, 0x22, 0x1e, 0x6d, 0x18, 0x51, 0x78, 0x2d, 0x62, 0x31, 0x4c, 0x50, 0x40, 0x17, 0x4b,
207 0x5e,0x1e,0x0c,0x7c,0x38,0x01,0x61,0x64,0x76,0x22,0x6e,0x08,0x20,0x38,0x4f,0x73, 205 0x6f, 0x22, 0x00, 0x7f, 0x61, 0x2a, 0x34, 0x3e, 0x00, 0x5f, 0x2f, 0x5f, 0x2f, 0x14, 0x2a,
208 0x72,0x55,0x12,0x42,0x19,0x50,0x61,0x43,0x77,0x7d,0x41,0x2e,0x35,0x4f,0x3d,0x31, 206 0x55, 0x27, 0x1f, 0x46, 0x1f, 0x12, 0x46, 0x5e, 0x1e, 0x0c, 0x7c, 0x38, 0x01, 0x61, 0x64,
209 0x28,0x58,0x67,0x1b,0x03,0x51,0x20,0x32,0x1c,0x08,0x6e,0x37,0x75,0x37,0x44,0x4f, 207 0x76, 0x22, 0x6e, 0x08, 0x20, 0x38, 0x4f, 0x73, 0x72, 0x55, 0x12, 0x42, 0x19, 0x50, 0x61,
210 0x68,0x19,0x07,0x64,0x14,0x28,0x25,0x2b,0x69,0x35,0x18,0x27,0x26,0x14,0x13,0x70, 208 0x43, 0x77, 0x7d, 0x41, 0x2e, 0x35, 0x4f, 0x3d, 0x31, 0x28, 0x58, 0x67, 0x1b, 0x03, 0x51,
211 0x42,0x19,0x12,0x75,0x3e,0x02,0x5d,0x7c,0x13,0x1f,0x16,0x53,0x3b,0x74,0x48,0x3c, 209 0x20, 0x32, 0x1c, 0x08, 0x6e, 0x37, 0x75, 0x37, 0x44, 0x4f, 0x68, 0x19, 0x07, 0x64, 0x14,
212 0x5e,0x39,0x6c,0x1c,0x1c,0x74,0x39,0x1f,0x00,0x1b,0x06,0x0a,0x68,0x3b,0x52,0x4f, 210 0x28, 0x25, 0x2b, 0x69, 0x35, 0x18, 0x27, 0x26, 0x14, 0x13, 0x70, 0x42, 0x19, 0x12, 0x75,
213 0x1e,0x6e,0x3c,0x35,0x0c,0x38,0x0e,0x0b,0x3b,0x1a,0x76,0x23,0x29,0x53,0x1e,0x5f, 211 0x3e, 0x02, 0x5d, 0x7c, 0x13, 0x1f, 0x16, 0x53, 0x3b, 0x74, 0x48, 0x3c, 0x5e, 0x39, 0x6c,
214 0x41,0x0c,0x4b,0x0a,0x65,0x28,0x78,0x67,0x48,0x59,0x26,0x6d,0x31,0x76,0x23,0x70, 212 0x1c, 0x1c, 0x74, 0x39, 0x1f, 0x00, 0x1b, 0x06, 0x0a, 0x68, 0x3b, 0x52, 0x4f, 0x1e, 0x6e,
215 0x61,0x64,0x3b,0x38,0x79,0x66,0x74,0x53,0x2c,0x64,0x64,0x54,0x03,0x54,0x65,0x44, 213 0x3c, 0x35, 0x0c, 0x38, 0x0e, 0x0b, 0x3b, 0x1a, 0x76, 0x23, 0x29, 0x53, 0x1e, 0x5f, 0x41,
216 0x4c,0x18,0x4f,0x48,0x20,0x4f,0x72,0x10,0x3f,0x0c,0x52,0x2d,0x03,0x14,0x03,0x51, 214 0x0c, 0x4b, 0x0a, 0x65, 0x28, 0x78, 0x67, 0x48, 0x59, 0x26, 0x6d, 0x31, 0x76, 0x23, 0x70,
217 0x42,0x10,0x77,0x6a,0x34,0x06,0x32,0x03,0x72,0x14,0x7c,0x08,0x5d,0x52,0x1a,0x62, 215 0x61, 0x64, 0x3b, 0x38, 0x79, 0x66, 0x74, 0x53, 0x2c, 0x64, 0x64, 0x54, 0x03, 0x54, 0x65,
218 0x7c,0x3e,0x30,0x7e,0x5f,0x7f,0x54,0x0f,0x44,0x49,0x5d,0x5e,0x10,0x6a,0x06,0x2b, 216 0x44, 0x4c, 0x18, 0x4f, 0x48, 0x20, 0x4f, 0x72, 0x10, 0x3f, 0x0c, 0x52, 0x2d, 0x03, 0x14,
219 0x06,0x53,0x10,0x39,0x37,0x32,0x4a,0x4e,0x3d,0x2b,0x65,0x38,0x39,0x07,0x72,0x54, 217 0x03, 0x51, 0x42, 0x10, 0x77, 0x6a, 0x34, 0x06, 0x32, 0x03, 0x72, 0x14, 0x7c, 0x08, 0x5d,
220 0x64,0x4d,0x56,0x6a,0x03,0x22,0x70,0x7b,0x5f,0x60,0x0b,0x2a,0x0b,0x6b,0x10,0x64, 218 0x52, 0x1a, 0x62, 0x7c, 0x3e, 0x30, 0x7e, 0x5f, 0x7f, 0x54, 0x0f, 0x44, 0x49, 0x5d, 0x5e,
221 0x14,0x05,0x22,0x00,0x73,0x40,0x23,0x5b,0x51,0x1f,0x2b,0x1a,0x5d,0x69,0x7a,0x46, 219 0x10, 0x6a, 0x06, 0x2b, 0x06, 0x53, 0x10, 0x39, 0x37, 0x32, 0x4a, 0x4e, 0x3d, 0x2b, 0x65,
222 0x0c,0x5f,0x32,0x4b,0x4a,0x28,0x52,0x79,0x5b,0x12,0x42,0x18,0x00,0x5d,0x27,0x31, 220 0x38, 0x39, 0x07, 0x72, 0x54, 0x64, 0x4d, 0x56, 0x6a, 0x03, 0x22, 0x70, 0x7b, 0x5f, 0x60,
223 0x53,0x3c,0x4c,0x36,0x4e,0x38,0x3f,0x72,0x03,0x71,0x02,0x5b,0x36,0x59,0x7f,0x75, 221 0x0b, 0x2a, 0x0b, 0x6b, 0x10, 0x64, 0x14, 0x05, 0x22, 0x00, 0x73, 0x40, 0x23, 0x5b, 0x51,
224 0x6e,0x08,0x54,0x0d,0x34,0x1c,0x34,0x57,0x5d,0x69,0x48,0x00,0x3b,0x05,0x07,0x6e, 222 0x1f, 0x2b, 0x1a, 0x5d, 0x69, 0x7a, 0x46, 0x0c, 0x5f, 0x32, 0x4b, 0x4a, 0x28, 0x52, 0x79,
225 0x27,0x65,0x6e,0x40,0x3d,0x3a,0x4f,0x72,0x5d,0x39,0x16,0x0f,0x63,0x12,0x12,0x15, 223 0x5b, 0x12, 0x42, 0x18, 0x00, 0x5d, 0x27, 0x31, 0x53, 0x3c, 0x4c, 0x36, 0x4e, 0x38, 0x3f,
226 0x3a,0x70,0x0d,0x57,0x18,0x0d,0x5e,0x3d,0x22,0x68,0x68,0x7c,0x6d,0x4f,0x0c,0x7b, 224 0x72, 0x03, 0x71, 0x02, 0x5b, 0x36, 0x59, 0x7f, 0x75, 0x6e, 0x08, 0x54, 0x0d, 0x34, 0x1c,
227 0x09,0x2d,0x4a,0x73,0x20,0x47,0x07,0x57,0x75,0x5d,0x53,0x70,0x34,0x21,0x40,0x57, 225 0x34, 0x57, 0x5d, 0x69, 0x48, 0x00, 0x3b, 0x05, 0x07, 0x6e, 0x27, 0x65, 0x6e, 0x40, 0x3d,
228 0x51,0x5e,0x49,0x44,0x00,0x54,0x27,0x04,0x68,0x7e,0x59,0x56,0x58,0x74,0x14,0x3c, 226 0x3a, 0x4f, 0x72, 0x5d, 0x39, 0x16, 0x0f, 0x63, 0x12, 0x12, 0x15, 0x3a, 0x70, 0x0d, 0x57,
229 0x16,0x33,0x41,0x16,0x4b,0x2f,0x49,0x37,0x0a,0x54,0x08,0x08,0x1f,0x39,0x67,0x76, 227 0x18, 0x0d, 0x5e, 0x3d, 0x22, 0x68, 0x68, 0x7c, 0x6d, 0x4f, 0x0c, 0x7b, 0x09, 0x2d, 0x4a,
230 0x28,0x28,0x07,0x1d,0x61,0x47,0x51,0x4d,0x75,0x26,0x52,0x47,0x47,0x0c,0x57,0x58, 228 0x73, 0x20, 0x47, 0x07, 0x57, 0x75, 0x5d, 0x53, 0x70, 0x34, 0x21, 0x40, 0x57, 0x51, 0x5e,
231 0x74,0x3e,0x62,0x6c,0x58,0x3a,0x44,0x1e,0x16,0x2e,0x21,0x1c,0x73,0x45,0x67,0x74, 229 0x49, 0x44, 0x00, 0x54, 0x27, 0x04, 0x68, 0x7e, 0x59, 0x56, 0x58, 0x74, 0x14, 0x3c, 0x16,
232 0x4f,0x33,0x66,0x0e,0x74,0x66,0x26,0x1f,0x2e,0x38,0x44,0x40,0x7e,0x2a,0x50,0x52, 230 0x33, 0x41, 0x16, 0x4b, 0x2f, 0x49, 0x37, 0x0a, 0x54, 0x08, 0x08, 0x1f, 0x39, 0x67, 0x76,
233 0x5e,0x43,0x01,0x7a,0x38,0x49,0x3c,0x55,0x4d,0x5a,0x44,0x08,0x26,0x59,0x4d,0x45, 231 0x28, 0x28, 0x07, 0x1d, 0x61, 0x47, 0x51, 0x4d, 0x75, 0x26, 0x52, 0x47, 0x47, 0x0c, 0x57,
234 0x0b,0x48,0x0a,0x33,0x5e,0x4a,0x4d,0x75,0x16,0x17,0x63,0x46,0x01,0x2a,0x55,0x7b, 232 0x58, 0x74, 0x3e, 0x62, 0x6c, 0x58, 0x3a, 0x44, 0x1e, 0x16, 0x2e, 0x21, 0x1c, 0x73, 0x45,
235 0x0f,0x02,0x73,0x6a,0x4b,0x7f,0x75,0x65,0x3c,0x4c,0x33,0x39,0x6c,0x74,0x05,0x60, 233 0x67, 0x74, 0x4f, 0x33, 0x66, 0x0e, 0x74, 0x66, 0x26, 0x1f, 0x2e, 0x38, 0x44, 0x40, 0x7e,
236 0x0f,0x7f,0x2d,0x41,0x4d,0x4d,0x46,0x71,0x09,0x6f,0x4f,0x60,0x15,0x0f,0x46,0x73, 234 0x2a, 0x50, 0x52, 0x5e, 0x43, 0x01, 0x7a, 0x38, 0x49, 0x3c, 0x55, 0x4d, 0x5a, 0x44, 0x08,
237 0x63,0x4c,0x5e,0x74,0x30,0x0d,0x28,0x43,0x08,0x72,0x32,0x04,0x2e,0x31,0x29,0x27, 235 0x26, 0x59, 0x4d, 0x45, 0x0b, 0x48, 0x0a, 0x33, 0x5e, 0x4a, 0x4d, 0x75, 0x16, 0x17, 0x63,
238 0x44,0x6d,0x13,0x17,0x48,0x0f,0x49,0x52,0x10,0x13,0x7f,0x17,0x16,0x62,0x79,0x35, 236 0x46, 0x01, 0x2a, 0x55, 0x7b, 0x0f, 0x02, 0x73, 0x6a, 0x4b, 0x7f, 0x75, 0x65, 0x3c, 0x4c,
239 0x78,0x3e,0x01,0x7c,0x2e,0x0f,0x76,0x3e,0x5e,0x53,0x6c,0x5b,0x5f,0x7c,0x19,0x41, 237 0x33, 0x39, 0x6c, 0x74, 0x05, 0x60, 0x0f, 0x7f, 0x2d, 0x41, 0x4d, 0x4d, 0x46, 0x71, 0x09,
240 0x02,0x2f,0x17,0x64,0x41,0x75,0x10,0x04,0x47,0x7c,0x3d,0x4b,0x52,0x00,0x10,0x5d, 238 0x6f, 0x4f, 0x60, 0x15, 0x0f, 0x46, 0x73, 0x63, 0x4c, 0x5e, 0x74, 0x30, 0x0d, 0x28, 0x43,
241 0x51,0x4e,0x7a,0x27,0x25,0x55,0x40,0x12,0x35,0x60,0x05,0x1b,0x34,0x2d,0x04,0x7a, 239 0x08, 0x72, 0x32, 0x04, 0x2e, 0x31, 0x29, 0x27, 0x44, 0x6d, 0x13, 0x17, 0x48, 0x0f, 0x49,
242 0x6a,0x69,0x02,0x79,0x03,0x3a,0x2f,0x06,0x0a,0x79,0x7b,0x12,0x5d,0x7c,0x52,0x29, 240 0x52, 0x10, 0x13, 0x7f, 0x17, 0x16, 0x62, 0x79, 0x35, 0x78, 0x3e, 0x01, 0x7c, 0x2e, 0x0f,
243 0x47,0x58,0x12,0x73,0x3f,0x27,0x56,0x05,0x0c,0x48,0x32,0x58,0x6b,0x57,0x5c,0x03, 241 0x76, 0x3e, 0x5e, 0x53, 0x6c, 0x5b, 0x5f, 0x7c, 0x19, 0x41, 0x02, 0x2f, 0x17, 0x64, 0x41,
244 0x64,0x56,0x11,0x52,0x7a,0x30,0x36,0x29,0x17,0x3b,0x68,0x7a,0x7c,0x05,0x6b,0x6b, 242 0x75, 0x10, 0x04, 0x47, 0x7c, 0x3d, 0x4b, 0x52, 0x00, 0x10, 0x5d, 0x51, 0x4e, 0x7a, 0x27,
245 0x13,0x6a,0x24,0x5c,0x68,0x42,0x18,0x32,0x03,0x73,0x6e,0x04,0x21,0x2e,0x01,0x04, 243 0x25, 0x55, 0x40, 0x12, 0x35, 0x60, 0x05, 0x1b, 0x34, 0x2d, 0x04, 0x7a, 0x6a, 0x69, 0x02,
246 0x63,0x7d,0x44,0x41,0x12,0x31,0x0b,0x15,0x1f,0x70,0x00,0x2e,0x66,0x14,0x3c,0x7f, 244 0x79, 0x03, 0x3a, 0x2f, 0x06, 0x0a, 0x79, 0x7b, 0x12, 0x5d, 0x7c, 0x52, 0x29, 0x47, 0x58,
247 0x2b,0x00,0x1f,0x0c,0x28,0x59,0x0a,0x16,0x49,0x5a,0x5c,0x64,0x65,0x4b,0x11,0x29, 245 0x12, 0x73, 0x3f, 0x27, 0x56, 0x05, 0x0c, 0x48, 0x32, 0x58, 0x6b, 0x57, 0x5c, 0x03, 0x64,
248 0x15,0x36,0x5a,0x65,0x19,0x4f,0x60,0x23,0x3a,0x3a,0x13,0x25,0x02,0x78,0x4c,0x54 246 0x56, 0x11, 0x52, 0x7a, 0x30, 0x36, 0x29, 0x17, 0x3b, 0x68, 0x7a, 0x7c, 0x05, 0x6b, 0x6b,
249 }; 247 0x13, 0x6a, 0x24, 0x5c, 0x68, 0x42, 0x18, 0x32, 0x03, 0x73, 0x6e, 0x04, 0x21, 0x2e, 0x01,
250 char b64_known[1369] = { 248 0x04, 0x63, 0x7d, 0x44, 0x41, 0x12, 0x31, 0x0b, 0x15, 0x1f, 0x70, 0x00, 0x2e, 0x66, 0x14,
251 0x43,0x7a,0x42,0x45,0x59,0x6e,0x77,0x69,0x48,0x77,0x30,0x46,0x5a,0x79,0x77,0x71, 249 0x3c, 0x7f, 0x2b, 0x00, 0x1f, 0x0c, 0x28, 0x59, 0x0a, 0x16, 0x49, 0x5a, 0x5c, 0x64, 0x65,
252 0x4f,0x53,0x46,0x47,0x43,0x46,0x42,0x6d,0x4e,0x44,0x63,0x4c,0x52,0x55,0x73,0x34, 250 0x4b, 0x11, 0x29, 0x15, 0x36, 0x5a, 0x65, 0x19, 0x4f, 0x60, 0x23, 0x3a, 0x3a, 0x13, 0x25,
253 0x4d,0x67,0x5a,0x36,0x50,0x6e,0x38,0x4d,0x51,0x42,0x68,0x72,0x4c,0x57,0x42,0x4d, 251 0x02, 0x78, 0x4c, 0x54};
254 0x59,0x41,0x77,0x6a,0x51,0x7a,0x73,0x2b,0x47,0x78,0x59,0x45,0x52,0x6c,0x67,0x2f, 252 char b64_known[1369] = {
255 0x51,0x47,0x6f,0x52,0x42,0x57,0x4e,0x78,0x46,0x44,0x56,0x48,0x65,0x52,0x4e,0x76, 253 0x43, 0x7a, 0x42, 0x45, 0x59, 0x6e, 0x77, 0x69, 0x48, 0x77, 0x30, 0x46, 0x5a, 0x79, 0x77,
256 0x61,0x79,0x63,0x59,0x57,0x30,0x67,0x6e,0x50,0x6d,0x38,0x56,0x4d,0x30,0x38,0x2b, 254 0x71, 0x4f, 0x53, 0x46, 0x47, 0x43, 0x46, 0x42, 0x6d, 0x4e, 0x44, 0x63, 0x4c, 0x52, 0x55,
257 0x58,0x6c,0x46,0x7a,0x61,0x43,0x55,0x50,0x42,0x6c,0x74,0x38,0x63,0x6e,0x55,0x2b, 255 0x73, 0x34, 0x4d, 0x67, 0x5a, 0x36, 0x50, 0x6e, 0x38, 0x4d, 0x51, 0x42, 0x68, 0x72, 0x4c,
258 0x50,0x78,0x74,0x63,0x62,0x57,0x6f,0x35,0x66,0x47,0x4e,0x6a,0x59,0x47,0x78,0x36, 256 0x57, 0x42, 0x4d, 0x59, 0x41, 0x77, 0x6a, 0x51, 0x7a, 0x73, 0x2b, 0x47, 0x78, 0x59, 0x45,
259 0x4d,0x33,0x5a,0x53,0x45,0x79,0x55,0x7a,0x66,0x57,0x55,0x6a,0x4a,0x78,0x45,0x47, 257 0x52, 0x6c, 0x67, 0x2f, 0x51, 0x47, 0x6f, 0x52, 0x42, 0x57, 0x4e, 0x78, 0x46, 0x44, 0x56,
260 0x42,0x6b,0x64,0x78,0x48,0x68,0x52,0x30,0x59,0x33,0x41,0x74,0x46,0x53,0x63,0x59, 258 0x48, 0x65, 0x52, 0x4e, 0x76, 0x61, 0x79, 0x63, 0x59, 0x57, 0x30, 0x67, 0x6e, 0x50, 0x6d,
261 0x55,0x51,0x59,0x46,0x4d,0x78,0x45,0x73,0x61,0x77,0x41,0x74,0x64,0x79,0x42,0x49, 259 0x38, 0x56, 0x4d, 0x30, 0x38, 0x2b, 0x58, 0x6c, 0x46, 0x7a, 0x61, 0x43, 0x55, 0x50, 0x42,
262 0x44,0x58,0x4e,0x52,0x52,0x53,0x56,0x2f,0x66,0x7a,0x55,0x6d,0x4c,0x69,0x5a,0x54, 260 0x6c, 0x74, 0x38, 0x63, 0x6e, 0x55, 0x2b, 0x50, 0x78, 0x74, 0x63, 0x62, 0x57, 0x6f, 0x35,
263 0x4a,0x47,0x67,0x65,0x44,0x6c,0x67,0x36,0x57,0x56,0x42,0x57,0x4e,0x31,0x39,0x6d, 261 0x66, 0x47, 0x4e, 0x6a, 0x59, 0x47, 0x78, 0x36, 0x4d, 0x33, 0x5a, 0x53, 0x45, 0x79, 0x55,
264 0x41,0x55,0x78,0x61,0x5a,0x44,0x4a,0x51,0x65,0x32,0x6f,0x67,0x63,0x69,0x73,0x64, 262 0x7a, 0x66, 0x57, 0x55, 0x6a, 0x4a, 0x78, 0x45, 0x47, 0x42, 0x6b, 0x64, 0x78, 0x48, 0x68,
265 0x66,0x6b,0x4e,0x37,0x59,0x55,0x49,0x4c,0x59,0x58,0x4d,0x6b,0x65,0x54,0x70,0x72, 263 0x52, 0x30, 0x59, 0x33, 0x41, 0x74, 0x46, 0x53, 0x63, 0x59, 0x55, 0x51, 0x59, 0x46, 0x4d,
266 0x53,0x6e,0x6c,0x75,0x43,0x51,0x38,0x6e,0x4c,0x51,0x78,0x65,0x4d,0x6b,0x73,0x4e, 264 0x78, 0x45, 0x73, 0x61, 0x77, 0x41, 0x74, 0x64, 0x79, 0x42, 0x49, 0x44, 0x58, 0x4e, 0x52,
267 0x65,0x55,0x59,0x35,0x49,0x51,0x6f,0x6d,0x58,0x7a,0x6f,0x41,0x4a,0x6a,0x38,0x54, 265 0x52, 0x53, 0x56, 0x2f, 0x66, 0x7a, 0x55, 0x6d, 0x4c, 0x69, 0x5a, 0x54, 0x4a, 0x47, 0x67,
268 0x4c,0x6e,0x35,0x51,0x4b,0x32,0x64,0x47,0x63,0x6a,0x38,0x37,0x41,0x55,0x59,0x62, 266 0x65, 0x44, 0x6c, 0x67, 0x36, 0x57, 0x56, 0x42, 0x57, 0x4e, 0x31, 0x39, 0x6d, 0x41, 0x55,
269 0x43,0x7a,0x56,0x4a,0x4f,0x52,0x6c,0x77,0x50,0x51,0x4a,0x42,0x44,0x6a,0x67,0x46, 267 0x78, 0x61, 0x5a, 0x44, 0x4a, 0x51, 0x65, 0x32, 0x6f, 0x67, 0x63, 0x69, 0x73, 0x64, 0x66,
270 0x64,0x6d,0x56,0x50,0x4d,0x57,0x78,0x65,0x46,0x77,0x51,0x56,0x4e,0x69,0x5a,0x6b, 268 0x6b, 0x4e, 0x37, 0x59, 0x55, 0x49, 0x4c, 0x59, 0x58, 0x4d, 0x6b, 0x65, 0x54, 0x70, 0x72,
271 0x4e,0x42,0x51,0x58,0x66,0x41,0x34,0x4c,0x57,0x31,0x56,0x54,0x61,0x77,0x42,0x43, 269 0x53, 0x6e, 0x6c, 0x75, 0x43, 0x51, 0x38, 0x6e, 0x4c, 0x51, 0x78, 0x65, 0x4d, 0x6b, 0x73,
272 0x51,0x55,0x38,0x43,0x58,0x42,0x4d,0x4b,0x4c,0x43,0x77,0x2b,0x45,0x42,0x51,0x7a, 270 0x4e, 0x65, 0x55, 0x59, 0x35, 0x49, 0x51, 0x6f, 0x6d, 0x58, 0x7a, 0x6f, 0x41, 0x4a, 0x6a,
273 0x52,0x58,0x78,0x36,0x57,0x6a,0x46,0x68,0x4f,0x51,0x67,0x69,0x61,0x68,0x34,0x50, 271 0x38, 0x54, 0x4c, 0x6e, 0x35, 0x51, 0x4b, 0x32, 0x64, 0x47, 0x63, 0x6a, 0x38, 0x37, 0x41,
274 0x62,0x78,0x74,0x73,0x45,0x31,0x35,0x35,0x49,0x48,0x6c,0x51,0x59,0x67,0x59,0x73, 272 0x55, 0x59, 0x62, 0x43, 0x7a, 0x56, 0x4a, 0x4f, 0x52, 0x6c, 0x77, 0x50, 0x51, 0x4a, 0x42,
275 0x64,0x68,0x63,0x45,0x4b,0x79,0x70,0x31,0x48,0x77,0x77,0x33,0x54,0x67,0x39,0x37, 273 0x44, 0x6a, 0x67, 0x46, 0x64, 0x6d, 0x56, 0x50, 0x4d, 0x57, 0x78, 0x65, 0x46, 0x77, 0x51,
276 0x4c,0x54,0x52,0x31,0x59,0x44,0x46,0x30,0x4c,0x67,0x70,0x4b,0x45,0x57,0x78,0x4a, 274 0x56, 0x4e, 0x69, 0x5a, 0x6b, 0x4e, 0x42, 0x51, 0x58, 0x66, 0x41, 0x34, 0x4c, 0x57, 0x31,
277 0x4a,0x51,0x45,0x36,0x50,0x53,0x49,0x65,0x62,0x52,0x68,0x52,0x65,0x43,0x31,0x69, 275 0x56, 0x54, 0x61, 0x77, 0x42, 0x43, 0x51, 0x55, 0x38, 0x43, 0x58, 0x42, 0x4d, 0x4b, 0x4c,
278 0x4d,0x55,0x78,0x51,0x51,0x42,0x64,0x4c,0x62,0x79,0x49,0x41,0x66,0x32,0x45,0x71, 276 0x43, 0x77, 0x2b, 0x45, 0x42, 0x51, 0x7a, 0x52, 0x58, 0x78, 0x36, 0x57, 0x6a, 0x46, 0x68,
279 0x4e,0x44,0x34,0x41,0x58,0x79,0x39,0x66,0x4c,0x78,0x51,0x71,0x56,0x53,0x63,0x66, 277 0x4f, 0x51, 0x67, 0x69, 0x61, 0x68, 0x34, 0x50, 0x62, 0x78, 0x74, 0x73, 0x45, 0x31, 0x35,
280 0x52,0x68,0x38,0x53,0x52,0x6c,0x34,0x65,0x44,0x48,0x77,0x34,0x41,0x57,0x46,0x6b, 278 0x35, 0x49, 0x48, 0x6c, 0x51, 0x59, 0x67, 0x59, 0x73, 0x64, 0x68, 0x63, 0x45, 0x4b, 0x79,
281 0x64,0x69,0x4a,0x75,0x43,0x43,0x41,0x34,0x54,0x33,0x4e,0x79,0x56,0x52,0x4a,0x43, 279 0x70, 0x31, 0x48, 0x77, 0x77, 0x33, 0x54, 0x67, 0x39, 0x37, 0x4c, 0x54, 0x52, 0x31, 0x59,
282 0x47,0x56,0x42,0x68,0x51,0x33,0x64,0x39,0x51,0x53,0x34,0x31,0x54,0x7a,0x30,0x78, 280 0x44, 0x46, 0x30, 0x4c, 0x67, 0x70, 0x4b, 0x45, 0x57, 0x78, 0x4a, 0x4a, 0x51, 0x45, 0x36,
283 0x4b,0x46,0x68,0x6e,0x47,0x77,0x4e,0x52,0x49,0x44,0x49,0x63,0x43,0x47,0x34,0x33, 281 0x50, 0x53, 0x49, 0x65, 0x62, 0x52, 0x68, 0x52, 0x65, 0x43, 0x31, 0x69, 0x4d, 0x55, 0x78,
284 0x64,0x54,0x64,0x45,0x54,0x32,0x67,0x5a,0x42,0x32,0x51,0x55,0x4b,0x43,0x55,0x72, 282 0x51, 0x51, 0x42, 0x64, 0x4c, 0x62, 0x79, 0x49, 0x41, 0x66, 0x32, 0x45, 0x71, 0x4e, 0x44,
285 0x61,0x54,0x55,0x59,0x4a,0x79,0x59,0x55,0x45,0x33,0x42,0x43,0x47,0x52,0x4a,0x31, 283 0x34, 0x41, 0x58, 0x79, 0x39, 0x66, 0x4c, 0x78, 0x51, 0x71, 0x56, 0x53, 0x63, 0x66, 0x52,
286 0x50,0x67,0x4a,0x64,0x66,0x42,0x4d,0x66,0x46,0x6c,0x4d,0x37,0x64,0x45,0x67,0x38, 284 0x68, 0x38, 0x53, 0x52, 0x6c, 0x34, 0x65, 0x44, 0x48, 0x77, 0x34, 0x41, 0x57, 0x46, 0x6b,
287 0x58,0x6a,0x6c,0x73,0x48,0x42,0x78,0x30,0x4f,0x52,0x38,0x41,0x47,0x77,0x59,0x4b, 285 0x64, 0x69, 0x4a, 0x75, 0x43, 0x43, 0x41, 0x34, 0x54, 0x33, 0x4e, 0x79, 0x56, 0x52, 0x4a,
288 0x61,0x44,0x74,0x53,0x54,0x78,0x35,0x75,0x50,0x44,0x55,0x4d,0x4f,0x41,0x34,0x4c, 286 0x43, 0x47, 0x56, 0x42, 0x68, 0x51, 0x33, 0x64, 0x39, 0x51, 0x53, 0x34, 0x31, 0x54, 0x7a,
289 0x4f,0x78,0x70,0x32,0x49,0x79,0x6c,0x54,0x48,0x6c,0x39,0x42,0x44,0x45,0x73,0x4b, 287 0x30, 0x78, 0x4b, 0x46, 0x68, 0x6e, 0x47, 0x77, 0x4e, 0x52, 0x49, 0x44, 0x49, 0x63, 0x43,
290 0x5a,0x53,0x68,0x34,0x5a,0x30,0x68,0x5a,0x4a,0x6d,0x30,0x78,0x64,0x69,0x4e,0x77, 288 0x47, 0x34, 0x33, 0x64, 0x54, 0x64, 0x45, 0x54, 0x32, 0x67, 0x5a, 0x42, 0x32, 0x51, 0x55,
291 0x59,0x57,0x51,0x37,0x4f,0x48,0x6c,0x6d,0x64,0x46,0x4d,0x73,0x5a,0x47,0x52,0x55, 289 0x4b, 0x43, 0x55, 0x72, 0x61, 0x54, 0x55, 0x59, 0x4a, 0x79, 0x59, 0x55, 0x45, 0x33, 0x42,
292 0x41,0x31,0x52,0x6c,0x52,0x45,0x77,0x59,0x54,0x30,0x67,0x67,0x54,0x33,0x49,0x51, 290 0x43, 0x47, 0x52, 0x4a, 0x31, 0x50, 0x67, 0x4a, 0x64, 0x66, 0x42, 0x4d, 0x66, 0x46, 0x6c,
293 0x50,0x77,0x78,0x53,0x4c,0x51,0x4d,0x55,0x41,0x31,0x46,0x43,0x45,0x48,0x64,0x71, 291 0x4d, 0x37, 0x64, 0x45, 0x67, 0x38, 0x58, 0x6a, 0x6c, 0x73, 0x48, 0x42, 0x78, 0x30, 0x4f,
294 0x4e,0x41,0x59,0x79,0x41,0x33,0x49,0x55,0x66,0x41,0x68,0x64,0x55,0x68,0x70,0x69, 292 0x52, 0x38, 0x41, 0x47, 0x77, 0x59, 0x4b, 0x61, 0x44, 0x74, 0x53, 0x54, 0x78, 0x35, 0x75,
295 0x66,0x44,0x34,0x77,0x66,0x6c,0x39,0x2f,0x56,0x41,0x39,0x45,0x53,0x56,0x31,0x65, 293 0x50, 0x44, 0x55, 0x4d, 0x4f, 0x41, 0x34, 0x4c, 0x4f, 0x78, 0x70, 0x32, 0x49, 0x79, 0x6c,
296 0x45,0x47,0x6f,0x47,0x4b,0x77,0x5a,0x54,0x45,0x44,0x6b,0x33,0x4d,0x6b,0x70,0x4f, 294 0x54, 0x48, 0x6c, 0x39, 0x42, 0x44, 0x45, 0x73, 0x4b, 0x5a, 0x53, 0x68, 0x34, 0x5a, 0x30,
297 0x50,0x53,0x74,0x6c,0x4f,0x44,0x6b,0x48,0x63,0x6c,0x52,0x6b,0x54,0x56,0x5a,0x71, 295 0x68, 0x5a, 0x4a, 0x6d, 0x30, 0x78, 0x64, 0x69, 0x4e, 0x77, 0x59, 0x57, 0x51, 0x37, 0x4f,
298 0x41,0x79,0x4a,0x77,0x65,0x31,0x39,0x67,0x43,0x79,0x6f,0x4c,0x61,0x78,0x42,0x6b, 296 0x48, 0x6c, 0x6d, 0x64, 0x46, 0x4d, 0x73, 0x5a, 0x47, 0x52, 0x55, 0x41, 0x31, 0x52, 0x6c,
299 0x46,0x41,0x55,0x69,0x41,0x48,0x4e,0x41,0x49,0x31,0x74,0x52,0x48,0x79,0x73,0x61, 297 0x52, 0x45, 0x77, 0x59, 0x54, 0x30, 0x67, 0x67, 0x54, 0x33, 0x49, 0x51, 0x50, 0x77, 0x78,
300 0x58,0x57,0x6c,0x36,0x52,0x67,0x78,0x66,0x4d,0x6b,0x74,0x4b,0x4b,0x46,0x4a,0x35, 298 0x53, 0x4c, 0x51, 0x4d, 0x55, 0x41, 0x31, 0x46, 0x43, 0x45, 0x48, 0x64, 0x71, 0x4e, 0x41,
301 0x57,0x78,0x4a,0x43,0x47,0x41,0x42,0x64,0x4a,0x7a,0x46,0x54,0x50,0x45,0x77,0x32, 299 0x59, 0x79, 0x41, 0x33, 0x49, 0x55, 0x66, 0x41, 0x68, 0x64, 0x55, 0x68, 0x70, 0x69, 0x66,
302 0x54,0x6a,0x67,0x2f,0x63,0x67,0x4e,0x78,0x41,0x6c,0x73,0x32,0x57,0x58,0x39,0x31, 300 0x44, 0x34, 0x77, 0x66, 0x6c, 0x39, 0x2f, 0x56, 0x41, 0x39, 0x45, 0x53, 0x56, 0x31, 0x65,
303 0x62,0x67,0x68,0x55,0x44,0x54,0x51,0x63,0x4e,0x46,0x64,0x64,0x61,0x55,0x67,0x41, 301 0x45, 0x47, 0x6f, 0x47, 0x4b, 0x77, 0x5a, 0x54, 0x45, 0x44, 0x6b, 0x33, 0x4d, 0x6b, 0x70,
304 0x4f,0x77,0x55,0x48,0x62,0x69,0x64,0x6c,0x62,0x6b,0x41,0x39,0x4f,0x6b,0x39,0x79, 302 0x4f, 0x50, 0x53, 0x74, 0x6c, 0x4f, 0x44, 0x6b, 0x48, 0x63, 0x6c, 0x52, 0x6b, 0x54, 0x56,
305 0x58,0x54,0x6b,0x57,0x44,0x32,0x4d,0x53,0x45,0x68,0x55,0x36,0x63,0x41,0x31,0x58, 303 0x5a, 0x71, 0x41, 0x79, 0x4a, 0x77, 0x65, 0x31, 0x39, 0x67, 0x43, 0x79, 0x6f, 0x4c, 0x61,
306 0x47,0x41,0x31,0x65,0x50,0x53,0x4a,0x6f,0x61,0x48,0x78,0x74,0x54,0x77,0x78,0x37, 304 0x78, 0x42, 0x6b, 0x46, 0x41, 0x55, 0x69, 0x41, 0x48, 0x4e, 0x41, 0x49, 0x31, 0x74, 0x52,
307 0x43,0x53,0x31,0x4b,0x63,0x79,0x42,0x48,0x42,0x31,0x64,0x31,0x58,0x56,0x4e,0x77, 305 0x48, 0x79, 0x73, 0x61, 0x58, 0x57, 0x6c, 0x36, 0x52, 0x67, 0x78, 0x66, 0x4d, 0x6b, 0x74,
308 0x4e,0x43,0x46,0x41,0x56,0x31,0x46,0x65,0x53,0x55,0x51,0x41,0x56,0x43,0x63,0x45, 306 0x4b, 0x4b, 0x46, 0x4a, 0x35, 0x57, 0x78, 0x4a, 0x43, 0x47, 0x41, 0x42, 0x64, 0x4a, 0x7a,
309 0x61,0x48,0x35,0x5a,0x56,0x6c,0x68,0x30,0x46,0x44,0x77,0x57,0x4d,0x30,0x45,0x57, 307 0x46, 0x54, 0x50, 0x45, 0x77, 0x32, 0x54, 0x6a, 0x67, 0x2f, 0x63, 0x67, 0x4e, 0x78, 0x41,
310 0x53,0x79,0x39,0x4a,0x4e,0x77,0x70,0x55,0x43,0x41,0x67,0x66,0x4f,0x57,0x64,0x32, 308 0x6c, 0x73, 0x32, 0x57, 0x58, 0x39, 0x31, 0x62, 0x67, 0x68, 0x55, 0x44, 0x54, 0x51, 0x63,
311 0x4b,0x43,0x67,0x48,0x48,0x57,0x46,0x48,0x55,0x55,0x31,0x31,0x4a,0x6c,0x4a,0x48, 309 0x4e, 0x46, 0x64, 0x64, 0x61, 0x55, 0x67, 0x41, 0x4f, 0x77, 0x55, 0x48, 0x62, 0x69, 0x64,
312 0x52,0x77,0x78,0x58,0x57,0x48,0x51,0x2b,0x59,0x6d,0x78,0x59,0x4f,0x6b,0x51,0x65, 310 0x6c, 0x62, 0x6b, 0x41, 0x39, 0x4f, 0x6b, 0x39, 0x79, 0x58, 0x54, 0x6b, 0x57, 0x44, 0x32,
313 0x46,0x69,0x34,0x68,0x48,0x48,0x4e,0x46,0x5a,0x33,0x52,0x50,0x4d,0x32,0x59,0x4f, 311 0x4d, 0x53, 0x45, 0x68, 0x55, 0x36, 0x63, 0x41, 0x31, 0x58, 0x47, 0x41, 0x31, 0x65, 0x50,
314 0x64,0x47,0x59,0x6d,0x48,0x79,0x34,0x34,0x52,0x45,0x42,0x2b,0x4b,0x6c,0x42,0x53, 312 0x53, 0x4a, 0x6f, 0x61, 0x48, 0x78, 0x74, 0x54, 0x77, 0x78, 0x37, 0x43, 0x53, 0x31, 0x4b,
315 0x58,0x6b,0x4d,0x42,0x65,0x6a,0x68,0x4a,0x50,0x46,0x56,0x4e,0x57,0x6b,0x51,0x49, 313 0x63, 0x79, 0x42, 0x48, 0x42, 0x31, 0x64, 0x31, 0x58, 0x56, 0x4e, 0x77, 0x4e, 0x43, 0x46,
316 0x4a,0x6c,0x6c,0x4e,0x52,0x51,0x74,0x49,0x43,0x6a,0x4e,0x65,0x53,0x6b,0x31,0x31, 314 0x41, 0x56, 0x31, 0x46, 0x65, 0x53, 0x55, 0x51, 0x41, 0x56, 0x43, 0x63, 0x45, 0x61, 0x48,
317 0x46,0x68,0x64,0x6a,0x52,0x67,0x45,0x71,0x56,0x58,0x73,0x50,0x41,0x6e,0x4e,0x71, 315 0x35, 0x5a, 0x56, 0x6c, 0x68, 0x30, 0x46, 0x44, 0x77, 0x57, 0x4d, 0x30, 0x45, 0x57, 0x53,
318 0x53,0x33,0x39,0x31,0x5a,0x54,0x78,0x4d,0x4d,0x7a,0x6c,0x73,0x64,0x41,0x56,0x67, 316 0x79, 0x39, 0x4a, 0x4e, 0x77, 0x70, 0x55, 0x43, 0x41, 0x67, 0x66, 0x4f, 0x57, 0x64, 0x32,
319 0x44,0x33,0x38,0x74,0x51,0x55,0x31,0x4e,0x52,0x6e,0x45,0x4a,0x62,0x30,0x39,0x67, 317 0x4b, 0x43, 0x67, 0x48, 0x48, 0x57, 0x46, 0x48, 0x55, 0x55, 0x31, 0x31, 0x4a, 0x6c, 0x4a,
320 0x46,0x51,0x39,0x47,0x63,0x32,0x4e,0x4d,0x58,0x6e,0x51,0x77,0x44,0x53,0x68,0x44, 318 0x48, 0x52, 0x77, 0x78, 0x58, 0x57, 0x48, 0x51, 0x2b, 0x59, 0x6d, 0x78, 0x59, 0x4f, 0x6b,
321 0x43,0x48,0x49,0x79,0x42,0x43,0x34,0x78,0x4b,0x53,0x64,0x45,0x62,0x52,0x4d,0x58, 319 0x51, 0x65, 0x46, 0x69, 0x34, 0x68, 0x48, 0x48, 0x4e, 0x46, 0x5a, 0x33, 0x52, 0x50, 0x4d,
322 0x53,0x41,0x39,0x4a,0x55,0x68,0x41,0x54,0x66,0x78,0x63,0x57,0x59,0x6e,0x6b,0x31, 320 0x32, 0x59, 0x4f, 0x64, 0x47, 0x59, 0x6d, 0x48, 0x79, 0x34, 0x34, 0x52, 0x45, 0x42, 0x2b,
323 0x65,0x44,0x34,0x42,0x66,0x43,0x34,0x50,0x64,0x6a,0x35,0x65,0x55,0x32,0x78,0x62, 321 0x4b, 0x6c, 0x42, 0x53, 0x58, 0x6b, 0x4d, 0x42, 0x65, 0x6a, 0x68, 0x4a, 0x50, 0x46, 0x56,
324 0x58,0x33,0x77,0x5a,0x51,0x51,0x49,0x76,0x46,0x32,0x52,0x42,0x64,0x52,0x41,0x45, 322 0x4e, 0x57, 0x6b, 0x51, 0x49, 0x4a, 0x6c, 0x6c, 0x4e, 0x52, 0x51, 0x74, 0x49, 0x43, 0x6a,
325 0x52,0x33,0x77,0x39,0x53,0x31,0x49,0x41,0x45,0x46,0x31,0x52,0x54,0x6e,0x6f,0x6e, 323 0x4e, 0x65, 0x53, 0x6b, 0x31, 0x31, 0x46, 0x68, 0x64, 0x6a, 0x52, 0x67, 0x45, 0x71, 0x56,
326 0x4a,0x56,0x56,0x41,0x45,0x6a,0x56,0x67,0x42,0x52,0x73,0x30,0x4c,0x51,0x52,0x36, 324 0x58, 0x73, 0x50, 0x41, 0x6e, 0x4e, 0x71, 0x53, 0x33, 0x39, 0x31, 0x5a, 0x54, 0x78, 0x4d,
327 0x61,0x6d,0x6b,0x43,0x65,0x51,0x4d,0x36,0x4c,0x77,0x59,0x4b,0x65,0x58,0x73,0x53, 325 0x4d, 0x7a, 0x6c, 0x73, 0x64, 0x41, 0x56, 0x67, 0x44, 0x33, 0x38, 0x74, 0x51, 0x55, 0x31,
328 0x58,0x58,0x78,0x53,0x4b,0x55,0x64,0x59,0x45,0x6e,0x4d,0x2f,0x4a,0x31,0x59,0x46, 326 0x4e, 0x52, 0x6e, 0x45, 0x4a, 0x62, 0x30, 0x39, 0x67, 0x46, 0x51, 0x39, 0x47, 0x63, 0x32,
329 0x44,0x45,0x67,0x79,0x57,0x47,0x74,0x58,0x58,0x41,0x4e,0x6b,0x56,0x68,0x46,0x53, 327 0x4e, 0x4d, 0x58, 0x6e, 0x51, 0x77, 0x44, 0x53, 0x68, 0x44, 0x43, 0x48, 0x49, 0x79, 0x42,
330 0x65,0x6a,0x41,0x32,0x4b,0x52,0x63,0x37,0x61,0x48,0x70,0x38,0x42,0x57,0x74,0x72, 328 0x43, 0x34, 0x78, 0x4b, 0x53, 0x64, 0x45, 0x62, 0x52, 0x4d, 0x58, 0x53, 0x41, 0x39, 0x4a,
331 0x45,0x32,0x6f,0x6b,0x58,0x47,0x68,0x43,0x47,0x44,0x49,0x44,0x63,0x32,0x34,0x45, 329 0x55, 0x68, 0x41, 0x54, 0x66, 0x78, 0x63, 0x57, 0x59, 0x6e, 0x6b, 0x31, 0x65, 0x44, 0x34,
332 0x49,0x53,0x34,0x42,0x42,0x47,0x4e,0x39,0x52,0x45,0x45,0x53,0x4d,0x51,0x73,0x56, 330 0x42, 0x66, 0x43, 0x34, 0x50, 0x64, 0x6a, 0x35, 0x65, 0x55, 0x32, 0x78, 0x62, 0x58, 0x33,
333 0x48,0x33,0x41,0x41,0x4c,0x6d,0x59,0x55,0x50,0x48,0x38,0x72,0x41,0x42,0x38,0x4d, 331 0x77, 0x5a, 0x51, 0x51, 0x49, 0x76, 0x46, 0x32, 0x52, 0x42, 0x64, 0x52, 0x41, 0x45, 0x52,
334 0x4b,0x46,0x6b,0x4b,0x46,0x6b,0x6c,0x61,0x58,0x47,0x52,0x6c,0x53,0x78,0x45,0x70, 332 0x33, 0x77, 0x39, 0x53, 0x31, 0x49, 0x41, 0x45, 0x46, 0x31, 0x52, 0x54, 0x6e, 0x6f, 0x6e,
335 0x46,0x54,0x5a,0x61,0x5a,0x52,0x6c,0x50,0x59,0x43,0x4d,0x36,0x4f,0x68,0x4d,0x6c, 333 0x4a, 0x56, 0x56, 0x41, 0x45, 0x6a, 0x56, 0x67, 0x42, 0x52, 0x73, 0x30, 0x4c, 0x51, 0x52,
336 0x41,0x6e,0x68,0x4d,0x56,0x41,0x3d,0x3d,0x00 334 0x36, 0x61, 0x6d, 0x6b, 0x43, 0x65, 0x51, 0x4d, 0x36, 0x4c, 0x77, 0x59, 0x4b, 0x65, 0x58,
337 }; 335 0x73, 0x53, 0x58, 0x58, 0x78, 0x53, 0x4b, 0x55, 0x64, 0x59, 0x45, 0x6e, 0x4d, 0x2f, 0x4a,
336 0x31, 0x59, 0x46, 0x44, 0x45, 0x67, 0x79, 0x57, 0x47, 0x74, 0x58, 0x58, 0x41, 0x4e, 0x6b,
337 0x56, 0x68, 0x46, 0x53, 0x65, 0x6a, 0x41, 0x32, 0x4b, 0x52, 0x63, 0x37, 0x61, 0x48, 0x70,
338 0x38, 0x42, 0x57, 0x74, 0x72, 0x45, 0x32, 0x6f, 0x6b, 0x58, 0x47, 0x68, 0x43, 0x47, 0x44,
339 0x49, 0x44, 0x63, 0x32, 0x34, 0x45, 0x49, 0x53, 0x34, 0x42, 0x42, 0x47, 0x4e, 0x39, 0x52,
340 0x45, 0x45, 0x53, 0x4d, 0x51, 0x73, 0x56, 0x48, 0x33, 0x41, 0x41, 0x4c, 0x6d, 0x59, 0x55,
341 0x50, 0x48, 0x38, 0x72, 0x41, 0x42, 0x38, 0x4d, 0x4b, 0x46, 0x6b, 0x4b, 0x46, 0x6b, 0x6c,
342 0x61, 0x58, 0x47, 0x52, 0x6c, 0x53, 0x78, 0x45, 0x70, 0x46, 0x54, 0x5a, 0x61, 0x5a, 0x52,
343 0x6c, 0x50, 0x59, 0x43, 0x4d, 0x36, 0x4f, 0x68, 0x4d, 0x6c, 0x41, 0x6e, 0x68, 0x4d, 0x56,
344 0x41, 0x3d, 0x3d, 0x00};
338 char *b64_test; 345 char *b64_test;
339 346
340 plan_tests(1); 347 plan_tests(1);
341 348
342 base64_encode_alloc (random, 1024, &b64_test); 349 base64_encode_alloc(random, 1024, &b64_test);
343 350
344 ok(strcmp(b64_known, b64_test) == 0, 351 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 352
347 return exit_status(); 353 return exit_status();
348} 354}
349
diff --git a/lib/tests/test_cmd.c b/lib/tests/test_cmd.c
index 02ae11f5..d51016cc 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,212 +22,186 @@
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)
44{
45 char **command_line = malloc (sizeof (char *) * COMMAND_LINE);
46 char *command = NULL;
47 char *perl;
48 output chld_out, chld_err;
49 int c;
50 int result = UNSET;
51
52 plan_tests(51); 41 plan_tests(51);
53 42
54 diag ("Running plain echo command, set one"); 43 diag("Running plain echo command, set one");
55 44
56 /* ensure everything is empty before we begin */ 45 /* ensure everything is empty before we begin */
57 memset (&chld_out, 0, sizeof (output)); 46
58 memset (&chld_err, 0, sizeof (output)); 47 output chld_out;
59 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 48 memset(&chld_out, 0, sizeof(output));
60 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 49 output chld_err;
61 ok (result == UNSET, "(initialised) Checking exit code is reset"); 50 memset(&chld_err, 0, sizeof(output));
62 51 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
63 command_line[0] = strdup ("/bin/echo"); 52 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
64 command_line[1] = strdup ("this"); 53 int result = UNSET;
65 command_line[2] = strdup ("is"); 54 ok(result == UNSET, "(initialised) Checking exit code is reset");
66 command_line[3] = strdup ("test"); 55
67 command_line[4] = strdup ("one"); 56 char **command_line = malloc(sizeof(char *) * COMMAND_LINE);
68 57 command_line[0] = strdup("/bin/echo");
69 command = get_command (command_line); 58 command_line[1] = strdup("this");
70 59 command_line[2] = strdup("is");
71 result = cmd_run_array (command_line, &chld_out, &chld_err, 0); 60 command_line[3] = strdup("test");
72 ok (chld_out.lines == 1, 61 command_line[4] = strdup("one");
73 "(array) Check for expected number of stdout lines"); 62
74 ok (chld_err.lines == 0, 63 char *command = get_command(command_line);
75 "(array) Check for expected number of stderr lines"); 64
76 ok (strcmp (chld_out.line[0], "this is test one") == 0, 65 result = cmd_run_array(command_line, &chld_out, &chld_err, 0);
77 "(array) Check for expected stdout output"); 66 ok(chld_out.lines == 1, "(array) Check for expected number of stdout lines");
78 ok (result == 0, "(array) Checking exit code"); 67 ok(chld_err.lines == 0, "(array) Check for expected number of stderr lines");
68 ok(strcmp(chld_out.line[0], "this is test one") == 0,
69 "(array) Check for expected stdout output");
70 ok(result == 0, "(array) Checking exit code");
79 71
80 /* ensure everything is empty again */ 72 /* ensure everything is empty again */
81 memset (&chld_out, 0, sizeof (output)); 73 memset(&chld_out, 0, sizeof(output));
82 memset (&chld_err, 0, sizeof (output)); 74 memset(&chld_err, 0, sizeof(output));
83 result = UNSET; 75 result = UNSET;
84 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 76 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
85 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 77 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
86 ok (result == UNSET, "(initialised) Checking exit code is reset"); 78 ok(result == UNSET, "(initialised) Checking exit code is reset");
87 79
88 result = cmd_run (command, &chld_out, &chld_err, 0); 80 result = cmd_run(command, &chld_out, &chld_err, 0);
89 81
90 ok (chld_out.lines == 1, 82 ok(chld_out.lines == 1, "(string) Check for expected number of stdout lines");
91 "(string) Check for expected number of stdout lines"); 83 ok(chld_err.lines == 0, "(string) Check for expected number of stderr lines");
92 ok (chld_err.lines == 0, 84 ok(strcmp(chld_out.line[0], "this is test one") == 0,
93 "(string) Check for expected number of stderr lines"); 85 "(string) Check for expected stdout output");
94 ok (strcmp (chld_out.line[0], "this is test one") == 0, 86 ok(result == 0, "(string) Checking exit code");
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,
118 "(array) Check for expected number of stderr lines"); 108 "(array) Check for expected stdout output");
119 ok (strcmp (chld_out.line[0], "this is test two") == 0, 109 ok(result == 0, "(array) Checking exit code");
120 "(array) Check for expected stdout output");
121 ok (result == 0, "(array) Checking exit code");
122 110
123 /* ensure everything is empty again */ 111 /* ensure everything is empty again */
124 memset (&chld_out, 0, sizeof (output)); 112 memset(&chld_out, 0, sizeof(output));
125 memset (&chld_err, 0, sizeof (output)); 113 memset(&chld_err, 0, sizeof(output));
126 result = UNSET; 114 result = UNSET;
127 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 115 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
128 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 116 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
129 ok (result == UNSET, "(initialised) Checking exit code is reset"); 117 ok(result == UNSET, "(initialised) Checking exit code is reset");
130
131 result = cmd_run (command, &chld_out, &chld_err, 0);
132 118
133 ok (chld_out.lines == 1, 119 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 120
121 ok(chld_out.lines == 1, "(string) Check for expected number of stdout lines");
122 ok(chld_err.lines == 0, "(string) Check for expected number of stderr lines");
123 ok(strcmp(chld_out.line[0], "this is test one") == 0,
124 "(string) Check for expected stdout output");
125 ok(result == 0, "(string) Checking exit code");
141 126
142 /* ensure everything is empty again */ 127 /* ensure everything is empty again */
143 memset (&chld_out, 0, sizeof (output)); 128 memset(&chld_out, 0, sizeof(output));
144 memset (&chld_err, 0, sizeof (output)); 129 memset(&chld_err, 0, sizeof(output));
145 result = UNSET; 130 result = UNSET;
146 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 131 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
147 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 132 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
148 ok (result == UNSET, "(initialised) Checking exit code is reset"); 133 ok(result == UNSET, "(initialised) Checking exit code is reset");
149 134
150 /* Pass linefeeds via parameters through - those should be evaluated by echo to give multi line output */ 135 /* Pass linefeeds via parameters through - those should be evaluated by echo to give multi line
136 * output */
151 command_line[0] = strdup("/bin/echo"); 137 command_line[0] = strdup("/bin/echo");
152 command_line[1] = strdup("this is a test via echo\nline two\nit's line 3"); 138 command_line[1] = strdup("this is a test via echo\nline two\nit's line 3");
153 command_line[2] = strdup("and (note space between '3' and 'and') $$ will not get evaluated"); 139 command_line[2] = strdup("and (note space between '3' and 'and') $$ will not get evaluated");
154 140
155 result = cmd_run_array (command_line, &chld_out, &chld_err, 0); 141 result = cmd_run_array(command_line, &chld_out, &chld_err, 0);
156 ok (chld_out.lines == 3, 142 ok(chld_out.lines == 3, "(array) Check for expected number of stdout lines");
157 "(array) Check for expected number of stdout lines"); 143 ok(chld_err.lines == 0, "(array) Check for expected number of stderr lines");
158 ok (chld_err.lines == 0, 144 ok(strcmp(chld_out.line[0], "this is a test via echo") == 0,
159 "(array) Check for expected number of stderr lines"); 145 "(array) Check line 1 for expected stdout output");
160 ok (strcmp (chld_out.line[0], "this is a test via echo") == 0, 146 ok(strcmp(chld_out.line[1], "line two") == 0,
161 "(array) Check line 1 for expected stdout output"); 147 "(array) Check line 2 for expected stdout output");
162 ok (strcmp (chld_out.line[1], "line two") == 0, 148 ok(strcmp(chld_out.line[2],
163 "(array) Check line 2 for expected stdout output"); 149 "it's line 3 and (note space between '3' and 'and') $$ will not get evaluated") == 0,
164 ok (strcmp (chld_out.line[2], "it's line 3 and (note space between '3' and 'and') $$ will not get evaluated") == 0, 150 "(array) Check line 3 for expected stdout output");
165 "(array) Check line 3 for expected stdout output"); 151 ok(result == 0, "(array) Checking exit code");
166 ok (result == 0, "(array) Checking exit code");
167
168
169 152
170 /* ensure everything is empty again */ 153 /* ensure everything is empty again */
171 memset (&chld_out, 0, sizeof (output)); 154 memset(&chld_out, 0, sizeof(output));
172 memset (&chld_err, 0, sizeof (output)); 155 memset(&chld_err, 0, sizeof(output));
173 result = UNSET; 156 result = UNSET;
174 ok (chld_out.lines == 0, "(initialised) Checking stdout is reset"); 157 ok(chld_out.lines == 0, "(initialised) Checking stdout is reset");
175 ok (chld_err.lines == 0, "(initialised) Checking stderr is reset"); 158 ok(chld_err.lines == 0, "(initialised) Checking stderr is reset");
176 ok (result == UNSET, "(initialised) Checking exit code is reset"); 159 ok(result == UNSET, "(initialised) Checking exit code is reset");
177 160
178 command = (char *)malloc(COMMAND_LINE); 161 command = (char *)malloc(COMMAND_LINE);
179 strcpy(command, "/bin/echo3456 non-existent command"); 162 strcpy(command, "/bin/echo3456 non-existent command");
180 result = cmd_run (command, &chld_out, &chld_err, 0); 163 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 164
165 ok(chld_out.lines == 0, "Non existent command, so no output");
166 ok(chld_err.lines == 0, "No stderr either");
167 ok(result == 3, "Get return code 3 (?) for non-existent command");
188 168
189 /* ensure everything is empty again */ 169 /* ensure everything is empty again */
190 memset (&chld_out, 0, sizeof (output)); 170 memset(&chld_out, 0, sizeof(output));
191 memset (&chld_err, 0, sizeof (output)); 171 memset(&chld_err, 0, sizeof(output));
192 result = UNSET; 172 result = UNSET;
193 173
194 command = (char *)malloc(COMMAND_LINE); 174 command = (char *)malloc(COMMAND_LINE);
195 strcpy(command, "/bin/sh non-existent-file"); 175 strcpy(command, "/bin/sh non-existent-file");
196 result = cmd_run (command, &chld_out, &chld_err, 0); 176 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 177
178 ok(chld_out.lines == 0, "/bin/sh returns no stdout when file is missing...");
179 ok(chld_err.lines == 1, "...but does give an error line");
180 ok(strstr(chld_err.line[0], "non-existent-file") != NULL,
181 "And missing filename is in error message");
182 ok(result != 0, "Get non-zero return code from /bin/sh");
205 183
206 /* ensure everything is empty again */ 184 /* ensure everything is empty again */
207 result = UNSET; 185 result = UNSET;
208 186
209 command = (char *)malloc(COMMAND_LINE); 187 command = (char *)malloc(COMMAND_LINE);
210 strcpy(command, "/bin/sh -c 'exit 7'"); 188 strcpy(command, "/bin/sh -c 'exit 7'");
211 result = cmd_run (command, NULL, NULL, 0); 189 result = cmd_run(command, NULL, NULL, 0);
212
213 ok (result == 7, "Get return code 7 from /bin/sh");
214 190
191 ok(result == 7, "Get return code 7 from /bin/sh");
215 192
216 /* ensure everything is empty again */ 193 /* ensure everything is empty again */
217 memset (&chld_out, 0, sizeof (output)); 194 memset(&chld_out, 0, sizeof(output));
218 memset (&chld_err, 0, sizeof (output)); 195 memset(&chld_err, 0, sizeof(output));
219 result = UNSET; 196 result = UNSET;
220 197
221 command = (char *)malloc(COMMAND_LINE); 198 command = (char *)malloc(COMMAND_LINE);
222 strcpy(command, "/bin/non-existent-command"); 199 strcpy(command, "/bin/non-existent-command");
223 result = cmd_run (command, &chld_out, &chld_err, 0); 200 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 201
202 ok(chld_out.lines == 0, "/bin/non-existent-command returns no stdout...");
203 ok(chld_err.lines == 0, "...and no stderr output either");
204 ok(result == 3, "Get return code 3 = UNKNOWN when command does not exist");
231 205
232 return exit_status (); 206 return exit_status();
233} 207}
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..e4a78bcd
--- /dev/null
+++ b/lib/tests/test_generic_output.c
@@ -0,0 +1,317 @@
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,
114 "Test subcheck state directly after setting it");
115
116 mp_perfdata pd1 = perfdata_init();
117
118 pd1 = mp_set_pd_value(pd1, 23);
119
120 pd1.uom = "s";
121 pd1.label = "foo";
122
123 mp_add_perfdata_to_subcheck(&sc1, pd1);
124
125 mp_subcheck sc2 = mp_subcheck_init();
126 sc2.output = "baz";
127 sc2 = mp_set_subcheck_state(sc2, STATE_OK);
128
129 ok(mp_compute_subcheck_state(sc2) == STATE_OK, "Test subcheck 2 state after setting it");
130
131 mp_add_subcheck_to_subcheck(&sc1, sc2);
132
133 ok(mp_compute_subcheck_state(sc1) == STATE_WARNING,
134 "Test subcheck state after adding a subcheck");
135
136 mp_check check = mp_check_init();
137 mp_add_subcheck_to_check(&check, sc1);
138
139 ok(mp_compute_check_state(check) == STATE_WARNING, "Test main check result");
140
141 char *output = mp_fmt_output(check);
142
143 // diag("Formatted output. Length: %u", strlen(output));
144 // diag(output);
145
146 ok(output != NULL, "Output should not be NULL");
147
148 char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n"
149 "\t\\_[WARNING] - foobar\n"
150 "\t\t\\_[OK] - baz\n"
151 "|foo=23s;;; \n";
152
153 // diag("Expected output. Length: %u", strlen(expected));
154 // diag(expected);
155
156 ok(strcmp(output, expected) == 0, "Output is as expected");
157}
158
159void test_deep_check_hierarchy(void) {
160 // level 4
161 mp_subcheck sc4 = mp_subcheck_init();
162 sc4.output = "level4";
163 sc4 = mp_set_subcheck_state(sc4, STATE_OK);
164
165 // level 3
166 mp_subcheck sc3 = mp_subcheck_init();
167 sc3.output = "level3";
168 sc3 = mp_set_subcheck_state(sc3, STATE_OK);
169
170 // level 2
171 mp_subcheck sc2 = mp_subcheck_init();
172 sc2.output = "baz";
173 sc2 = mp_set_subcheck_state(sc2, STATE_OK);
174
175 // level 1
176 mp_subcheck sc1 = mp_subcheck_init();
177
178 sc1.output = "foobar";
179 sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
180
181 mp_perfdata pd1 = perfdata_init();
182
183 pd1.uom = "s";
184 pd1.label = "foo";
185 pd1 = mp_set_pd_value(pd1, 23);
186
187 mp_add_perfdata_to_subcheck(&sc1, pd1);
188
189 // main check
190 mp_check check = mp_check_init();
191
192 mp_add_subcheck_to_subcheck(&sc3, sc4);
193 mp_add_subcheck_to_subcheck(&sc2, sc3);
194 mp_add_subcheck_to_subcheck(&sc1, sc2);
195 mp_add_subcheck_to_check(&check, sc1);
196
197 char *output = mp_fmt_output(check);
198
199 size_t output_length = strlen(output);
200
201 // diag("Formatted output of length %i", output_length);
202 // diag(output);
203
204 ok(output != NULL, "Output should not be NULL");
205
206 char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n"
207 "\t\\_[WARNING] - foobar\n"
208 "\t\t\\_[OK] - baz\n"
209 "\t\t\t\\_[OK] - level3\n"
210 "\t\t\t\t\\_[OK] - level4\n"
211 "|foo=23s;;; \n";
212
213 size_t expected_length = strlen(expected);
214
215 // diag("Expected output of length: %i", expected_length);
216 // diag(expected);
217
218 ok(output_length == expected_length, "Outputs are of equal length");
219 ok(strcmp(output, expected) == 0, "Output is as expected");
220}
221
222void test_deep_check_hierarchy2(void) {
223 // level 1
224 mp_subcheck sc1 = mp_subcheck_init();
225
226 sc1.output = "foobar";
227 sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
228
229 mp_perfdata pd1 = perfdata_init();
230 pd1.uom = "s";
231 pd1.label = "foo";
232 pd1 = mp_set_pd_value(pd1, 23);
233
234 mp_add_perfdata_to_subcheck(&sc1, pd1);
235
236 // level 2
237 mp_subcheck sc2 = mp_subcheck_init();
238 sc2.output = "baz";
239 sc2 = mp_set_subcheck_state(sc2, STATE_OK);
240
241 mp_perfdata pd2 = perfdata_init();
242 pd2.uom = "B";
243 pd2.label = "baz";
244 pd2 = mp_set_pd_value(pd2, 1024);
245 mp_add_perfdata_to_subcheck(&sc2, pd2);
246
247 // level 3
248 mp_subcheck sc3 = mp_subcheck_init();
249 sc3.output = "level3";
250 sc3 = mp_set_subcheck_state(sc3, STATE_OK);
251
252 mp_perfdata pd3 = perfdata_init();
253 pd3.label = "floatMe";
254 pd3 = mp_set_pd_value(pd3, 1024.1024);
255 mp_add_perfdata_to_subcheck(&sc3, pd3);
256
257 // level 4
258 mp_subcheck sc4 = mp_subcheck_init();
259 sc4.output = "level4";
260 sc4 = mp_set_subcheck_state(sc4, STATE_OK);
261
262 mp_check check = mp_check_init();
263
264 mp_add_subcheck_to_subcheck(&sc3, sc4);
265 mp_add_subcheck_to_subcheck(&sc2, sc3);
266 mp_add_subcheck_to_subcheck(&sc1, sc2);
267 mp_add_subcheck_to_check(&check, sc1);
268
269 char *output = mp_fmt_output(check);
270
271 // diag("Formatted output of length: %i", strlen(output));
272 // diag(output);
273
274 ok(output != NULL, "Output should not be NULL");
275
276 char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n"
277 "\t\\_[WARNING] - foobar\n"
278 "\t\t\\_[OK] - baz\n"
279 "\t\t\t\\_[OK] - level3\n"
280 "\t\t\t\t\\_[OK] - level4\n"
281 "|foo=23s;;; baz=1024B;;; floatMe=1024.102400;;; \n";
282
283 // diag("Expected output of length: %i", strlen(expected));
284 // diag(expected);
285
286 ok(strcmp(output, expected) == 0, "Output is as expected");
287}
288
289void test_default_states1(void) {
290 mp_subcheck sc = mp_subcheck_init();
291
292 mp_state_enum state1 = mp_compute_subcheck_state(sc);
293 ok(state1 == STATE_UNKNOWN, "Default default state is Unknown");
294
295 sc = mp_set_subcheck_default_state(sc, STATE_CRITICAL);
296
297 mp_state_enum state2 = mp_compute_subcheck_state(sc);
298 ok(state2 == STATE_CRITICAL, "Default state is Critical");
299
300 sc = mp_set_subcheck_state(sc, STATE_OK);
301
302 mp_state_enum state3 = mp_compute_subcheck_state(sc);
303 ok(state3 == STATE_OK, "Default state is Critical");
304}
305
306void test_default_states2(void) {
307 mp_check check = mp_check_init();
308
309 mp_subcheck sc = mp_subcheck_init();
310 sc.output = "placeholder";
311 sc = mp_set_subcheck_default_state(sc, STATE_CRITICAL);
312
313 mp_add_subcheck_to_check(&check, sc);
314
315 mp_state_enum result_state = mp_compute_check_state(check);
316 ok(result_state == STATE_CRITICAL, "Derived state is the proper default state");
317}
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..de983764 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,109 @@ 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';
47 }
48 48
49 return optstr; 49 return optstr;
50} 50}
51 51
52int 52int main(int argc, char **argv) {
53main (int argc, char **argv)
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 char *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"),
58 "config-tiny.ini's section as expected");
61 my_free(optstr); 59 my_free(optstr);
62 60
63 optstr=list2str(np_get_defaults("@./config-tiny.ini", "section")); 61 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"); 62 ok(!strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank"),
63 "Used default section name, without specific");
65 my_free(optstr); 64 my_free(optstr);
66 65
67 optstr=list2str(np_get_defaults("Section Two@./config-tiny.ini", "check_disk")); 66 optstr = list2str(np_get_defaults("Section Two@./config-tiny.ini", "check_disk"));
68 ok( !strcmp(optstr, "--something else=blah --remove=whitespace"), "config-tiny.ini's Section Two as expected"); 67 ok(!strcmp(optstr, "--something else=blah --remove=whitespace"),
68 "config-tiny.ini's Section Two as expected");
69 my_free(optstr); 69 my_free(optstr);
70 70
71 optstr=list2str(np_get_defaults("/path/to/file.txt@./config-tiny.ini", "check_disk")); 71 optstr = list2str(np_get_defaults("/path/to/file.txt@./config-tiny.ini", "check_disk"));
72 ok( !strcmp(optstr, "--this=that"), "config-tiny.ini's filename as section name"); 72 ok(!strcmp(optstr, "--this=that"), "config-tiny.ini's filename as section name");
73 my_free(optstr); 73 my_free(optstr);
74 74
75 optstr=list2str(np_get_defaults("section2@./config-tiny.ini", "check_disk")); 75 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"); 76 ok(!strcmp(optstr, "--this=that"),
77 "config-tiny.ini's section2 with whitespace before section name");
77 my_free(optstr); 78 my_free(optstr);
78 79
79 optstr=list2str(np_get_defaults("section3@./config-tiny.ini", "check_disk")); 80 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"); 81 ok(!strcmp(optstr, "--this=that"),
82 "config-tiny.ini's section3 with whitespace after section name");
81 my_free(optstr); 83 my_free(optstr);
82 84
83 optstr=list2str(np_get_defaults("check_mysql@./plugin.ini", "check_disk")); 85 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"); 86 ok(!strcmp(optstr, "--username=operator --password=secret"),
87 "plugin.ini's check_mysql as expected");
85 my_free(optstr); 88 my_free(optstr);
86 89
87 optstr=list2str(np_get_defaults("check_mysql2@./plugin.ini", "check_disk")); 90 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"); 91 ok(!strcmp(optstr, "-u=admin -p=secret"), "plugin.ini's check_mysql2 as expected");
89 my_free(optstr); 92 my_free(optstr);
90 93
91 optstr=list2str(np_get_defaults("check space_and_flags@./plugin.ini", "check_disk")); 94 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"); 95 ok(!strcmp(optstr, "--foo=bar -a -b --bar"), "plugin.ini space in stanza and flag arguments");
93 my_free(optstr); 96 my_free(optstr);
94 97
95 optstr=list2str(np_get_defaults("Section Two@./config-dos.ini", "check_disk")); 98 optstr = list2str(np_get_defaults("Section Two@./config-dos.ini", "check_disk"));
96 ok( !strcmp(optstr, "--something else=blah --remove=whitespace"), "config-dos.ini's Section Two as expected"); 99 ok(!strcmp(optstr, "--something else=blah --remove=whitespace"),
100 "config-dos.ini's Section Two as expected");
97 my_free(optstr); 101 my_free(optstr);
98 102
99 optstr=list2str(np_get_defaults("section_twice@./plugin.ini", "check_disk")); 103 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"); 104 ok(!strcmp(optstr, "--foo=bar --bar=foo"),
105 "plugin.ini's section_twice defined twice in the file");
101 my_free(optstr); 106 my_free(optstr);
102 107
103 optstr=list2str(np_get_defaults("tcp_long_lines@plugins.ini", "check_tcp")); 108 optstr = list2str(np_get_defaults("tcp_long_lines@plugins.ini", "check_tcp"));
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"); 109 ok(!strcmp(optstr, "--escape --send=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
110 "yadda Foo bar BAZ yadda yadda yadda Foo bar "
111 "BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
112 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar "
113 "BAZ yadda yadda yadda Foo bar BAZ yadda "
114 "yadda yadda Foo bar BAZ yadda yadda yadda Foo "
115 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
116 "yadda yadda Foo bar BAZ yadda yadda "
117 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
118 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
119 "yadda --expect=Foo bar BAZ yadda yadda "
120 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
121 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
122 "yadda Foo bar BAZ yadda yadda yadda Foo "
123 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
124 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar "
125 "BAZ yadda yadda yadda Foo bar BAZ yadda "
126 "yadda yadda Foo bar BAZ yadda yadda yadda Foo "
127 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
128 "yadda yadda Foo bar BAZ yadda yadda "
129 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
130 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
131 "yadda Foo bar BAZ yadda yadda yadda Foo "
132 "bar BAZ yadda yadda yadda --jail"),
133 "Long options");
105 my_free(optstr); 134 my_free(optstr);
106 135
107 return exit_status(); 136 return exit_status();
108} 137}
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..fa95c4d4 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,36 +40,41 @@ void my_free(int *argc, char **newargv, char **argv) {
40#else 40#else
41void my_free(int *argc, char **newargv, char **argv) { 41void my_free(int *argc, char **newargv, char **argv) {
42 /* Free stuff (and print while we're at it) */ 42 /* Free stuff (and print while we're at it) */
43 int i, freeflag=1; 43 bool freeflag = true;
44 printf (" Arg(%i): ", *argc+1); 44 printf(" Arg(%i): ", *argc + 1);
45 printf ("'%s' ", newargv[0]); 45 printf("'%s' ", newargv[0]);
46 for (i=1; i<*argc; i++) { 46
47 printf ("'%s' ", newargv[i]); 47 for (int i = 1; i < *argc; i++) {
48 printf("'%s' ", newargv[i]);
48 /* Stop freeing when we get to the start of the original array */ 49 /* Stop freeing when we get to the start of the original array */
49 if (freeflag) { 50 if (freeflag) {
50 if (newargv[i] == argv[1]) 51 if (newargv[i] == argv[1]) {
51 freeflag=0; 52 freeflag = false;
52 else 53 } else {
53 free(newargv[i]); 54 free(newargv[i]);
55 }
54 } 56 }
55 } 57 }
56 printf ("\n"); 58 printf("\n");
57 /* Free only if it's a different array */ 59 /* Free only if it's a different array */
58 if (newargv != argv) free(newargv); 60 if (newargv != argv) {
59 *argc=0; 61 free(newargv);
62 }
63 *argc = 0;
60} 64}
61#endif 65#endif
62 66
63int array_diff(int i1, char **a1, int i2, char **a2) { 67int array_diff(int i1, char **a1, int i2, char **a2) {
64 int i;
65
66 if (i1 != i2) { 68 if (i1 != i2) {
67 printf(" Argument count doesn't match!\n"); 69 printf(" Argument count doesn't match!\n");
68 return 0; 70 return 0;
69 } 71 }
70 for (i=0; i<=i1; i++) { 72
71 if (a1[i]==NULL && a2[i]==NULL) continue; 73 for (int i = 0; i <= i1; i++) {
72 if (a1[i]==NULL || a2[i]==NULL) { 74 if (a1[i] == NULL && a2[i] == NULL) {
75 continue;
76 }
77 if (a1[i] == NULL || a2[i] == NULL) {
73 printf(" Argument # %i null in one array!\n", i); 78 printf(" Argument # %i null in one array!\n", i);
74 return 0; 79 return 0;
75 } 80 }
@@ -81,59 +86,66 @@ int array_diff(int i1, char **a1, int i2, char **a2) {
81 return 1; 86 return 1;
82} 87}
83 88
84int 89int main(int argc, char **argv) {
85main (int argc, char **argv)
86{
87 char **argv_new=NULL;
88 int i, argc_test;
89
90 plan_tests(5); 90 plan_tests(5);
91 91
92 char **argv_new = NULL;
93 int argc_test;
92 { 94 {
93 char *argv_test[] = {"prog_name", (char *) NULL}; 95 char *argv_test[] = {"prog_name", (char *)NULL};
94 argc_test=1; 96 argc_test = 1;
95 char *argv_known[] = {"prog_name", (char *) NULL}; 97 char *argv_known[] = {"prog_name", (char *)NULL};
96 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 98 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"); 99 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); 100 my_free(&argc_test, argv_new, argv_test);
99 } 101 }
100 102
101 { 103 {
102 char *argv_test[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *) NULL}; 104 char *argv_test[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *)NULL};
103 argc_test=5; 105 argc_test = 5;
104 char *argv_known[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *) NULL}; 106 char *argv_known[] = {"prog_name", "arg1", "--arg2=val1", "--arg3", "val2", (char *)NULL};
105 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 107 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"); 108 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); 109 my_free(&argc_test, argv_new, argv_test);
108 } 110 }
109 111
110 { 112 {
111 char *argv_test[] = {"prog_name", "--extra-opts=@./config-opts.ini", (char *) NULL}; 113 char *argv_test[] = {"prog_name", "--extra-opts=@./config-opts.ini", (char *)NULL};
112 argc_test=2; 114 argc_test = 2;
113 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank", (char *) NULL}; 115 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank",
114 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 116 (char *)NULL};
117 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
115 ok(array_diff(argc_test, argv_new, 4, argv_known), "Only extra opts using default section"); 118 ok(array_diff(argc_test, argv_new, 4, argv_known), "Only extra opts using default section");
116 my_free(&argc_test, argv_new, argv_test); 119 my_free(&argc_test, argv_new, argv_test);
117 } 120 }
118 121
119 { 122 {
120 char *argv_test[] = {"prog_name", "--extra-opts=sect1@./config-opts.ini", "--extra-opts", "sect2@./config-opts.ini", (char *) NULL}; 123 char *argv_test[] = {"prog_name", "--extra-opts=sect1@./config-opts.ini", "--extra-opts",
121 argc_test=4; 124 "sect2@./config-opts.ini", (char *)NULL};
122 char *argv_known[] = {"prog_name", "--one=two", "--something else=oops", "--this=that", (char *) NULL}; 125 argc_test = 4;
123 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 126 char *argv_known[] = {"prog_name", "--one=two", "--something else=oops", "--this=that",
127 (char *)NULL};
128 argv_new = np_extra_opts(&argc_test, argv_test, "check_disk");
124 ok(array_diff(argc_test, argv_new, 4, argv_known), "Only extra opts specified twice"); 129 ok(array_diff(argc_test, argv_new, 4, argv_known), "Only extra opts specified twice");
125 my_free(&argc_test, argv_new, argv_test); 130 my_free(&argc_test, argv_new, argv_test);
126 } 131 }
127 132
128 { 133 {
129 char *argv_test[] = {"prog_name", "--arg1=val1", "--extra-opts=@./config-opts.ini", "--extra-opts", "sect1@./config-opts.ini", "--arg2", (char *) NULL}; 134 char *argv_test[] = {"prog_name",
130 argc_test=6; 135 "--arg1=val1",
131 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!", "--blank", "--one=two", "--arg1=val1", "--arg2", (char *) NULL}; 136 "--extra-opts=@./config-opts.ini",
132 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 137 "--extra-opts",
138 "sect1@./config-opts.ini",
139 "--arg2",
140 (char *)NULL};
141 argc_test = 6;
142 char *argv_known[] = {"prog_name", "--foo=Bar", "--this=Your Mother!",
143 "--blank", "--one=two", "--arg1=val1",
144 "--arg2", (char *)NULL};
145 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"); 146 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); 147 my_free(&argc_test, argv_new, argv_test);
135 } 148 }
136 149
137 return exit_status(); 150 return exit_status();
138} 151}
139
diff --git a/lib/tests/test_opts2.c b/lib/tests/test_opts2.c
index 780220ee..3dd1b039 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,35 +23,40 @@
23 23
24void my_free(int *argc, char **newargv, char **argv) { 24void my_free(int *argc, char **newargv, char **argv) {
25 /* Free stuff (and print while we're at it) */ 25 /* Free stuff (and print while we're at it) */
26 int i, freeflag=1; 26 bool freeflag = true;
27 printf (" Arg(%i): ", *argc+1); 27
28 printf ("'%s' ", newargv[0]); 28 printf(" Arg(%i): ", *argc + 1);
29 for (i=1; i<*argc; i++) { 29 printf("'%s' ", newargv[0]);
30 printf ("'%s' ", newargv[i]); 30 for (int i = 1; i < *argc; i++) {
31 printf("'%s' ", newargv[i]);
31 /* Stop freeing when we get to the start of the original array */ 32 /* Stop freeing when we get to the start of the original array */
32 if (freeflag) { 33 if (freeflag) {
33 if (newargv[i] == argv[1]) 34 if (newargv[i] == argv[1]) {
34 freeflag=0; 35 freeflag = false;
35 else 36 } else {
36 free(newargv[i]); 37 free(newargv[i]);
38 }
37 } 39 }
38 } 40 }
39 printf ("\n"); 41 printf("\n");
40 /* Free only if it's a different array */ 42 /* Free only if it's a different array */
41 if (newargv != argv) free(newargv); 43 if (newargv != argv) {
42 *argc=0; 44 free(newargv);
45 }
46 *argc = 0;
43} 47}
44 48
45int array_diff(int i1, char **a1, int i2, char **a2) { 49int array_diff(int i1, char **a1, int i2, char **a2) {
46 int i;
47
48 if (i1 != i2) { 50 if (i1 != i2) {
49 printf(" Argument count doesn't match!\n"); 51 printf(" Argument count doesn't match!\n");
50 return 0; 52 return 0;
51 } 53 }
52 for (i=0; i<=i1; i++) { 54
53 if (a1[i]==NULL && a2[i]==NULL) continue; 55 for (int i = 0; i <= i1; i++) {
54 if (a1[i]==NULL || a2[i]==NULL) { 56 if (a1[i] == NULL && a2[i] == NULL) {
57 continue;
58 }
59 if (a1[i] == NULL || a2[i] == NULL) {
55 printf(" Argument # %i null in one array!\n", i); 60 printf(" Argument # %i null in one array!\n", i);
56 return 0; 61 return 0;
57 } 62 }
@@ -63,59 +68,86 @@ int array_diff(int i1, char **a1, int i2, char **a2) {
63 return 1; 68 return 1;
64} 69}
65 70
66int 71int main(int argc, char **argv) {
67main (int argc, char **argv)
68{
69 char **argv_new=NULL;
70 int i, argc_test;
71
72 plan_tests(5); 72 plan_tests(5);
73 73
74 char **argv_new = NULL;
75 int argc_test;
74 { 76 {
75 char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "--arg3", "val2", (char *) NULL}; 77 char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "--arg3", "val2", (char *)NULL};
76 argc_test=5; 78 argc_test = 5;
77 char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "--arg3", "val2", (char *) NULL}; 79 char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "--arg3", "val2", (char *)NULL};
78 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 80 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"); 81 ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 1");
80 my_free(&argc_test, argv_new, argv_test); 82 my_free(&argc_test, argv_new, argv_test);
81 } 83 }
82 84
83 { 85 {
84 char *argv_test[] = {"prog_name", "--extra-opts", (char *) NULL}; 86 char *argv_test[] = {"prog_name", "--extra-opts", (char *)NULL};
85 argc_test=2; 87 argc_test = 2;
86 char *argv_known[] = {"prog_name", "--foo=bar", (char *) NULL}; 88 char *argv_known[] = {"prog_name", "--foo=bar", (char *)NULL};
87 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 89 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"); 90 ok(array_diff(argc_test, argv_new, 2, argv_known), "Default section 2");
89 my_free(&argc_test, argv_new, argv_test); 91 my_free(&argc_test, argv_new, argv_test);
90 } 92 }
91 93
92 { 94 {
93 char *argv_test[] = {"prog_name", "arg1", "--extra-opts=section1", "--arg3", "val2", (char *) NULL}; 95 char *argv_test[] = {"prog_name", "arg1", "--extra-opts=section1",
94 argc_test=5; 96 "--arg3", "val2", (char *)NULL};
95 char *argv_known[] = {"prog_name", "--foobar=baz", "arg1", "--arg3", "val2", (char *) NULL}; 97 argc_test = 5;
96 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 98 char *argv_known[] = {"prog_name", "--foobar=baz", "arg1", "--arg3", "val2", (char *)NULL};
99 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"); 100 ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 3");
98 my_free(&argc_test, argv_new, argv_test); 101 my_free(&argc_test, argv_new, argv_test);
99 } 102 }
100 103
101 { 104 {
102 char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "-arg3", "val2", (char *) NULL}; 105 char *argv_test[] = {"prog_name", "arg1", "--extra-opts", "-arg3", "val2", (char *)NULL};
103 argc_test=5; 106 argc_test = 5;
104 char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "-arg3", "val2", (char *) NULL}; 107 char *argv_known[] = {"prog_name", "--foo=bar", "arg1", "-arg3", "val2", (char *)NULL};
105 argv_new=np_extra_opts(&argc_test, argv_test, "check_disk"); 108 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"); 109 ok(array_diff(argc_test, argv_new, 5, argv_known), "Default section 4");
107 my_free(&argc_test, argv_new, argv_test); 110 my_free(&argc_test, argv_new, argv_test);
108 } 111 }
109 112
110 { 113 {
111 char *argv_test[] = {"check_tcp", "--extra-opts", "--extra-opts=tcp_long_lines", (char *) NULL}; 114 char *argv_test[] = {"check_tcp", "--extra-opts", "--extra-opts=tcp_long_lines",
112 argc_test=3; 115 (char *)NULL};
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}; 116 argc_test = 3;
114 argv_new=np_extra_opts(&argc_test, argv_test, "check_tcp"); 117 char *argv_known[] = {"check_tcp",
118 "--timeout=10",
119 "--escape",
120 "--send=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda "
121 "Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
122 "yadda Foo bar BAZ yadda "
123 "yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
124 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
125 "yadda Foo bar BAZ "
126 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
127 "yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
128 "yadda yadda Foo bar "
129 "BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
130 "yadda yadda yadda Foo bar BAZ yadda yadda yadda",
131 "--expect=Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
132 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
133 "yadda Foo bar BAZ yadda "
134 "yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
135 "yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda "
136 "yadda Foo bar BAZ "
137 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
138 "yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ yadda "
139 "yadda yadda Foo bar "
140 "BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
141 "yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
142 "yadda yadda yadda Foo "
143 "bar BAZ yadda yadda yadda Foo bar BAZ yadda yadda yadda Foo bar BAZ "
144 "yadda yadda yadda Foo bar BAZ yadda yadda yadda",
145 "--jail",
146 (char *)NULL};
147 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"); 148 ok(array_diff(argc_test, argv_new, 6, argv_known), "Long lines test");
116 my_free(&argc_test, argv_new, argv_test); 149 my_free(&argc_test, argv_new, argv_test);
117 } 150 }
118 151
119 return exit_status(); 152 return exit_status();
120} 153}
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..37c818c9 100644
--- a/lib/tests/test_tcp.c
+++ b/lib/tests/test_tcp.c
@@ -1,58 +1,60 @@
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;
27 int server_expect_count = 3;
28
29 plan_tests(9); 24 plan_tests(9);
30 25
31 server_expect = malloc(sizeof(char*) * server_expect_count); 26 char **server_expect;
27 const int server_expect_count = 3;
28 server_expect = malloc(sizeof(char *) * server_expect_count);
32 29
33 server_expect[0] = strdup("AA"); 30 server_expect[0] = strdup("AA");
34 server_expect[1] = strdup("bb"); 31 server_expect[1] = strdup("bb");
35 server_expect[2] = strdup("CC"); 32 server_expect[2] = strdup("CC");
36 33
37 ok(np_expect_match("AA bb CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_SUCCESS, 34 ok(np_expect_match("AA bb CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) ==
35 NP_MATCH_SUCCESS,
38 "Test matching any string at the beginning (first expect string)"); 36 "Test matching any string at the beginning (first expect string)");
39 ok(np_expect_match("bb AA CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_SUCCESS, 37 ok(np_expect_match("bb AA CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) ==
38 NP_MATCH_SUCCESS,
40 "Test matching any string at the beginning (second expect string)"); 39 "Test matching any string at the beginning (second expect string)");
41 ok(np_expect_match("b", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_RETRY, 40 ok(np_expect_match("b", server_expect, server_expect_count, NP_MATCH_EXACT) == NP_MATCH_RETRY,
42 "Test matching any string at the beginning (substring match)"); 41 "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, 42 ok(np_expect_match("XX bb AA CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) ==
43 NP_MATCH_FAILURE,
44 "Test with strings not matching at the beginning"); 44 "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, 45 ok(np_expect_match("XX CC XX", server_expect, server_expect_count, NP_MATCH_EXACT) ==
46 NP_MATCH_FAILURE,
46 "Test matching any string"); 47 "Test matching any string");
47 ok(np_expect_match("XX", server_expect, server_expect_count, 0) == NP_MATCH_RETRY, 48 ok(np_expect_match("XX", server_expect, server_expect_count, 0) == NP_MATCH_RETRY,
48 "Test not matching any string"); 49 "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, 50 ok(np_expect_match("XX AA bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) ==
51 NP_MATCH_SUCCESS,
50 "Test matching all strings"); 52 "Test matching all strings");
51 ok(np_expect_match("XX bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_RETRY, 53 ok(np_expect_match("XX bb CC XX", server_expect, server_expect_count, NP_MATCH_ALL) ==
54 NP_MATCH_RETRY,
52 "Test not matching all strings"); 55 "Test not matching all strings");
53 ok(np_expect_match("XX XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_RETRY, 56 ok(np_expect_match("XX XX", server_expect, server_expect_count, NP_MATCH_ALL) == NP_MATCH_RETRY,
54 "Test not matching any string (testing all)"); 57 "Test not matching any string (testing all)");
55 58
56
57 return exit_status(); 59 return exit_status();
58} 60}
diff --git a/lib/tests/test_utils.c b/lib/tests/test_utils.c
index 01afacdc..8040dec8 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,484 +27,315 @@
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) 31 plan_tests(155);
32{
33 char state_path[1024];
34 range *range;
35 double temp;
36 thresholds *thresholds = NULL;
37 int i, rc;
38 char *temp_string;
39 state_key *temp_state_key = NULL;
40 state_data *temp_state_data;
41 time_t current_time;
42
43 plan_tests(185);
44 32
45 ok( this_monitoring_plugin==NULL, "monitoring_plugin not initialised"); 33 ok(this_monitoring_plugin == NULL, "monitoring_plugin not initialised");
46 34
47 np_init( "check_test", argc, argv ); 35 np_init("check_test", argc, argv);
48 36
49 ok( this_monitoring_plugin!=NULL, "monitoring_plugin now initialised"); 37 ok(this_monitoring_plugin != NULL, "monitoring_plugin now initialised");
50 ok( !strcmp(this_monitoring_plugin->plugin_name, "check_test"), "plugin name initialised" ); 38 ok(!strcmp(this_monitoring_plugin->plugin_name, "check_test"), "plugin name initialised");
51 39
52 ok( this_monitoring_plugin->argc==argc, "Argc set" ); 40 ok(this_monitoring_plugin->argc == argc, "Argc set");
53 ok( this_monitoring_plugin->argv==argv, "Argv set" ); 41 ok(this_monitoring_plugin->argv == argv, "Argv set");
54 42
55 np_set_args(0,0); 43 np_set_args(0, 0);
56 44
57 ok( this_monitoring_plugin->argc==0, "argc changed" ); 45 ok(this_monitoring_plugin->argc == 0, "argc changed");
58 ok( this_monitoring_plugin->argv==0, "argv changed" ); 46 ok(this_monitoring_plugin->argv == 0, "argv changed");
59 47
60 np_set_args(argc, argv); 48 np_set_args(argc, argv);
61 49
62 range = parse_range_string("6"); 50 range *range = parse_range_string("6");
63 ok( range != NULL, "'6' is valid range"); 51 ok(range != NULL, "'6' is valid range");
64 ok( range->start == 0, "Start correct"); 52 ok(range->start == 0, "Start correct");
65 ok( range->start_infinity == false, "Not using negative infinity"); 53 ok(range->start_infinity == false, "Not using negative infinity");
66 ok( range->end == 6, "End correct"); 54 ok(range->end == 6, "End correct");
67 ok( range->end_infinity == false, "Not using infinity"); 55 ok(range->end_infinity == false, "Not using infinity");
68 free(range); 56 free(range);
69 57
70 range = parse_range_string("1:12%%"); 58 range = parse_range_string("1:12%%");
71 ok( range != NULL, "'1:12%%' is valid - percentages are ignored"); 59 ok(range != NULL, "'1:12%%' is valid - percentages are ignored");
72 ok( range->start == 1, "Start correct"); 60 ok(range->start == 1, "Start correct");
73 ok( range->start_infinity == false, "Not using negative infinity"); 61 ok(range->start_infinity == false, "Not using negative infinity");
74 ok( range->end == 12, "End correct"); 62 ok(range->end == 12, "End correct");
75 ok( range->end_infinity == false, "Not using infinity"); 63 ok(range->end_infinity == false, "Not using infinity");
76 free(range); 64 free(range);
77 65
78 range = parse_range_string("-7:23"); 66 range = parse_range_string("-7:23");
79 ok( range != NULL, "'-7:23' is valid range"); 67 ok(range != NULL, "'-7:23' is valid range");
80 ok( range->start == -7, "Start correct"); 68 ok(range->start == -7, "Start correct");
81 ok( range->start_infinity == false, "Not using negative infinity"); 69 ok(range->start_infinity == false, "Not using negative infinity");
82 ok( range->end == 23, "End correct"); 70 ok(range->end == 23, "End correct");
83 ok( range->end_infinity == false, "Not using infinity"); 71 ok(range->end_infinity == false, "Not using infinity");
84 free(range); 72 free(range);
85 73
86 range = parse_range_string(":5.75"); 74 range = parse_range_string(":5.75");
87 ok( range != NULL, "':5.75' is valid range"); 75 ok(range != NULL, "':5.75' is valid range");
88 ok( range->start == 0, "Start correct"); 76 ok(range->start == 0, "Start correct");
89 ok( range->start_infinity == false, "Not using negative infinity"); 77 ok(range->start_infinity == false, "Not using negative infinity");
90 ok( range->end == 5.75, "End correct"); 78 ok(range->end == 5.75, "End correct");
91 ok( range->end_infinity == false, "Not using infinity"); 79 ok(range->end_infinity == false, "Not using infinity");
92 free(range); 80 free(range);
93 81
94 range = parse_range_string("~:-95.99"); 82 range = parse_range_string("~:-95.99");
95 ok( range != NULL, "~:-95.99' is valid range"); 83 ok(range != NULL, "~:-95.99' is valid range");
96 ok( range->start_infinity == true, "Using negative infinity"); 84 ok(range->start_infinity == true, "Using negative infinity");
97 ok( range->end == -95.99, "End correct (with rounding errors)"); 85 ok(range->end == -95.99, "End correct (with rounding errors)");
98 ok( range->end_infinity == false, "Not using infinity"); 86 ok(range->end_infinity == false, "Not using infinity");
99 free(range); 87 free(range);
100 88
101 range = parse_range_string("12345678901234567890:"); 89 range = parse_range_string("12345678901234567890:");
102 temp = atof("12345678901234567890"); /* Can't just use this because number too large */ 90 double temp = atof("12345678901234567890"); /* Can't just use this because number too large */
103 ok( range != NULL, "'12345678901234567890:' is valid range"); 91 ok(range != NULL, "'12345678901234567890:' is valid range");
104 ok( range->start == temp, "Start correct"); 92 ok(range->start == temp, "Start correct");
105 ok( range->start_infinity == false, "Not using negative infinity"); 93 ok(range->start_infinity == false, "Not using negative infinity");
106 ok( range->end_infinity == true, "Using infinity"); 94 ok(range->end_infinity == true, "Using infinity");
107 /* Cannot do a "-1" on temp, as it appears to be same value */ 95 /* 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"); 96 ok(check_range(temp / 1.1, range) == true, "12345678901234567890/1.1 - alert");
109 ok( check_range(temp, range) == false, "12345678901234567890 - no alert"); 97 ok(check_range(temp, range) == false, "12345678901234567890 - no alert");
110 ok( check_range(temp*2, range) == false, "12345678901234567890*2 - no alert"); 98 ok(check_range(temp * 2, range) == false, "12345678901234567890*2 - no alert");
111 free(range); 99 free(range);
112 100
113 range = parse_range_string("~:0"); 101 range = parse_range_string("~:0");
114 ok( range != NULL, "'~:0' is valid range"); 102 ok(range != NULL, "'~:0' is valid range");
115 ok( range->start_infinity == true, "Using negative infinity"); 103 ok(range->start_infinity == true, "Using negative infinity");
116 ok( range->end == 0, "End correct"); 104 ok(range->end == 0, "End correct");
117 ok( range->end_infinity == false, "Not using infinity"); 105 ok(range->end_infinity == false, "Not using infinity");
118 ok( range->alert_on == OUTSIDE, "Will alert on outside of this range"); 106 ok(range->alert_on == OUTSIDE, "Will alert on outside of this range");
119 ok( check_range(0.5, range) == true, "0.5 - alert"); 107 ok(check_range(0.5, range) == true, "0.5 - alert");
120 ok( check_range(-10, range) == false, "-10 - no alert"); 108 ok(check_range(-10, range) == false, "-10 - no alert");
121 ok( check_range(0, range) == false, "0 - no alert"); 109 ok(check_range(0, range) == false, "0 - no alert");
122 free(range); 110 free(range);
123 111
124 range = parse_range_string("@0:657.8210567"); 112 range = parse_range_string("@0:657.8210567");
125 ok( range != 0, "@0:657.8210567' is a valid range"); 113 ok(range != 0, "@0:657.8210567' is a valid range");
126 ok( range->start == 0, "Start correct"); 114 ok(range->start == 0, "Start correct");
127 ok( range->start_infinity == false, "Not using negative infinity"); 115 ok(range->start_infinity == false, "Not using negative infinity");
128 ok( range->end == 657.8210567, "End correct"); 116 ok(range->end == 657.8210567, "End correct");
129 ok( range->end_infinity == false, "Not using infinity"); 117 ok(range->end_infinity == false, "Not using infinity");
130 ok( range->alert_on == INSIDE, "Will alert on inside of this range" ); 118 ok(range->alert_on == INSIDE, "Will alert on inside of this range");
131 ok( check_range(32.88, range) == true, "32.88 - alert"); 119 ok(check_range(32.88, range) == true, "32.88 - alert");
132 ok( check_range(-2, range) == false, "-2 - no alert"); 120 ok(check_range(-2, range) == false, "-2 - no alert");
133 ok( check_range(657.8210567, range) == true, "657.8210567 - alert"); 121 ok(check_range(657.8210567, range) == true, "657.8210567 - alert");
134 ok( check_range(0, range) == true, "0 - alert"); 122 ok(check_range(0, range) == true, "0 - alert");
135 free(range); 123 free(range);
136 124
137 range = parse_range_string("@1:1"); 125 range = parse_range_string("@1:1");
138 ok( range != NULL, "'@1:1' is a valid range"); 126 ok(range != NULL, "'@1:1' is a valid range");
139 ok( range->start == 1, "Start correct"); 127 ok(range->start == 1, "Start correct");
140 ok( range->start_infinity == false, "Not using negative infinity"); 128 ok(range->start_infinity == false, "Not using negative infinity");
141 ok( range->end == 1, "End correct"); 129 ok(range->end == 1, "End correct");
142 ok( range->end_infinity == false, "Not using infinity"); 130 ok(range->end_infinity == false, "Not using infinity");
143 ok( range->alert_on == INSIDE, "Will alert on inside of this range" ); 131 ok(range->alert_on == INSIDE, "Will alert on inside of this range");
144 ok( check_range(0.5, range) == false, "0.5 - no alert"); 132 ok(check_range(0.5, range) == false, "0.5 - no alert");
145 ok( check_range(1, range) == true, "1 - alert"); 133 ok(check_range(1, range) == true, "1 - alert");
146 ok( check_range(5.2, range) == false, "5.2 - no alert"); 134 ok(check_range(5.2, range) == false, "5.2 - no alert");
147 free(range); 135 free(range);
148 136
149 range = parse_range_string("1:1"); 137 range = parse_range_string("1:1");
150 ok( range != NULL, "'1:1' is a valid range"); 138 ok(range != NULL, "'1:1' is a valid range");
151 ok( range->start == 1, "Start correct"); 139 ok(range->start == 1, "Start correct");
152 ok( range->start_infinity == false, "Not using negative infinity"); 140 ok(range->start_infinity == false, "Not using negative infinity");
153 ok( range->end == 1, "End correct"); 141 ok(range->end == 1, "End correct");
154 ok( range->end_infinity == false, "Not using infinity"); 142 ok(range->end_infinity == false, "Not using infinity");
155 ok( check_range(0.5, range) == true, "0.5 - alert"); 143 ok(check_range(0.5, range) == true, "0.5 - alert");
156 ok( check_range(1, range) == false, "1 - no alert"); 144 ok(check_range(1, range) == false, "1 - no alert");
157 ok( check_range(5.2, range) == true, "5.2 - alert"); 145 ok(check_range(5.2, range) == true, "5.2 - alert");
158 free(range); 146 free(range);
159 147
160 range = parse_range_string("2:1"); 148 range = parse_range_string("2:1");
161 ok( range == NULL, "'2:1' rejected"); 149 ok(range == NULL, "'2:1' rejected");
162 150
163 rc = _set_thresholds(&thresholds, NULL, NULL); 151 thresholds *thresholds = NULL;
164 ok( rc == 0, "Thresholds (NULL, NULL) set"); 152 int returnCode;
165 ok( thresholds->warning == NULL, "Warning not set"); 153 returnCode = _set_thresholds(&thresholds, NULL, NULL);
166 ok( thresholds->critical == NULL, "Critical not set"); 154 ok(returnCode == 0, "Thresholds (NULL, NULL) set");
167 155 ok(thresholds->warning == NULL, "Warning not set");
168 rc = _set_thresholds(&thresholds, NULL, "80"); 156 ok(thresholds->critical == NULL, "Critical not set");
169 ok( rc == 0, "Thresholds (NULL, '80') set"); 157
170 ok( thresholds->warning == NULL, "Warning not set"); 158 returnCode = _set_thresholds(&thresholds, NULL, "80");
171 ok( thresholds->critical->end == 80, "Critical set correctly"); 159 ok(returnCode == 0, "Thresholds (NULL, '80') set");
172 160 ok(thresholds->warning == NULL, "Warning not set");
173 rc = _set_thresholds(&thresholds, "5:33", NULL); 161 ok(thresholds->critical->end == 80, "Critical set correctly");
174 ok( rc == 0, "Thresholds ('5:33', NULL) set"); 162
175 ok( thresholds->warning->start == 5, "Warning start set"); 163 returnCode = _set_thresholds(&thresholds, "5:33", NULL);
176 ok( thresholds->warning->end == 33, "Warning end set"); 164 ok(returnCode == 0, "Thresholds ('5:33', NULL) set");
177 ok( thresholds->critical == NULL, "Critical not set"); 165 ok(thresholds->warning->start == 5, "Warning start set");
178 166 ok(thresholds->warning->end == 33, "Warning end set");
179 rc = _set_thresholds(&thresholds, "30", "60"); 167 ok(thresholds->critical == NULL, "Critical not set");
180 ok( rc == 0, "Thresholds ('30', '60') set"); 168
181 ok( thresholds->warning->end == 30, "Warning set correctly"); 169 returnCode = _set_thresholds(&thresholds, "30", "60");
182 ok( thresholds->critical->end == 60, "Critical set correctly"); 170 ok(returnCode == 0, "Thresholds ('30', '60') set");
183 ok( get_status(15.3, thresholds) == STATE_OK, "15.3 - ok"); 171 ok(thresholds->warning->end == 30, "Warning set correctly");
184 ok( get_status(30.0001, thresholds) == STATE_WARNING, "30.0001 - warning"); 172 ok(thresholds->critical->end == 60, "Critical set correctly");
185 ok( get_status(69, thresholds) == STATE_CRITICAL, "69 - critical"); 173 ok(get_status(15.3, thresholds) == STATE_OK, "15.3 - ok");
186 174 ok(get_status(30.0001, thresholds) == STATE_WARNING, "30.0001 - warning");
187 rc = _set_thresholds(&thresholds, "-10:-2", "-30:20"); 175 ok(get_status(69, thresholds) == STATE_CRITICAL, "69 - critical");
188 ok( rc == 0, "Thresholds ('-30:20', '-10:-2') set"); 176
189 ok( thresholds->warning->start == -10, "Warning start set correctly"); 177 returnCode = _set_thresholds(&thresholds, "-10:-2", "-30:20");
190 ok( thresholds->warning->end == -2, "Warning end set correctly"); 178 ok(returnCode == 0, "Thresholds ('-30:20', '-10:-2') set");
191 ok( thresholds->critical->start == -30, "Critical start set correctly"); 179 ok(thresholds->warning->start == -10, "Warning start set correctly");
192 ok( thresholds->critical->end == 20, "Critical end set correctly"); 180 ok(thresholds->warning->end == -2, "Warning end set correctly");
193 ok( get_status(-31, thresholds) == STATE_CRITICAL, "-31 - critical"); 181 ok(thresholds->critical->start == -30, "Critical start set correctly");
194 ok( get_status(-29, thresholds) == STATE_WARNING, "-29 - warning"); 182 ok(thresholds->critical->end == 20, "Critical end set correctly");
195 ok( get_status(-11, thresholds) == STATE_WARNING, "-11 - warning"); 183 ok(get_status(-31, thresholds) == STATE_CRITICAL, "-31 - critical");
196 ok( get_status(-10, thresholds) == STATE_OK, "-10 - ok"); 184 ok(get_status(-29, thresholds) == STATE_WARNING, "-29 - warning");
197 ok( get_status(-2, thresholds) == STATE_OK, "-2 - ok"); 185 ok(get_status(-11, thresholds) == STATE_WARNING, "-11 - warning");
198 ok( get_status(-1, thresholds) == STATE_WARNING, "-1 - warning"); 186 ok(get_status(-10, thresholds) == STATE_OK, "-10 - ok");
199 ok( get_status(19, thresholds) == STATE_WARNING, "19 - warning"); 187 ok(get_status(-2, thresholds) == STATE_OK, "-2 - ok");
200 ok( get_status(21, thresholds) == STATE_CRITICAL, "21 - critical"); 188 ok(get_status(-1, thresholds) == STATE_WARNING, "-1 - warning");
189 ok(get_status(19, thresholds) == STATE_WARNING, "19 - warning");
190 ok(get_status(21, thresholds) == STATE_CRITICAL, "21 - critical");
201 191
202 char *test; 192 char *test;
203 test = np_escaped_string("bob\\n"); 193 test = np_escaped_string("bob\\n");
204 ok( strcmp(test, "bob\n") == 0, "bob\\n ok"); 194 ok(strcmp(test, "bob\n") == 0, "bob\\n ok");
205 free(test); 195 free(test);
206 196
207 test = np_escaped_string("rhuba\\rb"); 197 test = np_escaped_string("rhuba\\rb");
208 ok( strcmp(test, "rhuba\rb") == 0, "rhuba\\rb okay"); 198 ok(strcmp(test, "rhuba\rb") == 0, "rhuba\\rb okay");
209 free(test); 199 free(test);
210 200
211 test = np_escaped_string("ba\\nge\\r"); 201 test = np_escaped_string("ba\\nge\\r");
212 ok( strcmp(test, "ba\nge\r") == 0, "ba\\nge\\r okay"); 202 ok(strcmp(test, "ba\nge\r") == 0, "ba\\nge\\r okay");
213 free(test); 203 free(test);
214 204
215 test = np_escaped_string("\\rabbi\\t"); 205 test = np_escaped_string("\\rabbi\\t");
216 ok( strcmp(test, "\rabbi\t") == 0, "\\rabbi\\t okay"); 206 ok(strcmp(test, "\rabbi\t") == 0, "\\rabbi\\t okay");
217 free(test); 207 free(test);
218 208
219 test = np_escaped_string("and\\\\or"); 209 test = np_escaped_string("and\\\\or");
220 ok( strcmp(test, "and\\or") == 0, "and\\\\or okay"); 210 ok(strcmp(test, "and\\or") == 0, "and\\\\or okay");
221 free(test); 211 free(test);
222 212
223 test = np_escaped_string("bo\\gus"); 213 test = np_escaped_string("bo\\gus");
224 ok( strcmp(test, "bogus") == 0, "bo\\gus okay"); 214 ok(strcmp(test, "bogus") == 0, "bo\\gus okay");
225 free(test); 215 free(test);
226 216
227 test = np_escaped_string("everything"); 217 test = np_escaped_string("everything");
228 ok( strcmp(test, "everything") == 0, "everything okay"); 218 ok(strcmp(test, "everything") == 0, "everything okay");
229 219
230 /* np_extract_ntpvar tests (23) */ 220 /* np_extract_ntpvar tests (23) */
231 test=np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foo"); 221 test = np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foo");
232 ok(test && !strcmp(test, "bar"), "1st test as expected"); 222 ok(test && !strcmp(test, "bar"), "1st test as expected");
233 free(test); 223 free(test);
234 224
235 test=np_extract_ntpvar("foo=bar,bar=foo,foobar=barfoo\n", "bar"); 225 test = np_extract_ntpvar("foo=bar,bar=foo,foobar=barfoo\n", "bar");
236 ok(test && !strcmp(test, "foo"), "2nd test as expected"); 226 ok(test && !strcmp(test, "foo"), "2nd test as expected");
237 free(test); 227 free(test);
238 228
239 test=np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foobar"); 229 test = np_extract_ntpvar("foo=bar, bar=foo, foobar=barfoo\n", "foobar");
240 ok(test && !strcmp(test, "barfoo"), "3rd test as expected"); 230 ok(test && !strcmp(test, "barfoo"), "3rd test as expected");
241 free(test); 231 free(test);
242 232
243 test=np_extract_ntpvar("foo=bar\n", "foo"); 233 test = np_extract_ntpvar("foo=bar\n", "foo");
244 ok(test && !strcmp(test, "bar"), "Single test as expected"); 234 ok(test && !strcmp(test, "bar"), "Single test as expected");
245 free(test); 235 free(test);
246 236
247 test=np_extract_ntpvar("foo=bar, bar=foo, foobar=barfooi\n", "abcd"); 237 test = np_extract_ntpvar("foo=bar, bar=foo, foobar=barfooi\n", "abcd");
248 ok(!test, "Key not found 1"); 238 ok(!test, "Key not found 1");
249 239
250 test=np_extract_ntpvar("foo=bar\n", "abcd"); 240 test = np_extract_ntpvar("foo=bar\n", "abcd");
251 ok(!test, "Key not found 2"); 241 ok(!test, "Key not found 2");
252 242
253 test=np_extract_ntpvar("foo=bar=foobar", "foo"); 243 test = np_extract_ntpvar("foo=bar=foobar", "foo");
254 ok(test && !strcmp(test, "bar=foobar"), "Strange string 1"); 244 ok(test && !strcmp(test, "bar=foobar"), "Strange string 1");
255 free(test); 245 free(test);
256 246
257 test=np_extract_ntpvar("foo", "foo"); 247 test = np_extract_ntpvar("foo", "foo");
258 ok(!test, "Malformed string 1"); 248 ok(!test, "Malformed string 1");
259 249
260 test=np_extract_ntpvar("foo,", "foo"); 250 test = np_extract_ntpvar("foo,", "foo");
261 ok(!test, "Malformed string 2"); 251 ok(!test, "Malformed string 2");
262 252
263 test=np_extract_ntpvar("foo=", "foo"); 253 test = np_extract_ntpvar("foo=", "foo");
264 ok(!test, "Malformed string 3"); 254 ok(!test, "Malformed string 3");
265 255
266 test=np_extract_ntpvar("foo=,bar=foo", "foo"); 256 test = np_extract_ntpvar("foo=,bar=foo", "foo");
267 ok(!test, "Malformed string 4"); 257 ok(!test, "Malformed string 4");
268 258
269 test=np_extract_ntpvar(",foo", "foo"); 259 test = np_extract_ntpvar(",foo", "foo");
270 ok(!test, "Malformed string 5"); 260 ok(!test, "Malformed string 5");
271 261
272 test=np_extract_ntpvar("=foo", "foo"); 262 test = np_extract_ntpvar("=foo", "foo");
273 ok(!test, "Malformed string 6"); 263 ok(!test, "Malformed string 6");
274 264
275 test=np_extract_ntpvar("=foo,", "foo"); 265 test = np_extract_ntpvar("=foo,", "foo");
276 ok(!test, "Malformed string 7"); 266 ok(!test, "Malformed string 7");
277 267
278 test=np_extract_ntpvar(",,,", "foo"); 268 test = np_extract_ntpvar(",,,", "foo");
279 ok(!test, "Malformed string 8"); 269 ok(!test, "Malformed string 8");
280 270
281 test=np_extract_ntpvar("===", "foo"); 271 test = np_extract_ntpvar("===", "foo");
282 ok(!test, "Malformed string 9"); 272 ok(!test, "Malformed string 9");
283 273
284 test=np_extract_ntpvar(",=,=,", "foo"); 274 test = np_extract_ntpvar(",=,=,", "foo");
285 ok(!test, "Malformed string 10"); 275 ok(!test, "Malformed string 10");
286 276
287 test=np_extract_ntpvar("=,=,=", "foo"); 277 test = np_extract_ntpvar("=,=,=", "foo");
288 ok(!test, "Malformed string 11"); 278 ok(!test, "Malformed string 11");
289 279
290 test=np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "foo"); 280 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"); 281 ok(test && !strcmp(test, "bar"), "Random spaces and newlines 1");
292 free(test); 282 free(test);
293 283
294 test=np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "bar"); 284 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"); 285 ok(test && !strcmp(test, "foo"), "Random spaces and newlines 2");
296 free(test); 286 free(test);
297 287
298 test=np_extract_ntpvar(" foo=bar ,\n bar=foo\n , foobar=barfoo \n ", "foobar"); 288 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"); 289 ok(test && !strcmp(test, "barfoo"), "Random spaces and newlines 3");
300 free(test); 290 free(test);
301 291
302 test=np_extract_ntpvar(" foo=bar ,\n bar\n \n= \n foo\n , foobar=barfoo \n ", "bar"); 292 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"); 293 ok(test && !strcmp(test, "foo"), "Random spaces and newlines 4");
304 free(test); 294 free(test);
305 295
306 test=np_extract_ntpvar("", "foo"); 296 test = np_extract_ntpvar("", "foo");
307 ok(!test, "Empty string return NULL"); 297 ok(!test, "Empty string return NULL");
308 298
309
310 /* This is the result of running ./test_utils */
311 temp_string = (char *) _np_state_generate_key();
312 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" );
314
315
316 this_monitoring_plugin->argc=4;
317 this_monitoring_plugin->argv[0] = "./test_utils";
318 this_monitoring_plugin->argv[1] = "here";
319 this_monitoring_plugin->argv[2] = "--and";
320 this_monitoring_plugin->argv[3] = "now";
321 temp_string = (char *) _np_state_generate_key();
322 ok(!strcmp(temp_string, "bd72da9f78ff1419fad921ea5e43ce56508aef6c"), "Got based on expected argv" );
323
324 unsetenv("MP_STATE_PATH");
325 temp_string = (char *) _np_state_calculate_location_prefix();
326 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory" );
327
328 setenv("MP_STATE_PATH", "", 1);
329 temp_string = (char *) _np_state_calculate_location_prefix();
330 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory even with empty string" );
331
332 setenv("MP_STATE_PATH", "/usr/local/nagios/var", 1);
333 temp_string = (char *) _np_state_calculate_location_prefix();
334 ok(!strcmp(temp_string, "/usr/local/nagios/var"), "Got default directory" );
335
336
337
338 ok(temp_state_key==NULL, "temp_state_key initially empty");
339
340 this_monitoring_plugin->argc=1;
341 this_monitoring_plugin->argv[0] = "./test_utils";
342 np_enable_state(NULL, 51);
343 temp_state_key = this_monitoring_plugin->state;
344 ok( !strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name" );
345 ok( !strcmp(temp_state_key->name, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"), "Got generated filename" );
346
347
348 np_enable_state("allowedchars_in_keyname", 77);
349 temp_state_key = this_monitoring_plugin->state;
350 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" );
352 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" );
354
355
356 /* Don't do this test just yet. Will die */
357 /*
358 np_enable_state("bad^chars$in@here", 77);
359 temp_state_key = this_monitoring_plugin->state;
360 ok( !strcmp(temp_state_key->name, "bad_chars_in_here"), "Got key name with bad chars replaced" );
361 */
362
363 np_enable_state("funnykeyname", 54);
364 temp_state_key = this_monitoring_plugin->state;
365 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" );
367 ok( !strcmp(temp_state_key->name, "funnykeyname"), "Got key name" );
368
369
370
371 ok( !strcmp(temp_state_key->_filename, state_path), "Got internal filename" );
372 ok( temp_state_key->data_version==54, "Version set" );
373
374 temp_state_data = np_state_read();
375 ok( temp_state_data==NULL, "Got no state data as file does not exist" );
376
377
378/*
379 temp_fp = fopen("var/statefile", "r");
380 if (temp_fp==NULL)
381 printf("Error opening. errno=%d\n", errno);
382 printf("temp_fp=%s\n", temp_fp);
383 ok( _np_state_read_file(temp_fp) == true, "Can read state file" );
384 fclose(temp_fp);
385*/
386
387 temp_state_key->_filename="var/statefile";
388 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");
390 ok( this_monitoring_plugin->state->state_data->time==1234567890, "Got time" );
391 ok( !strcmp((char *)this_monitoring_plugin->state->state_data->data, "String to read"), "Data as expected" );
392
393 temp_state_key->data_version=53;
394 temp_state_data = np_state_read();
395 ok( temp_state_data==NULL, "Older data version gives NULL" );
396 temp_state_key->data_version=54;
397
398 temp_state_key->_filename="var/nonexistent";
399 temp_state_data = np_state_read();
400 ok( temp_state_data==NULL, "Missing file gives NULL" );
401 ok( this_monitoring_plugin->state->state_data==NULL, "No state information" );
402
403 temp_state_key->_filename="var/oldformat";
404 temp_state_data = np_state_read();
405 ok( temp_state_data==NULL, "Old file format gives NULL" );
406
407 temp_state_key->_filename="var/baddate";
408 temp_state_data = np_state_read();
409 ok( temp_state_data==NULL, "Bad date gives NULL" );
410
411 temp_state_key->_filename="var/missingdataline";
412 temp_state_data = np_state_read();
413 ok( temp_state_data==NULL, "Missing data line gives NULL" );
414
415
416
417
418 unlink("var/generated");
419 temp_state_key->_filename="var/generated";
420 current_time=1234567890;
421 np_state_write_string(current_time, "String to read");
422 ok(system("cmp var/generated var/statefile")==0, "Generated file same as expected");
423
424
425
426
427 unlink("var/generated_directory/statefile");
428 unlink("var/generated_directory");
429 temp_state_key->_filename="var/generated_directory/statefile";
430 current_time=1234567890;
431 np_state_write_string(current_time, "String to read");
432 ok(system("cmp var/generated_directory/statefile var/statefile")==0, "Have created directory");
433
434 /* This test to check cannot write to dir - can't automate yet */
435 /*
436 unlink("var/generated_bad_dir");
437 mkdir("var/generated_bad_dir", S_IRUSR);
438 np_state_write_string(current_time, "String to read");
439 */
440
441
442 temp_state_key->_filename="var/generated";
443 time(&current_time);
444 np_state_write_string(0, "String to read");
445 temp_state_data = np_state_read();
446 /* 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");
448 ok(this_monitoring_plugin->state->state_data->time-current_time<=1, "Has time generated from current time");
449
450
451 /* Don't know how to automatically test this. Need to be able to redefine die and catch the error */
452 /*
453 temp_state_key->_filename="/dev/do/not/expect/to/be/able/to/write";
454 np_state_write_string(0, "Bad file");
455 */
456
457
458 np_cleanup();
459
460 ok(this_monitoring_plugin==NULL, "Free'd this_monitoring_plugin");
461
462 ok(mp_suid() == false, "Test aren't suid"); 299 ok(mp_suid() == false, "Test aren't suid");
463 300
464 /* base states with random case */ 301 /* base states with random case */
465 char *states[] = { 302 char *states[] = {"Ok", "wArnINg", "cRiTIcaL", "UnKNoWN", NULL};
466 "Ok", 303
467 "wArnINg", 304 for (int i = 0; states[i] != NULL; i++) {
468 "cRiTIcaL", 305 /* out of the random case states, create the lower and upper versions + numeric string one
469 "UnKNoWN", 306 */
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 */
475 char *statelower = strdup(states[i]); 307 char *statelower = strdup(states[i]);
476 char *stateupper = strdup(states[i]); 308 char *stateupper = strdup(states[i]);
477 char statenum[2]; 309 char statenum[2];
478 char *temp_ptr; 310 for (char *temp_ptr = statelower; *temp_ptr; temp_ptr++) {
479 for (temp_ptr = statelower; *temp_ptr; temp_ptr++) { 311 *temp_ptr = (char)tolower(*temp_ptr);
480 *temp_ptr = tolower(*temp_ptr);
481 } 312 }
482 for (temp_ptr = stateupper; *temp_ptr; temp_ptr++) { 313 for (char *temp_ptr = stateupper; *temp_ptr; temp_ptr++) {
483 *temp_ptr = toupper(*temp_ptr); 314 *temp_ptr = (char)toupper(*temp_ptr);
484 } 315 }
485 snprintf(statenum, 2, "%i", i); 316 snprintf(statenum, 2, "%i", i);
486 317
487 /* Base test names, we'll append the state string */ 318 /* Base test names, we'll append the state string */
488 char testname[64] = "Translate state string: "; 319 char testname[64] = "Translate state string: ";
489 int tlen = strlen(testname); 320 size_t tlen = strlen(testname);
490 321
491 strcpy(testname+tlen, states[i]); 322 strcpy(testname + tlen, states[i]);
492 ok(i==mp_translate_state(states[i]), testname); 323 ok(i == mp_translate_state(states[i]), testname);
493 324
494 strcpy(testname+tlen, statelower); 325 strcpy(testname + tlen, statelower);
495 ok(i==mp_translate_state(statelower), testname); 326 ok(i == mp_translate_state(statelower), testname);
496 327
497 strcpy(testname+tlen, stateupper); 328 strcpy(testname + tlen, stateupper);
498 ok(i==mp_translate_state(stateupper), testname); 329 ok(i == mp_translate_state(stateupper), testname);
499 330
500 strcpy(testname+tlen, statenum); 331 strcpy(testname + tlen, statenum);
501 ok(i==mp_translate_state(statenum), testname); 332 ok(i == mp_translate_state(statenum), testname);
502 } 333 }
503 ok(ERROR==mp_translate_state("warningfewgw"), "Translate state string with garbage"); 334 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"); 335 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"); 336 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"); 337 ok(ERROR == mp_translate_state("10"), "Translate state string: bad numeric string 3");
507 ok(ERROR==mp_translate_state(""), "Translate state string: empty string"); 338 ok(ERROR == mp_translate_state(""), "Translate state string: empty string");
508 339
509 return exit_status(); 340 return exit_status();
510} 341}
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..f8647681
--- /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 {
10 range *warning;
11 range *critical;
12} thresholds;
13
14typedef 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..28e6dc47 100644
--- a/lib/utils_base.c
+++ b/lib/utils_base.c
@@ -1,30 +1,31 @@
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 "states.h"
28#include <stdarg.h> 29#include <stdarg.h>
29#include "utils_base.h" 30#include "utils_base.h"
30#include <ctype.h> 31#include <ctype.h>
@@ -33,94 +34,87 @@
33#include <unistd.h> 34#include <unistd.h>
34#include <sys/types.h> 35#include <sys/types.h>
35 36
36#define np_free(ptr) { if(ptr) { free(ptr); ptr = NULL; } } 37#define np_free(ptr) \
38 { \
39 if (ptr) { \
40 free(ptr); \
41 ptr = NULL; \
42 } \
43 }
37 44
38monitoring_plugin *this_monitoring_plugin=NULL; 45monitoring_plugin *this_monitoring_plugin = NULL;
39 46
40int timeout_state = STATE_CRITICAL; 47mp_state_enum timeout_state = STATE_CRITICAL;
41unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT; 48unsigned int timeout_interval = DEFAULT_SOCKET_TIMEOUT;
42 49
43bool _np_state_read_file(FILE *); 50bool _np_state_read_file(FILE *state_file);
44 51
45void np_init( char *plugin_name, int argc, char **argv ) { 52void np_init(char *plugin_name, int argc, char **argv) {
46 if (this_monitoring_plugin==NULL) { 53 if (this_monitoring_plugin == NULL) {
47 this_monitoring_plugin = calloc(1, sizeof(monitoring_plugin)); 54 this_monitoring_plugin = calloc(1, sizeof(monitoring_plugin));
48 if (this_monitoring_plugin==NULL) { 55 if (this_monitoring_plugin == NULL) {
49 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 56 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
50 strerror(errno));
51 } 57 }
52 this_monitoring_plugin->plugin_name = strdup(plugin_name); 58 this_monitoring_plugin->plugin_name = strdup(plugin_name);
53 if (this_monitoring_plugin->plugin_name==NULL) 59 if (this_monitoring_plugin->plugin_name == NULL) {
54 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno)); 60 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
61 }
55 this_monitoring_plugin->argc = argc; 62 this_monitoring_plugin->argc = argc;
56 this_monitoring_plugin->argv = argv; 63 this_monitoring_plugin->argv = argv;
57 } 64 }
58} 65}
59 66
60void np_set_args( int argc, char **argv ) { 67void np_set_args(int argc, char **argv) {
61 if (this_monitoring_plugin==NULL) 68 if (this_monitoring_plugin == NULL) {
62 die(STATE_UNKNOWN, _("This requires np_init to be called")); 69 die(STATE_UNKNOWN, _("This requires np_init to be called"));
70 }
63 71
64 this_monitoring_plugin->argc = argc; 72 this_monitoring_plugin->argc = argc;
65 this_monitoring_plugin->argv = argv; 73 this_monitoring_plugin->argv = argv;
66} 74}
67 75
68 76void np_cleanup(void) {
69void np_cleanup() { 77 if (this_monitoring_plugin != NULL) {
70 if (this_monitoring_plugin!=NULL) {
71 if(this_monitoring_plugin->state!=NULL) {
72 if(this_monitoring_plugin->state->state_data) {
73 np_free(this_monitoring_plugin->state->state_data->data);
74 np_free(this_monitoring_plugin->state->state_data);
75 }
76 np_free(this_monitoring_plugin->state->name);
77 np_free(this_monitoring_plugin->state);
78 }
79 np_free(this_monitoring_plugin->plugin_name); 78 np_free(this_monitoring_plugin->plugin_name);
80 np_free(this_monitoring_plugin); 79 np_free(this_monitoring_plugin);
81 } 80 }
82 this_monitoring_plugin=NULL; 81 this_monitoring_plugin = NULL;
83} 82}
84 83
85/* Hidden function to get a pointer to this_monitoring_plugin for testing */ 84/* Hidden function to get a pointer to this_monitoring_plugin for testing */
86void _get_monitoring_plugin( monitoring_plugin **pointer ){ 85void _get_monitoring_plugin(monitoring_plugin **pointer) { *pointer = this_monitoring_plugin; }
87 *pointer = this_monitoring_plugin;
88}
89 86
90void 87void die(int result, const char *fmt, ...) {
91die (int result, const char *fmt, ...) 88 if (fmt != NULL) {
92{
93 if(fmt!=NULL) {
94 va_list ap; 89 va_list ap;
95 va_start (ap, fmt); 90 va_start(ap, fmt);
96 vprintf (fmt, ap); 91 vprintf(fmt, ap);
97 va_end (ap); 92 va_end(ap);
98 } 93 }
99 94
100 if(this_monitoring_plugin!=NULL) { 95 if (this_monitoring_plugin != NULL) {
101 np_cleanup(); 96 np_cleanup();
102 } 97 }
103 exit (result); 98 exit(result);
104} 99}
105 100
106void set_range_start (range *this, double value) { 101void set_range_start(range *this, double value) {
107 this->start = value; 102 this->start = value;
108 this->start_infinity = false; 103 this->start_infinity = false;
109} 104}
110 105
111void set_range_end (range *this, double value) { 106void set_range_end(range *this, double value) {
112 this->end = value; 107 this->end = value;
113 this->end_infinity = false; 108 this->end_infinity = false;
114} 109}
115 110
116range 111range *parse_range_string(char *str) {
117*parse_range_string (char *str) {
118 range *temp_range; 112 range *temp_range;
119 double start; 113 double start;
120 double end; 114 double end;
121 char *end_str; 115 char *end_str;
122 116
123 temp_range = (range *) calloc(1, sizeof(range)); 117 temp_range = (range *)calloc(1, sizeof(range));
124 118
125 /* Set defaults */ 119 /* Set defaults */
126 temp_range->start = 0; 120 temp_range->start = 0;
@@ -140,10 +134,10 @@ range
140 if (str[0] == '~') { 134 if (str[0] == '~') {
141 temp_range->start_infinity = true; 135 temp_range->start_infinity = true;
142 } else { 136 } else {
143 start = strtod(str, NULL); /* Will stop at the ':' */ 137 start = strtod(str, NULL); /* Will stop at the ':' */
144 set_range_start(temp_range, start); 138 set_range_start(temp_range, start);
145 } 139 }
146 end_str++; /* Move past the ':' */ 140 end_str++; /* Move past the ':' */
147 } else { 141 } else {
148 end_str = str; 142 end_str = str;
149 } 143 }
@@ -152,8 +146,7 @@ range
152 set_range_end(temp_range, end); 146 set_range_end(temp_range, end);
153 } 147 }
154 148
155 if (temp_range->start_infinity == true || 149 if (temp_range->start_infinity || temp_range->end_infinity ||
156 temp_range->end_infinity == true ||
157 temp_range->start <= temp_range->end) { 150 temp_range->start <= temp_range->end) {
158 return temp_range; 151 return temp_range;
159 } 152 }
@@ -162,14 +155,12 @@ range
162} 155}
163 156
164/* returns 0 if okay, otherwise 1 */ 157/* returns 0 if okay, otherwise 1 */
165int 158int _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; 159 thresholds *temp_thresholds = NULL;
169 160
170 if ((temp_thresholds = calloc(1, sizeof(thresholds))) == NULL) 161 if ((temp_thresholds = calloc(1, sizeof(thresholds))) == NULL) {
171 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), 162 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
172 strerror(errno)); 163 }
173 164
174 temp_thresholds->warning = NULL; 165 temp_thresholds->warning = NULL;
175 temp_thresholds->critical = NULL; 166 temp_thresholds->critical = NULL;
@@ -190,9 +181,7 @@ _set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_st
190 return 0; 181 return 0;
191} 182}
192 183
193void 184void 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)) { 185 switch (_set_thresholds(my_thresholds, warn_string, critical_string)) {
197 case 0: 186 case 0:
198 return; 187 return;
@@ -206,16 +195,18 @@ set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_str
206 195
207void print_thresholds(const char *threshold_name, thresholds *my_threshold) { 196void print_thresholds(const char *threshold_name, thresholds *my_threshold) {
208 printf("%s - ", threshold_name); 197 printf("%s - ", threshold_name);
209 if (! my_threshold) { 198 if (!my_threshold) {
210 printf("Threshold not set"); 199 printf("Threshold not set");
211 } else { 200 } else {
212 if (my_threshold->warning) { 201 if (my_threshold->warning) {
213 printf("Warning: start=%g end=%g; ", my_threshold->warning->start, my_threshold->warning->end); 202 printf("Warning: start=%g end=%g; ", my_threshold->warning->start,
203 my_threshold->warning->end);
214 } else { 204 } else {
215 printf("Warning not set; "); 205 printf("Warning not set; ");
216 } 206 }
217 if (my_threshold->critical) { 207 if (my_threshold->critical) {
218 printf("Critical: start=%g end=%g", my_threshold->critical->start, my_threshold->critical->end); 208 printf("Critical: start=%g end=%g", my_threshold->critical->start,
209 my_threshold->critical->end);
219 } else { 210 } else {
220 printf("Critical not set"); 211 printf("Critical not set");
221 } 212 }
@@ -223,9 +214,38 @@ void print_thresholds(const char *threshold_name, thresholds *my_threshold) {
223 printf("\n"); 214 printf("\n");
224} 215}
225 216
217/* Returns true if alert should be raised based on the range, false otherwise */
218bool mp_check_range(const mp_perfdata_value value, const mp_range my_range) {
219 bool is_inside = false;
220
221 if (!my_range.end_infinity && !my_range.start_infinity) {
222 // range: .........|---inside---|...........
223 // value
224 is_inside = ((cmp_perfdata_value(value, my_range.start) >= 0) &&
225 (cmp_perfdata_value(value, my_range.end) <= 0));
226 } else if (!my_range.start_infinity && my_range.end_infinity) {
227 // range: .........|---inside---------
228 // value
229 is_inside = (cmp_perfdata_value(value, my_range.start) >= 0);
230 } else if (my_range.start_infinity && !my_range.end_infinity) {
231 // range: -inside--------|....................
232 // value
233 is_inside = (cmp_perfdata_value(value, my_range.end) == -1);
234 } else {
235 // range from -inf to inf, so always inside
236 is_inside = true;
237 }
238
239 if ((is_inside && my_range.alert_on_inside_range == INSIDE) ||
240 (!is_inside && my_range.alert_on_inside_range == OUTSIDE)) {
241 return true;
242 }
243
244 return false;
245}
246
226/* Returns true if alert should be raised based on the range */ 247/* Returns true if alert should be raised based on the range */
227bool check_range(double value, range *my_range) 248bool check_range(double value, range *my_range) {
228{
229 bool no = false; 249 bool no = false;
230 bool yes = true; 250 bool yes = true;
231 251
@@ -234,73 +254,71 @@ bool check_range(double value, range *my_range)
234 yes = false; 254 yes = false;
235 } 255 }
236 256
237 if (my_range->end_infinity == false && my_range->start_infinity == false) { 257 if (!my_range->end_infinity && !my_range->start_infinity) {
238 if ((my_range->start <= value) && (value <= my_range->end)) { 258 if ((my_range->start <= value) && (value <= my_range->end)) {
239 return no; 259 return no;
240 } else {
241 return yes;
242 } 260 }
243 } else if (my_range->start_infinity == false && my_range->end_infinity == true) { 261 return yes;
262 }
263
264 if (!my_range->start_infinity && my_range->end_infinity) {
244 if (my_range->start <= value) { 265 if (my_range->start <= value) {
245 return no; 266 return no;
246 } else {
247 return yes;
248 } 267 }
249 } else if (my_range->start_infinity == true && my_range->end_infinity == false) { 268 return yes;
269 }
270
271 if (my_range->start_infinity && !my_range->end_infinity) {
250 if (value <= my_range->end) { 272 if (value <= my_range->end) {
251 return no; 273 return no;
252 } else {
253 return yes;
254 } 274 }
255 } else { 275 return yes;
256 return no;
257 } 276 }
277 return no;
258} 278}
259 279
260/* Returns status */ 280/* Returns status */
261int 281mp_state_enum get_status(double value, thresholds *my_thresholds) {
262get_status(double value, thresholds *my_thresholds)
263{
264 if (my_thresholds->critical != NULL) { 282 if (my_thresholds->critical != NULL) {
265 if (check_range(value, my_thresholds->critical) == true) { 283 if (check_range(value, my_thresholds->critical)) {
266 return STATE_CRITICAL; 284 return STATE_CRITICAL;
267 } 285 }
268 } 286 }
269 if (my_thresholds->warning != NULL) { 287 if (my_thresholds->warning != NULL) {
270 if (check_range(value, my_thresholds->warning) == true) { 288 if (check_range(value, my_thresholds->warning)) {
271 return STATE_WARNING; 289 return STATE_WARNING;
272 } 290 }
273 } 291 }
274 return STATE_OK; 292 return STATE_OK;
275} 293}
276 294
277char *np_escaped_string (const char *string) { 295char *np_escaped_string(const char *string) {
278 char *data; 296 char *data;
279 int i, j=0; 297 int write_index = 0;
280 data = strdup(string); 298 data = strdup(string);
281 for (i=0; data[i]; i++) { 299 for (int i = 0; data[i]; i++) {
282 if (data[i] == '\\') { 300 if (data[i] == '\\') {
283 switch(data[++i]) { 301 switch (data[++i]) {
284 case 'n': 302 case 'n':
285 data[j++] = '\n'; 303 data[write_index++] = '\n';
286 break; 304 break;
287 case 'r': 305 case 'r':
288 data[j++] = '\r'; 306 data[write_index++] = '\r';
289 break; 307 break;
290 case 't': 308 case 't':
291 data[j++] = '\t'; 309 data[write_index++] = '\t';
292 break; 310 break;
293 case '\\': 311 case '\\':
294 data[j++] = '\\'; 312 data[write_index++] = '\\';
295 break; 313 break;
296 default: 314 default:
297 data[j++] = data[i]; 315 data[write_index++] = data[i];
298 } 316 }
299 } else { 317 } else {
300 data[j++] = data[i]; 318 data[write_index++] = data[i];
301 } 319 }
302 } 320 }
303 data[j] = '\0'; 321 data[write_index] = '\0';
304 return data; 322 return data;
305} 323}
306 324
@@ -313,33 +331,43 @@ int np_check_if_root(void) { return (geteuid() == 0); }
313 * data strings. 331 * data strings.
314 */ 332 */
315char *np_extract_value(const char *varlist, const char *name, char sep) { 333char *np_extract_value(const char *varlist, const char *name, char sep) {
316 char *tmp=NULL, *value=NULL; 334 char *tmp = NULL;
317 int i; 335 char *value = NULL;
318 336
319 while (1) { 337 while (true) {
320 /* Strip any leading space */ 338 /* Strip any leading space */
321 for (; isspace(varlist[0]); varlist++); 339 for (; isspace(varlist[0]); varlist++) {
340 ;
341 }
322 342
323 if (strncmp(name, varlist, strlen(name)) == 0) { 343 if (strncmp(name, varlist, strlen(name)) == 0) {
324 varlist += strlen(name); 344 varlist += strlen(name);
325 /* strip trailing spaces */ 345 /* strip trailing spaces */
326 for (; isspace(varlist[0]); varlist++); 346 for (; isspace(varlist[0]); varlist++) {
347 ;
348 }
327 349
328 if (varlist[0] == '=') { 350 if (varlist[0] == '=') {
329 /* We matched the key, go past the = sign */ 351 /* We matched the key, go past the = sign */
330 varlist++; 352 varlist++;
331 /* strip leading spaces */ 353 /* strip leading spaces */
332 for (; isspace(varlist[0]); varlist++); 354 for (; isspace(varlist[0]); varlist++) {
355 ;
356 }
333 357
334 if ((tmp = index(varlist, sep))) { 358 if ((tmp = index(varlist, sep))) {
335 /* Value is delimited by a comma */ 359 /* Value is delimited by a comma */
336 if (tmp-varlist == 0) continue; 360 if (tmp - varlist == 0) {
337 value = (char *)calloc(1, tmp-varlist+1); 361 continue;
338 strncpy(value, varlist, tmp-varlist); 362 }
339 value[tmp-varlist] = '\0'; 363 value = (char *)calloc(1, (unsigned long)(tmp - varlist + 1));
364 strncpy(value, varlist, (unsigned long)(tmp - varlist));
365 value[tmp - varlist] = '\0';
340 } else { 366 } else {
341 /* Value is delimited by a \0 */ 367 /* Value is delimited by a \0 */
342 if (strlen(varlist) == 0) continue; 368 if (strlen(varlist) == 0) {
369 continue;
370 }
343 value = (char *)calloc(1, strlen(varlist) + 1); 371 value = (char *)calloc(1, strlen(varlist) + 1);
344 strncpy(value, varlist, strlen(varlist)); 372 strncpy(value, varlist, strlen(varlist));
345 value[strlen(varlist)] = '\0'; 373 value[strlen(varlist)] = '\0';
@@ -357,14 +385,16 @@ char *np_extract_value(const char *varlist, const char *name, char sep) {
357 } 385 }
358 386
359 /* Clean-up trailing spaces/newlines */ 387 /* Clean-up trailing spaces/newlines */
360 if (value) for (i=strlen(value)-1; isspace(value[i]); i--) value[i] = '\0'; 388 if (value) {
389 for (unsigned long i = strlen(value) - 1; isspace(value[i]); i--) {
390 value[i] = '\0';
391 }
392 }
361 393
362 return value; 394 return value;
363} 395}
364 396
365const char * 397const char *state_text(mp_state_enum result) {
366state_text (int result)
367{
368 switch (result) { 398 switch (result) {
369 case STATE_OK: 399 case STATE_OK:
370 return "OK"; 400 return "OK";
@@ -383,345 +413,18 @@ state_text (int result)
383 * Read a string representing a state (ok, warning... or numeric: 0, 1) and 413 * Read a string representing a state (ok, warning... or numeric: 0, 1) and
384 * return the corresponding STATE_ value or ERROR) 414 * return the corresponding STATE_ value or ERROR)
385 */ 415 */
386int mp_translate_state (char *state_text) { 416int mp_translate_state(char *state_text) {
387 if (!strcasecmp(state_text,"OK") || !strcmp(state_text,"0")) 417 if (!strcasecmp(state_text, "OK") || !strcmp(state_text, "0")) {
388 return STATE_OK; 418 return STATE_OK;
389 if (!strcasecmp(state_text,"WARNING") || !strcmp(state_text,"1"))
390 return STATE_WARNING;
391 if (!strcasecmp(state_text,"CRITICAL") || !strcmp(state_text,"2"))
392 return STATE_CRITICAL;
393 if (!strcasecmp(state_text,"UNKNOWN") || !strcmp(state_text,"3"))
394 return STATE_UNKNOWN;
395 return ERROR;
396}
397
398/*
399 * Returns a string to use as a keyname, based on an md5 hash of argv, thus
400 * hopefully a unique key per service/plugin invocation. Use the extra-opts
401 * parse of argv, so that uniqueness in parameters are reflected there.
402 */
403char *_np_state_generate_key() {
404 int i;
405 char **argv = this_monitoring_plugin->argv;
406 char keyname[41];
407 char *p=NULL;
408
409 unsigned char result[256];
410
411#ifdef USE_OPENSSL
412 /*
413 * This code path is chosen if openssl is available (which should be the most common
414 * scenario). Alternatively, the gnulib implementation/
415 *
416 */
417 EVP_MD_CTX *ctx = EVP_MD_CTX_new();
418
419 EVP_DigestInit(ctx, EVP_sha256());
420
421 for(i=0; i<this_monitoring_plugin->argc; i++) {
422 EVP_DigestUpdate(ctx, argv[i], strlen(argv[i]));
423 }
424
425 EVP_DigestFinal(ctx, result, NULL);
426#else
427
428 struct sha256_ctx ctx;
429
430 for(i=0; i<this_monitoring_plugin->argc; i++) {
431 sha256_process_bytes(argv[i], strlen(argv[i]), &ctx);
432 }
433
434 sha256_finish_ctx(&ctx, result);
435#endif // FOUNDOPENSSL
436
437 for (i=0; i<20; ++i) {
438 sprintf(&keyname[2*i], "%02x", result[i]);
439 } 419 }
440 420 if (!strcasecmp(state_text, "WARNING") || !strcmp(state_text, "1")) {
441 keyname[40]='\0'; 421 return STATE_WARNING;
442
443 p = strdup(keyname);
444 if(p==NULL) {
445 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
446 }
447 return p;
448}
449
450void _cleanup_state_data() {
451 if (this_monitoring_plugin->state->state_data!=NULL) {
452 np_free(this_monitoring_plugin->state->state_data->data);
453 np_free(this_monitoring_plugin->state->state_data);
454 }
455}
456
457/*
458 * Internal function. Returns either:
459 * envvar NAGIOS_PLUGIN_STATE_DIRECTORY
460 * statically compiled shared state directory
461 */
462char* _np_state_calculate_location_prefix(){
463 char *env_dir;
464
465 /* Do not allow passing MP_STATE_PATH in setuid plugins
466 * for security reasons */
467 if (!mp_suid()) {
468 env_dir = getenv("MP_STATE_PATH");
469 if(env_dir && env_dir[0] != '\0')
470 return env_dir;
471 /* This is the former ENV, for backward-compatibility */
472 env_dir = getenv("NAGIOS_PLUGIN_STATE_DIRECTORY");
473 if(env_dir && env_dir[0] != '\0')
474 return env_dir;
475 }
476
477 return NP_STATE_DIR_PREFIX;
478}
479
480/*
481 * Initiatializer for state routines.
482 * Sets variables. Generates filename. Returns np_state_key. die with
483 * UNKNOWN if exception
484 */
485void np_enable_state(char *keyname, int expected_data_version) {
486 state_key *this_state = NULL;
487 char *temp_filename = NULL;
488 char *temp_keyname = NULL;
489 char *p=NULL;
490 int ret;
491
492 if(this_monitoring_plugin==NULL)
493 die(STATE_UNKNOWN, _("This requires np_init to be called"));
494
495 this_state = (state_key *) calloc(1, sizeof(state_key));
496 if(this_state==NULL)
497 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"),
498 strerror(errno));
499
500 if(keyname==NULL) {
501 temp_keyname = _np_state_generate_key();
502 } else {
503 temp_keyname = strdup(keyname);
504 if(temp_keyname==NULL)
505 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
506 }
507 /* Die if invalid characters used for keyname */
508 p = temp_keyname;
509 while(*p!='\0') {
510 if(! (isalnum(*p) || *p == '_')) {
511 die(STATE_UNKNOWN, _("Invalid character for keyname - only alphanumerics or '_'"));
512 }
513 p++;
514 }
515 this_state->name=temp_keyname;
516 this_state->plugin_name=this_monitoring_plugin->plugin_name;
517 this_state->data_version=expected_data_version;
518 this_state->state_data=NULL;
519
520 /* Calculate filename */
521 ret = asprintf(&temp_filename, "%s/%lu/%s/%s",
522 _np_state_calculate_location_prefix(), (unsigned long)geteuid(),
523 this_monitoring_plugin->plugin_name, this_state->name);
524 if (ret < 0)
525 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"),
526 strerror(errno));
527
528 this_state->_filename=temp_filename;
529
530 this_monitoring_plugin->state = this_state;
531}
532
533/*
534 * Will return NULL if no data is available (first run). If key currently
535 * exists, read data. If state file format version is not expected, return
536 * as if no data. Get state data version number and compares to expected.
537 * If numerically lower, then return as no previous state. die with UNKNOWN
538 * if exceptional error.
539 */
540state_data *np_state_read() {
541 state_data *this_state_data=NULL;
542 FILE *statefile;
543 bool rc = false;
544
545 if(this_monitoring_plugin==NULL)
546 die(STATE_UNKNOWN, _("This requires np_init to be called"));
547
548 /* Open file. If this fails, no previous state found */
549 statefile = fopen( this_monitoring_plugin->state->_filename, "r" );
550 if(statefile!=NULL) {
551
552 this_state_data = (state_data *) calloc(1, sizeof(state_data));
553 if(this_state_data==NULL)
554 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"),
555 strerror(errno));
556
557 this_state_data->data=NULL;
558 this_monitoring_plugin->state->state_data = this_state_data;
559
560 rc = _np_state_read_file(statefile);
561
562 fclose(statefile);
563 }
564
565 if(!rc) {
566 _cleanup_state_data();
567 }
568
569 return this_monitoring_plugin->state->state_data;
570}
571
572/*
573 * Read the state file
574 */
575bool _np_state_read_file(FILE *f) {
576 bool status = false;
577 size_t pos;
578 char *line;
579 int i;
580 int failure=0;
581 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;
583
584 time(&current_time);
585
586 /* Note: This introduces a limit of 1024 bytes in the string data */
587 line = (char *) calloc(1, 1024);
588 if(line==NULL)
589 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"),
590 strerror(errno));
591
592 while(!failure && (fgets(line,1024,f))!=NULL){
593 pos=strlen(line);
594 if(line[pos-1]=='\n') {
595 line[pos-1]='\0';
596 }
597
598 if(line[0] == '#') continue;
599
600 switch(expected) {
601 case STATE_FILE_VERSION:
602 i=atoi(line);
603 if(i!=NP_STATE_FORMAT_VERSION)
604 failure++;
605 else
606 expected=STATE_DATA_VERSION;
607 break;
608 case STATE_DATA_VERSION:
609 i=atoi(line);
610 if(i != this_monitoring_plugin->state->data_version)
611 failure++;
612 else
613 expected=STATE_DATA_TIME;
614 break;
615 case STATE_DATA_TIME:
616 /* If time > now, error */
617 data_time=strtoul(line,NULL,10);
618 if(data_time > current_time)
619 failure++;
620 else {
621 this_monitoring_plugin->state->state_data->time = data_time;
622 expected=STATE_DATA_TEXT;
623 }
624 break;
625 case STATE_DATA_TEXT:
626 this_monitoring_plugin->state->state_data->data = strdup(line);
627 if(this_monitoring_plugin->state->state_data->data==NULL)
628 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
629 expected=STATE_DATA_END;
630 status=true;
631 break;
632 case STATE_DATA_END:
633 ;
634 }
635 }
636
637 np_free(line);
638 return status;
639}
640
641/*
642 * If time=NULL, use current time. Create state file, with state format
643 * version, default text. Writes version, time, and data. Avoid locking
644 * problems - use mv to write and then swap. Possible loss of state data if
645 * two things writing to same key at same time.
646 * Will die with UNKNOWN if errors
647 */
648void np_state_write_string(time_t data_time, char *data_string) {
649 FILE *fp;
650 char *temp_file=NULL;
651 int fd=0, result=0;
652 time_t current_time;
653 char *directories=NULL;
654 char *p=NULL;
655
656 if(data_time==0)
657 time(&current_time);
658 else
659 current_time=data_time;
660
661 /* If file doesn't currently exist, create directories */
662 if(access(this_monitoring_plugin->state->_filename,F_OK)!=0) {
663 result = asprintf(&directories, "%s", this_monitoring_plugin->state->_filename);
664 if(result < 0)
665 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"),
666 strerror(errno));
667
668 for(p=directories+1; *p; p++) {
669 if(*p=='/') {
670 *p='\0';
671 if((access(directories,F_OK)!=0) && (mkdir(directories, S_IRWXU)!=0)) {
672 /* Can't free this! Otherwise error message is wrong! */
673 /* np_free(directories); */
674 die(STATE_UNKNOWN, _("Cannot create directory: %s"), directories);
675 }
676 *p='/';
677 }
678 }
679 np_free(directories);
680 }
681
682 result = asprintf(&temp_file,"%s.XXXXXX",this_monitoring_plugin->state->_filename);
683 if(result < 0)
684 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"),
685 strerror(errno));
686
687 if((fd=mkstemp(temp_file))==-1) {
688 np_free(temp_file);
689 die(STATE_UNKNOWN, _("Cannot create temporary filename"));
690 }
691
692 fp=(FILE *)fdopen(fd,"w");
693 if(fp==NULL) {
694 close(fd);
695 unlink(temp_file);
696 np_free(temp_file);
697 die(STATE_UNKNOWN, _("Unable to open temporary state file"));
698 } 422 }
699 423 if (!strcasecmp(state_text, "CRITICAL") || !strcmp(state_text, "2")) {
700 fprintf(fp,"# NP State file\n"); 424 return STATE_CRITICAL;
701 fprintf(fp,"%d\n",NP_STATE_FORMAT_VERSION);
702 fprintf(fp,"%d\n",this_monitoring_plugin->state->data_version);
703 fprintf(fp,"%lu\n",current_time);
704 fprintf(fp,"%s\n",data_string);
705
706 fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP);
707
708 fflush(fp);
709
710 result=fclose(fp);
711
712 fsync(fd);
713
714 if(result!=0) {
715 unlink(temp_file);
716 np_free(temp_file);
717 die(STATE_UNKNOWN, _("Error writing temp file"));
718 } 425 }
719 426 if (!strcasecmp(state_text, "UNKNOWN") || !strcmp(state_text, "3")) {
720 if(rename(temp_file, this_monitoring_plugin->state->_filename)!=0) { 427 return STATE_UNKNOWN;
721 unlink(temp_file);
722 np_free(temp_file);
723 die(STATE_UNKNOWN, _("Cannot rename state temp file"));
724 } 428 }
725 429 return ERROR;
726 np_free(temp_file);
727} 430}
diff --git a/lib/utils_base.h b/lib/utils_base.h
index 9d4dffed..27884bf0 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#include "states.h"
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,65 +26,34 @@
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
37
38typedef struct state_data_struct {
39 time_t time;
40 void *data;
41 int length; /* Of binary data */
42 } state_data;
43
44
45typedef struct state_key_struct {
46 char *name;
47 char *plugin_name;
48 int data_version;
49 char *_filename;
50 state_data *state_data;
51 } state_key;
52
53typedef struct np_struct { 29typedef struct np_struct {
54 char *plugin_name; 30 char *plugin_name;
55 state_key *state; 31 int argc;
56 int argc; 32 char **argv;
57 char **argv; 33} monitoring_plugin;
58 } monitoring_plugin;
59 34
60range *parse_range_string (char *); 35range *parse_range_string(char *);
61int _set_thresholds(thresholds **, char *, char *); 36int _set_thresholds(thresholds **, char *, char *);
62void set_thresholds(thresholds **, char *, char *); 37void set_thresholds(thresholds **, char *, char *);
63void print_thresholds(const char *, thresholds *); 38void print_thresholds(const char *, thresholds *);
64bool check_range(double, range *); 39bool check_range(double, range *);
65int get_status(double, thresholds *); 40bool mp_check_range(mp_perfdata_value, mp_range);
41mp_state_enum get_status(double, thresholds *);
66 42
67/* Handle timeouts */ 43/* Handle timeouts */
68extern int timeout_state; 44extern mp_state_enum timeout_state;
69extern unsigned int timeout_interval; 45extern unsigned int timeout_interval;
70 46
71/* All possible characters in a threshold range */ 47/* All possible characters in a threshold range */
72#define NP_THRESHOLDS_CHARS "-0123456789.:@~" 48#define NP_THRESHOLDS_CHARS "-0123456789.:@~"
73 49
74char *np_escaped_string (const char *); 50char *np_escaped_string(const char *);
75 51
76void die (int, const char *, ...) __attribute__((noreturn,format(printf, 2, 3))); 52void die(int, const char *, ...) __attribute__((noreturn, format(printf, 2, 3)));
77 53
78/* Return codes for _set_thresholds */ 54/* Return codes for _set_thresholds */
79#define NP_RANGE_UNPARSEABLE 1 55#define NP_RANGE_UNPARSEABLE 1
80#define NP_WARN_WITHIN_CRIT 2 56#define NP_WARN_WITHIN_CRIT 2
81 57
82/* a simple check to see if we're running as root. 58/* a simple check to see if we're running as root.
83 * returns zero on failure, nonzero on success */ 59 * returns zero on failure, nonzero on success */
@@ -93,7 +69,7 @@ int np_check_if_root(void);
93 * This function can be used to parse NTP control packet data and performance 69 * This function can be used to parse NTP control packet data and performance
94 * data strings. 70 * data strings.
95 */ 71 */
96char *np_extract_value(const char*, const char*, char); 72char *np_extract_value(const char *, const char *, char);
97 73
98/* 74/*
99 * Same as np_extract_value with separator suitable for NTP control packet 75 * Same as np_extract_value with separator suitable for NTP control packet
@@ -105,15 +81,11 @@ char *np_extract_value(const char*, const char*, char);
105 * Read a string representing a state (ok, warning... or numeric: 0, 1) and 81 * Read a string representing a state (ok, warning... or numeric: 0, 1) and
106 * return the corresponding NP_STATE or ERROR) 82 * return the corresponding NP_STATE or ERROR)
107 */ 83 */
108int mp_translate_state (char *); 84int mp_translate_state(char *);
109
110void np_enable_state(char *, int);
111state_data *np_state_read();
112void np_state_write_string(time_t, char *);
113 85
114void np_init(char *, int argc, char **argv); 86void np_init(char *, int argc, char **argv);
115void np_set_args(int argc, char **argv); 87void np_set_args(int argc, char **argv);
116void np_cleanup(); 88void np_cleanup(void);
117const char *state_text (int); 89const char *state_text(mp_state_enum);
118 90
119#endif /* _UTILS_BASE_ */ 91#endif /* _UTILS_BASE_ */
diff --git a/lib/utils_cmd.c b/lib/utils_cmd.c
index 7957ec14..35b83297 100644
--- a/lib/utils_cmd.c
+++ b/lib/utils_cmd.c
@@ -1,46 +1,45 @@
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
41/** includes **/ 41/** includes **/
42#include "common.h" 42#include "common.h"
43#include "utils.h"
44#include "utils_cmd.h" 43#include "utils_cmd.h"
45/* This variable must be global, since there's no way the caller 44/* This variable must be global, since there's no way the caller
46 * can forcibly slay a dead or ungainly running program otherwise. 45 * can forcibly slay a dead or ungainly running program otherwise.
@@ -59,115 +58,106 @@ static pid_t *_cmd_pids = NULL;
59#include <fcntl.h> 58#include <fcntl.h>
60 59
61#ifdef HAVE_SYS_WAIT_H 60#ifdef HAVE_SYS_WAIT_H
62# include <sys/wait.h> 61# include <sys/wait.h>
63#endif 62#endif
64 63
65/* used in _cmd_open to pass the environment to commands */
66extern char **environ;
67
68/** macros **/ 64/** macros **/
69#ifndef WEXITSTATUS 65#ifndef WEXITSTATUS
70# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) 66# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
71#endif 67#endif
72 68
73#ifndef WIFEXITED 69#ifndef WIFEXITED
74# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) 70# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
75#endif 71#endif
76 72
77/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */ 73/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */
78#if defined(SIG_IGN) && !defined(SIG_ERR) 74#if defined(SIG_IGN) && !defined(SIG_ERR)
79# define SIG_ERR ((Sigfunc *)-1) 75# define SIG_ERR ((Sigfunc *)-1)
80#endif 76#endif
81 77
82/** prototypes **/ 78/** prototypes **/
83static int _cmd_open (char *const *, int *, int *) 79static int _cmd_open(char *const *argv, int *pfd, int *pfderr)
84 __attribute__ ((__nonnull__ (1, 2, 3))); 80 __attribute__((__nonnull__(1, 2, 3)));
85
86static int _cmd_fetch_output (int, output *, int)
87 __attribute__ ((__nonnull__ (2)));
88 81
89static int _cmd_close (int); 82static int _cmd_fetch_output(int fileDescriptor, output *cmd_output, int flags) __attribute__((__nonnull__(2)));
90
91/* prototype imported from utils.h */
92extern void die (int, const char *, ...)
93 __attribute__ ((__noreturn__, __format__ (__printf__, 2, 3)));
94 83
84static int _cmd_close(int fileDescriptor);
95 85
96/* this function is NOT async-safe. It is exported so multithreaded 86/* this function is NOT async-safe. It is exported so multithreaded
97 * plugins (or other apps) can call it prior to running any commands 87 * plugins (or other apps) can call it prior to running any commands
98 * through this api and thus achieve async-safeness throughout the api */ 88 * through this api and thus achieve async-safeness throughout the api */
99void 89void cmd_init(void) {
100cmd_init (void)
101{
102 long maxfd = mp_open_max(); 90 long maxfd = mp_open_max();
103 91
104 /* if maxfd is unnaturally high, we force it to a lower value 92 /* 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 93 * ( e.g. on SunOS, when ulimit is set to unlimited: 2147483647 this would cause
106 * a segfault when following calloc is called ... ) */ 94 * a segfault when following calloc is called ... ) */
107 95
108 if ( maxfd > MAXFD_LIMIT ) { 96 if (maxfd > MAXFD_LIMIT) {
109 maxfd = MAXFD_LIMIT; 97 maxfd = MAXFD_LIMIT;
110 } 98 }
111 99
112 if (!_cmd_pids) 100 if (!_cmd_pids) {
113 _cmd_pids = calloc (maxfd, sizeof (pid_t)); 101 _cmd_pids = calloc(maxfd, sizeof(pid_t));
102 }
114} 103}
115 104
116
117/* Start running a command, array style */ 105/* Start running a command, array style */
118static int 106static 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;
122#ifdef RLIMIT_CORE 107#ifdef RLIMIT_CORE
123 struct rlimit limit; 108 struct rlimit limit;
124#endif 109#endif
125 110
126 int i = 0; 111 int i = 0;
127 112
128 if (!_cmd_pids) 113 if (!_cmd_pids) {
129 CMD_INIT; 114 CMD_INIT;
115 }
130 116
131 setenv("LC_ALL", "C", 1); 117 setenv("LC_ALL", "C", 1);
132 118
133 if (pipe (pfd) < 0 || pipe (pfderr) < 0 || (pid = fork ()) < 0) 119 pid_t pid;
134 return -1; /* errno set by the failing function */ 120 if (pipe(pfd) < 0 || pipe(pfderr) < 0 || (pid = fork()) < 0) {
121 return -1; /* errno set by the failing function */
122 }
135 123
136 /* child runs exceve() and _exit. */ 124 /* child runs exceve() and _exit. */
137 if (pid == 0) { 125 if (pid == 0) {
138#ifdef RLIMIT_CORE 126#ifdef RLIMIT_CORE
139 /* the program we execve shouldn't leave core files */ 127 /* the program we execve shouldn't leave core files */
140 getrlimit (RLIMIT_CORE, &limit); 128 getrlimit(RLIMIT_CORE, &limit);
141 limit.rlim_cur = 0; 129 limit.rlim_cur = 0;
142 setrlimit (RLIMIT_CORE, &limit); 130 setrlimit(RLIMIT_CORE, &limit);
143#endif 131#endif
144 close (pfd[0]); 132 close(pfd[0]);
145 if (pfd[1] != STDOUT_FILENO) { 133 if (pfd[1] != STDOUT_FILENO) {
146 dup2 (pfd[1], STDOUT_FILENO); 134 dup2(pfd[1], STDOUT_FILENO);
147 close (pfd[1]); 135 close(pfd[1]);
148 } 136 }
149 close (pfderr[0]); 137 close(pfderr[0]);
150 if (pfderr[1] != STDERR_FILENO) { 138 if (pfderr[1] != STDERR_FILENO) {
151 dup2 (pfderr[1], STDERR_FILENO); 139 dup2(pfderr[1], STDERR_FILENO);
152 close (pfderr[1]); 140 close(pfderr[1]);
153 } 141 }
154 142
155 /* close all descriptors in _cmd_pids[] 143 /* close all descriptors in _cmd_pids[]
156 * This is executed in a separate address space (pure child), 144 * This is executed in a separate address space (pure child),
157 * so we don't have to worry about async safety */ 145 * so we don't have to worry about async safety */
158 long maxfd = mp_open_max(); 146 long maxfd = mp_open_max();
159 for (i = 0; i < maxfd; i++) 147 for (i = 0; i < maxfd; i++) {
160 if (_cmd_pids[i] > 0) 148 if (_cmd_pids[i] > 0) {
161 close (i); 149 close(i);
150 }
151 }
162 152
163 execve (argv[0], argv, environ); 153 execve(argv[0], argv, environ);
164 _exit (STATE_UNKNOWN); 154 _exit(STATE_UNKNOWN);
165 } 155 }
166 156
167 /* parent picks up execution here */ 157 /* parent picks up execution here */
168 /* close children descriptors in our address space */ 158 /* close children descriptors in our address space */
169 close (pfd[1]); 159 close(pfd[1]);
170 close (pfderr[1]); 160 close(pfderr[1]);
171 161
172 /* tag our file's entry in the pid-list and return it */ 162 /* tag our file's entry in the pid-list and return it */
173 _cmd_pids[pfd[0]] = pid; 163 _cmd_pids[pfd[0]] = pid;
@@ -175,93 +165,94 @@ _cmd_open (char *const *argv, int *pfd, int *pfderr)
175 return pfd[0]; 165 return pfd[0];
176} 166}
177 167
178static int 168static int _cmd_close(int fileDescriptor) {
179_cmd_close (int fd)
180{
181 int status;
182 pid_t pid; 169 pid_t pid;
183 170
184 /* make sure the provided fd was opened */ 171 /* make sure the provided fd was opened */
185 long maxfd = mp_open_max(); 172 long maxfd = mp_open_max();
186 if (fd < 0 || fd > maxfd || !_cmd_pids || (pid = _cmd_pids[fd]) == 0) 173 if (fileDescriptor < 0 || fileDescriptor > maxfd || !_cmd_pids ||
174 (pid = _cmd_pids[fileDescriptor]) == 0) {
187 return -1; 175 return -1;
176 }
188 177
189 _cmd_pids[fd] = 0; 178 _cmd_pids[fileDescriptor] = 0;
190 if (close (fd) == -1) 179 if (close(fileDescriptor) == -1) {
191 return -1; 180 return -1;
181 }
192 182
193 /* EINTR is ok (sort of), everything else is bad */ 183 /* EINTR is ok (sort of), everything else is bad */
194 while (waitpid (pid, &status, 0) < 0) 184 int status;
195 if (errno != EINTR) 185 while (waitpid(pid, &status, 0) < 0) {
186 if (errno != EINTR) {
196 return -1; 187 return -1;
188 }
189 }
197 190
198 /* return child's termination status */ 191 /* return child's termination status */
199 return (WIFEXITED (status)) ? WEXITSTATUS (status) : -1; 192 return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1;
200} 193}
201 194
202 195static int _cmd_fetch_output(int fileDescriptor, output *cmd_output, int flags) {
203static int
204_cmd_fetch_output (int fd, output * op, int flags)
205{
206 size_t len = 0, i = 0, lineno = 0;
207 size_t rsf = 6, ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */
208 char *buf = NULL;
209 int ret;
210 char tmpbuf[4096]; 196 char tmpbuf[4096];
211 197 cmd_output->buf = NULL;
212 op->buf = NULL; 198 cmd_output->buflen = 0;
213 op->buflen = 0; 199 ssize_t ret;
214 while ((ret = read (fd, tmpbuf, sizeof (tmpbuf))) > 0) { 200 while ((ret = read(fileDescriptor, tmpbuf, sizeof(tmpbuf))) > 0) {
215 len = (size_t) ret; 201 size_t len = (size_t)ret;
216 op->buf = realloc (op->buf, op->buflen + len + 1); 202 cmd_output->buf = realloc(cmd_output->buf, cmd_output->buflen + len + 1);
217 memcpy (op->buf + op->buflen, tmpbuf, len); 203 memcpy(cmd_output->buf + cmd_output->buflen, tmpbuf, len);
218 op->buflen += len; 204 cmd_output->buflen += len;
219 i++;
220 } 205 }
221 206
222 if (ret < 0) { 207 if (ret < 0) {
223 printf ("read() returned %d: %s\n", ret, strerror (errno)); 208 printf("read() returned %zd: %s\n", ret, strerror(errno));
224 return ret; 209 return ret;
225 } 210 }
226 211
227 /* some plugins may want to keep output unbroken, and some commands 212 /* some plugins may want to keep output unbroken, and some commands
228 * will yield no output, so return here for those */ 213 * will yield no output, so return here for those */
229 if (flags & CMD_NO_ARRAYS || !op->buf || !op->buflen) 214 if (flags & CMD_NO_ARRAYS || !cmd_output->buf || !cmd_output->buflen) {
230 return op->buflen; 215 return cmd_output->buflen;
216 }
231 217
232 /* and some may want both */ 218 /* and some may want both */
219 char *buf = NULL;
233 if (flags & CMD_NO_ASSOC) { 220 if (flags & CMD_NO_ASSOC) {
234 buf = malloc (op->buflen); 221 buf = malloc(cmd_output->buflen);
235 memcpy (buf, op->buf, op->buflen); 222 memcpy(buf, cmd_output->buf, cmd_output->buflen);
223 } else {
224 buf = cmd_output->buf;
236 } 225 }
237 else
238 buf = op->buf;
239 226
240 op->line = NULL; 227 cmd_output->line = NULL;
241 op->lens = NULL; 228 cmd_output->lens = NULL;
242 i = 0; 229 size_t i = 0;
243 while (i < op->buflen) { 230 size_t ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */
231 size_t rsf = 6;
232 size_t lineno = 0;
233 while (i < cmd_output->buflen) {
244 /* make sure we have enough memory */ 234 /* make sure we have enough memory */
245 if (lineno >= ary_size) { 235 if (lineno >= ary_size) {
246 /* ary_size must never be zero */ 236 /* ary_size must never be zero */
247 do { 237 do {
248 ary_size = op->buflen >> --rsf; 238 ary_size = cmd_output->buflen >> --rsf;
249 } while (!ary_size); 239 } while (!ary_size);
250 240
251 op->line = realloc (op->line, ary_size * sizeof (char *)); 241 cmd_output->line = realloc(cmd_output->line, ary_size * sizeof(char *));
252 op->lens = realloc (op->lens, ary_size * sizeof (size_t)); 242 cmd_output->lens = realloc(cmd_output->lens, ary_size * sizeof(size_t));
253 } 243 }
254 244
255 /* set the pointer to the string */ 245 /* set the pointer to the string */
256 op->line[lineno] = &buf[i]; 246 cmd_output->line[lineno] = &buf[i];
257 247
258 /* hop to next newline or end of buffer */ 248 /* hop to next newline or end of buffer */
259 while (buf[i] != '\n' && i < op->buflen) 249 while (buf[i] != '\n' && i < cmd_output->buflen) {
260 i++; 250 i++;
251 }
261 buf[i] = '\0'; 252 buf[i] = '\0';
262 253
263 /* calculate the string length using pointer difference */ 254 /* calculate the string length using pointer difference */
264 op->lens[lineno] = (size_t) & buf[i] - (size_t) op->line[lineno]; 255 cmd_output->lens[lineno] = (size_t)&buf[i] - (size_t)cmd_output->line[lineno];
265 256
266 lineno++; 257 lineno++;
267 i++; 258 i++;
@@ -270,135 +261,142 @@ _cmd_fetch_output (int fd, output * op, int flags)
270 return lineno; 261 return lineno;
271} 262}
272 263
273 264int cmd_run(const char *cmdstring, output *out, output *err, int flags) {
274int 265 if (cmdstring == NULL) {
275cmd_run (const char *cmdstring, output * out, output * err, int flags)
276{
277 int i = 0, argc;
278 size_t cmdlen;
279 char **argv = NULL;
280 char *cmd = NULL;
281 char *str = NULL;
282
283 if (cmdstring == NULL)
284 return -1; 266 return -1;
267 }
285 268
286 /* initialize the structs */ 269 /* initialize the structs */
287 if (out) 270 if (out) {
288 memset (out, 0, sizeof (output)); 271 memset(out, 0, sizeof(output));
289 if (err) 272 }
290 memset (err, 0, sizeof (output)); 273 if (err) {
274 memset(err, 0, sizeof(output));
275 }
291 276
292 /* make copy of command string so strtok() doesn't silently modify it */ 277 /* make copy of command string so strtok() doesn't silently modify it */
293 /* (the calling program may want to access it later) */ 278 /* (the calling program may want to access it later) */
294 cmdlen = strlen (cmdstring); 279 size_t cmdlen = strlen(cmdstring);
295 if ((cmd = malloc (cmdlen + 1)) == NULL) 280 char *cmd = NULL;
281 if ((cmd = malloc(cmdlen + 1)) == NULL) {
296 return -1; 282 return -1;
297 memcpy (cmd, cmdstring, cmdlen); 283 }
284 memcpy(cmd, cmdstring, cmdlen);
298 cmd[cmdlen] = '\0'; 285 cmd[cmdlen] = '\0';
299 286
300 /* This is not a shell, so we don't handle "???" */ 287 /* This is not a shell, so we don't handle "???" */
301 if (strstr (cmdstring, "\"")) return -1; 288 if (strstr(cmdstring, "\"")) {
289 return -1;
290 }
302 291
303 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */ 292 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */
304 if (strstr (cmdstring, " ' ") || strstr (cmdstring, "'''")) 293 if (strstr(cmdstring, " ' ") || strstr(cmdstring, "'''")) {
305 return -1; 294 return -1;
295 }
306 296
307 /* each arg must be whitespace-separated, so args can be a maximum 297 /* 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 */ 298 * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */
309 argc = (cmdlen >> 1) + 2; 299 int argc = (cmdlen >> 1) + 2;
310 argv = calloc (sizeof (char *), argc); 300 char **argv = calloc((size_t)argc, sizeof(char *));
311 301
312 if (argv == NULL) { 302 if (argv == NULL) {
313 printf ("%s\n", _("Could not malloc argv array in popen()")); 303 printf("%s\n", _("Could not malloc argv array in popen()"));
314 return -1; 304 return -1;
315 } 305 }
316 306
317 /* get command arguments (stupidly, but fairly quickly) */ 307 /* get command arguments (stupidly, but fairly quickly) */
308 int i = 0;
318 while (cmd) { 309 while (cmd) {
319 str = cmd; 310 char *str = cmd;
320 str += strspn (str, " \t\r\n"); /* trim any leading whitespace */ 311 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */
321 312
322 if (strstr (str, "'") == str) { /* handle SIMPLE quoted strings */ 313 if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */
323 str++; 314 str++;
324 if (!strstr (str, "'")) 315 if (!strstr(str, "'")) {
325 return -1; /* balanced? */ 316 return -1; /* balanced? */
326 cmd = 1 + strstr (str, "'");
327 str[strcspn (str, "'")] = 0;
328 }
329 else {
330 if (strpbrk (str, " \t\r\n")) {
331 cmd = 1 + strpbrk (str, " \t\r\n");
332 str[strcspn (str, " \t\r\n")] = 0;
333 } 317 }
334 else { 318 cmd = 1 + strstr(str, "'");
319 str[strcspn(str, "'")] = 0;
320 } else {
321 if (strpbrk(str, " \t\r\n")) {
322 cmd = 1 + strpbrk(str, " \t\r\n");
323 str[strcspn(str, " \t\r\n")] = 0;
324 } else {
335 cmd = NULL; 325 cmd = NULL;
336 } 326 }
337 } 327 }
338 328
339 if (cmd && strlen (cmd) == strspn (cmd, " \t\r\n")) 329 if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n")) {
340 cmd = NULL; 330 cmd = NULL;
331 }
341 332
342 argv[i++] = str; 333 argv[i++] = str;
343 } 334 }
344 335
345 return cmd_run_array (argv, out, err, flags); 336 return cmd_run_array(argv, out, err, flags);
346} 337}
347 338
348int 339int 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];
352
353 /* initialize the structs */ 340 /* initialize the structs */
354 if (out) 341 if (out) {
355 memset (out, 0, sizeof (output)); 342 memset(out, 0, sizeof(output));
356 if (err) 343 }
357 memset (err, 0, sizeof (output)); 344 if (err) {
345 memset(err, 0, sizeof(output));
346 }
358 347
359 if ((fd = _cmd_open (argv, pfd_out, pfd_err)) == -1) 348 int fd;
360 die (STATE_UNKNOWN, _("Could not open pipe: %s\n"), argv[0]); 349 int pfd_out[2];
350 int pfd_err[2];
351 if ((fd = _cmd_open(argv, pfd_out, pfd_err)) == -1) {
352 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), argv[0]);
353 }
361 354
362 if (out) 355 if (out) {
363 out->lines = _cmd_fetch_output (pfd_out[0], out, flags); 356 out->lines = _cmd_fetch_output(pfd_out[0], out, flags);
364 if (err) 357 }
365 err->lines = _cmd_fetch_output (pfd_err[0], err, flags); 358 if (err) {
359 err->lines = _cmd_fetch_output(pfd_err[0], err, flags);
360 }
366 361
367 return _cmd_close (fd); 362 return _cmd_close(fd);
368} 363}
369 364
370int 365int cmd_file_read(const char *filename, output *out, int flags) {
371cmd_file_read ( char *filename, output *out, int flags)
372{
373 int fd; 366 int fd;
374 if(out) 367 if (out) {
375 memset (out, 0, sizeof(output)); 368 memset(out, 0, sizeof(output));
369 }
376 370
377 if ((fd = open(filename, O_RDONLY)) == -1) { 371 if ((fd = open(filename, O_RDONLY)) == -1) {
378 die( STATE_UNKNOWN, _("Error opening %s: %s"), filename, strerror(errno) ); 372 die(STATE_UNKNOWN, _("Error opening %s: %s"), filename, strerror(errno));
379 } 373 }
380 374
381 if(out) 375 if (out) {
382 out->lines = _cmd_fetch_output (fd, out, flags); 376 out->lines = _cmd_fetch_output(fd, out, flags);
377 }
383 378
384 if (close(fd) == -1) 379 if (close(fd) == -1) {
385 die( STATE_UNKNOWN, _("Error closing %s: %s"), filename, strerror(errno) ); 380 die(STATE_UNKNOWN, _("Error closing %s: %s"), filename, strerror(errno));
381 }
386 382
387 return 0; 383 return 0;
388} 384}
389 385
390void 386void timeout_alarm_handler(int signo) {
391timeout_alarm_handler (int signo)
392{
393 if (signo == SIGALRM) { 387 if (signo == SIGALRM) {
394 printf (_("%s - Plugin timed out after %d seconds\n"), 388 printf(_("%s - Plugin timed out after %d seconds\n"), state_text(timeout_state),
395 state_text(timeout_state), timeout_interval); 389 timeout_interval);
396 390
397 long maxfd = mp_open_max(); 391 long maxfd = mp_open_max();
398 if(_cmd_pids) for(long int i = 0; i < maxfd; i++) { 392 if (_cmd_pids) {
399 if(_cmd_pids[i] != 0) kill(_cmd_pids[i], SIGKILL); 393 for (long int i = 0; i < maxfd; i++) {
394 if (_cmd_pids[i] != 0) {
395 kill(_cmd_pids[i], SIGKILL);
396 }
397 }
400 } 398 }
401 399
402 exit (timeout_state); 400 exit(timeout_state);
403 } 401 }
404} 402}
diff --git a/lib/utils_cmd.h b/lib/utils_cmd.h
index 061f5d4f..3672cdc9 100644
--- a/lib/utils_cmd.h
+++ b/lib/utils_cmd.h
@@ -4,36 +4,32 @@
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 */
8#include "../config.h"
9#include <stddef.h>
9 10
10/** types **/ 11/** types **/
11struct output 12typedef struct {
12{
13 char *buf; /* output buffer */ 13 char *buf; /* output buffer */
14 size_t buflen; /* output buffer content length */ 14 size_t buflen; /* output buffer content length */
15 char **line; /* array of lines (points to buf) */ 15 char **line; /* array of lines (points to buf) */
16 size_t *lens; /* string lengths */ 16 size_t *lens; /* string lengths */
17 size_t lines; /* lines of output */ 17 size_t lines; /* lines of output */
18}; 18} output;
19
20typedef 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..a82d5a3f 100644
--- a/lib/utils_tcp.c
+++ b/lib/utils_tcp.c
@@ -1,75 +1,78 @@
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 "../config.h"
30#include "utils_tcp.h" 30#include "utils_tcp.h"
31#include <stdio.h>
32#include <string.h>
31 33
32#define VERBOSE(message) \ 34#define VERBOSE(message) \
33 do { \ 35 do { \
34 if (flags & NP_MATCH_VERBOSE) \ 36 if (flags & NP_MATCH_VERBOSE) \
35 puts(message); \ 37 puts(message); \
36 } while (0) 38 } while (0)
37 39
38enum np_match_result 40enum np_match_result np_expect_match(char *status, char **server_expect, int expect_count,
39np_expect_match(char *status, char **server_expect, int expect_count, int flags) 41 int flags) {
40{ 42 int match = 0;
41 int i, match = 0, partial = 0; 43 int partial = 0;
42 44 for (int i = 0; i < expect_count; i++) {
43 for (i = 0; i < expect_count; i++) { 45 if (flags & NP_MATCH_VERBOSE) {
44 if (flags & NP_MATCH_VERBOSE)
45 printf("looking for [%s] %s [%s]\n", server_expect[i], 46 printf("looking for [%s] %s [%s]\n", server_expect[i],
46 (flags & NP_MATCH_EXACT) ? 47 (flags & NP_MATCH_EXACT) ? "in beginning of" : "anywhere in", status);
47 "in beginning of" : "anywhere in", 48 }
48 status);
49 49
50 if (flags & NP_MATCH_EXACT) { 50 if (flags & NP_MATCH_EXACT) {
51 if (strncmp(status, server_expect[i], strlen(server_expect[i])) == 0) { 51 if (strncmp(status, server_expect[i], strlen(server_expect[i])) == 0) {
52 VERBOSE("found it"); 52 VERBOSE("found it");
53 match++; 53 match++;
54 continue; 54 continue;
55 } else if (strncmp(status, server_expect[i], strlen(status)) == 0) { 55 }
56
57 if (strncmp(status, server_expect[i], strlen(status)) == 0) {
56 VERBOSE("found a substring"); 58 VERBOSE("found a substring");
57 partial++; 59 partial++;
58 continue; 60 continue;
59 } 61 }
60 } else if (strstr(status, server_expect[i]) != NULL) { 62 } else if (strstr(status, server_expect[i]) != NULL) {
61 VERBOSE("found it"); 63 VERBOSE("found it");
62 match++; 64 match++;
63 continue; 65 continue;
64 } 66 }
65 VERBOSE("couldn't find it"); 67 VERBOSE("couldn't find it");
66 } 68 }
67 69
68 if ((flags & NP_MATCH_ALL && match == expect_count) || 70 if ((flags & NP_MATCH_ALL && match == expect_count) ||
69 (!(flags & NP_MATCH_ALL) && match >= 1)) 71 (!(flags & NP_MATCH_ALL) && match >= 1)) {
70 return NP_MATCH_SUCCESS; 72 return NP_MATCH_SUCCESS;
71 else if (partial > 0 || !(flags & NP_MATCH_EXACT)) 73 }
74 if (partial > 0 || !(flags & NP_MATCH_EXACT)) {
72 return NP_MATCH_RETRY; 75 return NP_MATCH_RETRY;
73 else 76 }
74 return NP_MATCH_FAILURE; 77 return NP_MATCH_FAILURE;
75} 78}
diff --git a/lib/utils_tcp.h b/lib/utils_tcp.h
index 0328a9cf..e5cdbb82 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,11 @@
11 * server. 11 * server.
12 */ 12 */
13enum np_match_result { 13enum np_match_result {
14 NP_MATCH_NONE,
14 NP_MATCH_FAILURE, 15 NP_MATCH_FAILURE,
15 NP_MATCH_SUCCESS, 16 NP_MATCH_SUCCESS,
16 NP_MATCH_RETRY 17 NP_MATCH_RETRY
17}; 18};
18 19
19enum np_match_result np_expect_match(char *status, 20enum np_match_result np_expect_match(char *status, char **server_expect, int server_expect_count,
20 char **server_expect, 21 int flags);
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..9a96547f 100644
--- a/plugins-root/check_dhcp.c
+++ b/plugins-root/check_dhcp.c
@@ -4,7 +4,7 @@
4 * 4 *
5 * License: GPL 5 * License: GPL
6 * Copyright (c) 2001-2004 Ethan Galstad (nagios@nagios.org) 6 * Copyright (c) 2001-2004 Ethan Galstad (nagios@nagios.org)
7 * Copyright (c) 2001-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,254 @@ 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*/,
236int get_ip_address(int,char *); 203 unsigned char *client_hardware_address);
237 204
238int send_dhcp_discover(int); 205typedef struct get_ip_address_wrapper {
239int get_dhcp_offer(int); 206 int error;
207 struct in_addr my_ip;
208} get_ip_address_wrapper;
209static get_ip_address_wrapper get_ip_address(int /*sock*/, char * /*interface_name*/);
210
211typedef struct send_dhcp_discover_wrapper {
212 int error;
213 uint32_t packet_xid;
214} send_dhcp_discover_wrapper;
215static send_dhcp_discover_wrapper
216send_dhcp_discover(int socket, bool unicast, struct in_addr dhcp_ip,
217 struct in_addr requested_address, bool request_specific_address,
218 struct in_addr my_ip, unsigned char *client_hardware_address);
219typedef struct get_dhcp_offer_wrapper {
220 int error;
221 int valid_responses;
222 dhcp_offer *dhcp_offer_list;
223} get_dhcp_offer_wrapper;
224static get_dhcp_offer_wrapper get_dhcp_offer(int /*sock*/, int dhcpoffer_timeout,
225 uint32_t packet_xid, dhcp_offer *dhcp_offer_list,
226 const unsigned char *client_hardware_address);
227
228static mp_subcheck get_results(bool exclusive, int requested_servers,
229 struct in_addr requested_address, bool request_specific_address,
230 requested_server *requested_server_list, int valid_responses,
231 dhcp_offer *dhcp_offer_list);
232
233typedef struct add_dhcp_offer_wrapper {
234 int error;
235 dhcp_offer *dhcp_offer_list;
236} add_dhcp_offer_wrapper;
237static add_dhcp_offer_wrapper add_dhcp_offer(struct in_addr /*source*/,
238 dhcp_packet * /*offer_packet*/,
239 dhcp_offer *dhcp_offer_list);
240static int free_dhcp_offer_list(dhcp_offer *dhcp_offer_list);
241static int free_requested_server_list(requested_server *requested_server_list);
242
243static int create_dhcp_socket(bool /*unicast*/, char *network_interface_name);
244static int close_dhcp_socket(int /*sock*/);
245static int send_dhcp_packet(void * /*buffer*/, int /*buffer_size*/, int /*sock*/,
246 struct sockaddr_in * /*dest*/);
247static int receive_dhcp_packet(void * /*buffer*/, int /*buffer_size*/, int /*sock*/,
248 int /*timeout*/, struct sockaddr_in * /*address*/);
249
250int main(int argc, char **argv) {
251 setlocale(LC_ALL, "");
252 bindtextdomain(PACKAGE, LOCALEDIR);
253 textdomain(PACKAGE);
240 254
241int get_results(void); 255 /* Parse extra opts if any */
242 256 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 257
258 setlocale (LC_ALL, ""); 258 process_arguments_wrapper tmp = process_arguments(argc, argv);
259 bindtextdomain (PACKAGE, LOCALEDIR);
260 textdomain (PACKAGE);
261 259
262 /* Parse extra opts if any */ 260 if (tmp.error != OK) {
263 argv=np_extra_opts(&argc, argv, progname); 261 usage4(_("Could not parse arguments"));
262 }
264 263
265 if(process_arguments(argc,argv)!=OK){ 264 check_dhcp_config config = tmp.config;
266 usage4 (_("Could not parse arguments")); 265 if (config.output_format_is_set) {
266 mp_set_format(config.output_format);
267 } 267 }
268 268
269 /* create socket for DHCP communications */ 269 /* create socket for DHCP communications */
270 dhcp_socket=create_dhcp_socket(); 270 int dhcp_socket = create_dhcp_socket(config.unicast_mode, config.network_interface_name);
271 271
272 /* get hardware address of client machine */ 272 /* get hardware address of client machine */
273 if(user_specified_mac!=NULL) 273 unsigned char client_hardware_address[MAX_DHCP_CHADDR_LENGTH] = "";
274 memcpy(client_hardware_address,user_specified_mac,6); 274 if (config.user_specified_mac != NULL) {
275 else 275 memcpy(client_hardware_address, config.user_specified_mac, MAC_ADDR_LEN);
276 get_hardware_address(dhcp_socket,network_interface_name); 276 } else {
277 get_hardware_address(dhcp_socket, config.network_interface_name, client_hardware_address);
278 }
277 279
278 if(unicast) /* get IP address of client machine */ 280 struct in_addr my_ip = {0};
279 get_ip_address(dhcp_socket,network_interface_name); 281
282 if (config.unicast_mode) { /* get IP address of client machine */
283 get_ip_address_wrapper tmp_get_ip =
284 get_ip_address(dhcp_socket, config.network_interface_name);
285 if (tmp_get_ip.error == OK) {
286 my_ip = tmp_get_ip.my_ip;
287 } else {
288 // TODO failed to get own IP
289 die(STATE_UNKNOWN, "Failed to retrieve my own IP address in unicast mode");
290 }
291 }
280 292
281 /* send DHCPDISCOVER packet */ 293 /* send DHCPDISCOVER packet */
282 send_dhcp_discover(dhcp_socket); 294 send_dhcp_discover_wrapper disco_res = send_dhcp_discover(
295 dhcp_socket, config.unicast_mode, config.dhcp_ip, config.requested_address,
296 config.request_specific_address, my_ip, client_hardware_address);
297
298 if (disco_res.error != OK) {
299 // DO something?
300 die(STATE_UNKNOWN, "Failed to send DHCP discover");
301 }
283 302
284 /* wait for a DHCPOFFER packet */ 303 /* wait for a DHCPOFFER packet */
285 get_dhcp_offer(dhcp_socket); 304 get_dhcp_offer_wrapper offer_res = get_dhcp_offer(
305 dhcp_socket, config.dhcpoffer_timeout, disco_res.packet_xid, NULL, client_hardware_address);
306
307 int valid_responses = 0;
308 dhcp_offer *dhcp_offer_list = NULL;
309 if (offer_res.error == OK) {
310 valid_responses = offer_res.valid_responses;
311 dhcp_offer_list = offer_res.dhcp_offer_list;
312 } else {
313 die(STATE_UNKNOWN, "Failed to get DHCP offers");
314 }
286 315
287 /* close socket we created */ 316 /* close socket we created */
288 close_dhcp_socket(dhcp_socket); 317 close_dhcp_socket(dhcp_socket);
289 318
290 /* determine state/plugin output to return */ 319 mp_check overall = mp_check_init();
291 result=get_results();
292 320
321 /* determine state/plugin output to return */
322 mp_subcheck sc_res =
323 get_results(config.exclusive_mode, config.num_of_requested_servers,
324 config.requested_address, config.request_specific_address,
325 config.requested_server_list, valid_responses, dhcp_offer_list);
326 mp_add_subcheck_to_check(&overall, sc_res);
293 /* free allocated memory */ 327 /* free allocated memory */
294 free_dhcp_offer_list(); 328 free_dhcp_offer_list(dhcp_offer_list);
295 free_requested_server_list(); 329 free_requested_server_list(config.requested_server_list);
296 330
297 return result; 331 mp_exit(overall);
298} 332}
299 333
300
301
302/* determines hardware address on client machine */ 334/* determines hardware address on client machine */
303int get_hardware_address(int sock,char *interface_name){ 335int get_hardware_address(int sock, char *interface_name, unsigned char *client_hardware_address) {
304 336
305#if defined(__linux__) 337#if defined(__linux__)
306 struct ifreq ifr; 338 struct ifreq ifr;
307 339
308 strncpy((char *)&ifr.ifr_name,interface_name,sizeof(ifr.ifr_name)-1); 340 strncpy((char *)&ifr.ifr_name, interface_name, sizeof(ifr.ifr_name) - 1);
309 ifr.ifr_name[sizeof(ifr.ifr_name)-1]='\0'; 341 ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
310 342
311 /* try and grab hardware address of requested interface */ 343 /* try and grab hardware address of requested interface */
312 if(ioctl(sock,SIOCGIFHWADDR,&ifr)<0){ 344 if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
313 printf(_("Error: Could not get hardware address of interface '%s'\n"),interface_name); 345 printf(_("Error: Could not get hardware address of interface '%s'\n"), interface_name);
314 exit(STATE_UNKNOWN); 346 exit(STATE_UNKNOWN);
315 } 347 }
316 348
317 memcpy(&client_hardware_address[0],&ifr.ifr_hwaddr.sa_data,6); 349 memcpy(&client_hardware_address[0], &ifr.ifr_hwaddr.sa_data, MAC_ADDR_LEN);
318 350
319#elif defined(__bsd__) 351#elif defined(__bsd__)
320 /* King 2004 see ACKNOWLEDGEMENTS */ 352 /* King 2004 see ACKNOWLEDGEMENTS */
321 353
322 size_t len; 354 size_t len;
323 int mib[6]; 355 int mib[6];
324 char *buf; 356 char *buf;
325 unsigned char *ptr; 357 unsigned char *ptr;
326 struct if_msghdr *ifm; 358 struct if_msghdr *ifm;
327 struct sockaddr_dl *sdl; 359 struct sockaddr_dl *sdl;
328 360
329 mib[0] = CTL_NET; 361 mib[0] = CTL_NET;
330 mib[1] = AF_ROUTE; 362 mib[1] = AF_ROUTE;
@@ -332,30 +364,33 @@ int get_hardware_address(int sock,char *interface_name){
332 mib[3] = AF_LINK; 364 mib[3] = AF_LINK;
333 mib[4] = NET_RT_IFLIST; 365 mib[4] = NET_RT_IFLIST;
334 366
335 if((mib[5] = if_nametoindex(interface_name)) == 0){ 367 if ((mib[5] = if_nametoindex(interface_name)) == 0) {
336 printf(_("Error: if_nametoindex error - %s.\n"), strerror(errno)); 368 printf(_("Error: if_nametoindex error - %s.\n"), strerror(errno));
337 exit(STATE_UNKNOWN); 369 exit(STATE_UNKNOWN);
338 } 370 }
339 371
340 if(sysctl(mib, 6, NULL, &len, NULL, 0) < 0){ 372 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)); 373 printf(_("Error: Couldn't get hardware address from %s. sysctl 1 error - %s.\n"),
374 interface_name, strerror(errno));
342 exit(STATE_UNKNOWN); 375 exit(STATE_UNKNOWN);
343 } 376 }
344 377
345 if((buf = malloc(len)) == NULL){ 378 if ((buf = malloc(len)) == NULL) {
346 printf(_("Error: Couldn't get hardware address from interface %s. malloc error - %s.\n"), interface_name, strerror(errno)); 379 printf(_("Error: Couldn't get hardware address from interface %s. malloc error - %s.\n"),
380 interface_name, strerror(errno));
347 exit(4); 381 exit(4);
348 } 382 }
349 383
350 if(sysctl(mib, 6, buf, &len, NULL, 0) < 0){ 384 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)); 385 printf(_("Error: Couldn't get hardware address from %s. sysctl 2 error - %s.\n"),
386 interface_name, strerror(errno));
352 exit(STATE_UNKNOWN); 387 exit(STATE_UNKNOWN);
353 } 388 }
354 389
355 ifm = (struct if_msghdr *)buf; 390 ifm = (struct if_msghdr *)buf;
356 sdl = (struct sockaddr_dl *)(ifm + 1); 391 sdl = (struct sockaddr_dl *)(ifm + 1);
357 ptr = (unsigned char *)LLADDR(sdl); 392 ptr = (unsigned char *)LLADDR(sdl);
358 memcpy(&client_hardware_address[0], ptr, 6) ; 393 memcpy(&client_hardware_address[0], ptr, 6);
359 /* King 2004 */ 394 /* King 2004 */
360 395
361#elif defined(__sun__) || defined(__solaris__) 396#elif defined(__sun__) || defined(__solaris__)
@@ -368,35 +403,41 @@ int get_hardware_address(int sock,char *interface_name){
368 403
369 /* get last number from interfacename, eg lnc0, e1000g0*/ 404 /* get last number from interfacename, eg lnc0, e1000g0*/
370 int i; 405 int i;
371 p = interface_name + strlen(interface_name) -1; 406 p = interface_name + strlen(interface_name) - 1;
372 for(i = strlen(interface_name) -1; i > 0; p--) { 407 for (i = strlen(interface_name) - 1; i > 0; p--) {
373 if(isalpha(*p)) 408 if (isalpha(*p)) {
374 break; 409 break;
410 }
375 } 411 }
376 p++; 412 p++;
377 if( p != interface_name ){ 413 if (p != interface_name) {
378 unit = atoi(p) ; 414 unit = atoi(p);
379 strncat(dev, interface_name, 6) ; 415 strncat(dev, interface_name, 6);
380 } 416 } else {
381 else{ 417 printf(_("Error: can't find unit number in interface_name (%s) - expecting TypeNumber eg "
382 printf(_("Error: can't find unit number in interface_name (%s) - expecting TypeNumber eg lnc0.\n"), interface_name); 418 "lnc0.\n"),
419 interface_name);
383 exit(STATE_UNKNOWN); 420 exit(STATE_UNKNOWN);
384 } 421 }
385 stat = mac_addr_dlpi(dev, unit, client_hardware_address); 422 stat = mac_addr_dlpi(dev, unit, client_hardware_address);
386 if(stat != 0){ 423 if (stat != 0) {
387 printf(_("Error: can't read MAC address from DLPI streams interface for device %s unit %d.\n"), dev, unit); 424 printf(
425 _("Error: can't read MAC address from DLPI streams interface for device %s unit %d.\n"),
426 dev, unit);
388 exit(STATE_UNKNOWN); 427 exit(STATE_UNKNOWN);
389 } 428 }
390 429
391#elif defined(__hpux__) 430#elif defined(__hpux__)
392 431
393 long stat; 432 long stat;
394 char dev[20] = "/dev/dlpi" ; 433 char dev[20] = "/dev/dlpi";
395 int unit = 0; 434 int unit = 0;
396 435
397 stat = mac_addr_dlpi(dev, unit, client_hardware_address); 436 stat = mac_addr_dlpi(dev, unit, client_hardware_address);
398 if(stat != 0){ 437 if (stat != 0) {
399 printf(_("Error: can't read MAC address from DLPI streams interface for device %s unit %d.\n"), dev, unit); 438 printf(
439 _("Error: can't read MAC address from DLPI streams interface for device %s unit %d.\n"),
440 dev, unit);
400 exit(STATE_UNKNOWN); 441 exit(STATE_UNKNOWN);
401 } 442 }
402 /* Kompf 2000-2003 */ 443 /* Kompf 2000-2003 */
@@ -406,68 +447,71 @@ int get_hardware_address(int sock,char *interface_name){
406 exit(STATE_UNKNOWN); 447 exit(STATE_UNKNOWN);
407#endif 448#endif
408 449
409 if(verbose) 450 if (verbose) {
410 print_hardware_address(client_hardware_address); 451 print_hardware_address(client_hardware_address);
452 }
411 453
412 return OK; 454 return OK;
413} 455}
414 456
415/* determines IP address of the client interface */ 457/* determines IP address of the client interface */
416int get_ip_address(int sock,char *interface_name){ 458get_ip_address_wrapper get_ip_address(int sock, char *interface_name) {
417#if defined(SIOCGIFADDR) 459#if defined(SIOCGIFADDR)
418 struct ifreq ifr; 460 struct ifreq ifr;
419 461
420 strncpy((char *)&ifr.ifr_name,interface_name,sizeof(ifr.ifr_name)-1); 462 strncpy((char *)&ifr.ifr_name, interface_name, sizeof(ifr.ifr_name) - 1);
421 ifr.ifr_name[sizeof(ifr.ifr_name)-1]='\0'; 463 ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
422 464
423 if(ioctl(sock,SIOCGIFADDR,&ifr)<0){ 465 if (ioctl(sock, SIOCGIFADDR, &ifr) < 0) {
424 printf(_("Error: Cannot determine IP address of interface %s\n"), 466 printf(_("Error: Cannot determine IP address of interface %s\n"), interface_name);
425 interface_name);
426 exit(STATE_UNKNOWN); 467 exit(STATE_UNKNOWN);
427 } 468 }
428 469
429 my_ip=((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
430
431#else 470#else
432 printf(_("Error: Cannot get interface IP address on this platform.\n")); 471 printf(_("Error: Cannot get interface IP address on this platform.\n"));
433 exit(STATE_UNKNOWN); 472 exit(STATE_UNKNOWN);
434#endif 473#endif
435 474
436 if(verbose) 475 get_ip_address_wrapper result = {
437 printf(_("Pretending to be relay client %s\n"),inet_ntoa(my_ip)); 476 .error = OK,
477 .my_ip = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr,
478 };
438 479
439 return OK; 480 if (verbose) {
481 printf(_("Pretending to be relay client %s\n"), inet_ntoa(result.my_ip));
482 }
483
484 return result;
440} 485}
441 486
442/* sends a DHCPDISCOVER broadcast message in an attempt to find DHCP servers */ 487/* sends a DHCPDISCOVER broadcast message in an attempt to find DHCP servers */
443int send_dhcp_discover(int sock){ 488static send_dhcp_discover_wrapper send_dhcp_discover(int sock, bool unicast, struct in_addr dhcp_ip,
444 dhcp_packet discover_packet; 489 struct in_addr requested_address,
445 struct sockaddr_in sockaddr_broadcast; 490 bool request_specific_address,
446 unsigned short opts; 491 struct in_addr my_ip,
447 492 unsigned char *client_hardware_address) {
448 493 dhcp_packet discover_packet = {0};
449 /* clear the packet data structure */
450 bzero(&discover_packet,sizeof(discover_packet));
451
452
453 /* boot request flag (backward compatible with BOOTP servers) */ 494 /* boot request flag (backward compatible with BOOTP servers) */
454 discover_packet.op=BOOTREQUEST; 495 discover_packet.op = BOOTREQUEST;
455 496
456 /* hardware address type */ 497 /* hardware address type */
457 discover_packet.htype=ETHERNET_HARDWARE_ADDRESS; 498 discover_packet.htype = ETHERNET_HARDWARE_ADDRESS;
458 499
459 /* length of our hardware address */ 500 /* length of our hardware address */
460 discover_packet.hlen=ETHERNET_HARDWARE_ADDRESS_LENGTH; 501 discover_packet.hlen = ETHERNET_HARDWARE_ADDRESS_LENGTH;
461 502
503 send_dhcp_discover_wrapper result = {
504 .error = OK,
505 };
462 /* 506 /*
463 * transaction ID is supposed to be random. 507 * transaction ID is supposed to be random.
464 */ 508 */
465 srand(time(NULL)^getpid()); 509 srand(time(NULL) ^ getpid());
466 packet_xid=random(); 510 result.packet_xid = random();
467 discover_packet.xid=htonl(packet_xid); 511 discover_packet.xid = htonl(result.packet_xid);
468 512
469 /*discover_packet.secs=htons(65535);*/ 513 /*discover_packet.secs=htons(65535);*/
470 discover_packet.secs=0xFF; 514 discover_packet.secs = 0xFF;
471 515
472 /* 516 /*
473 * server needs to know if it should broadcast or unicast its response: 517 * server needs to know if it should broadcast or unicast its response:
@@ -476,408 +520,431 @@ int send_dhcp_discover(int sock){
476 discover_packet.flags = unicast ? 0 : htons(DHCP_BROADCAST_FLAG); 520 discover_packet.flags = unicast ? 0 : htons(DHCP_BROADCAST_FLAG);
477 521
478 /* our hardware address */ 522 /* our hardware address */
479 memcpy(discover_packet.chaddr,client_hardware_address,ETHERNET_HARDWARE_ADDRESS_LENGTH); 523 memcpy(discover_packet.chaddr, client_hardware_address, ETHERNET_HARDWARE_ADDRESS_LENGTH);
480 524
481 /* first four bytes of options field is magic cookie (as per RFC 2132) */ 525 /* first four bytes of options field is magic cookie (as per RFC 2132) */
482 discover_packet.options[0]='\x63'; 526 discover_packet.options[0] = '\x63';
483 discover_packet.options[1]='\x82'; 527 discover_packet.options[1] = '\x82';
484 discover_packet.options[2]='\x53'; 528 discover_packet.options[2] = '\x53';
485 discover_packet.options[3]='\x63'; 529 discover_packet.options[3] = '\x63';
486 530
487 opts = 4; 531 unsigned short opts = 4;
488 /* DHCP message type is embedded in options field */ 532 /* DHCP message type is embedded in options field */
489 discover_packet.options[opts++]=DHCP_OPTION_MESSAGE_TYPE; /* DHCP message type option identifier */ 533 discover_packet.options[opts++] =
490 discover_packet.options[opts++]='\x01'; /* DHCP message option length in bytes */ 534 DHCP_OPTION_MESSAGE_TYPE; /* DHCP message type option identifier */
491 discover_packet.options[opts++]=DHCPDISCOVER; 535 discover_packet.options[opts++] = '\x01'; /* DHCP message option length in bytes */
536 discover_packet.options[opts++] = DHCPDISCOVER;
492 537
493 /* the IP address we're requesting */ 538 /* the IP address we're requesting */
494 if(request_specific_address){ 539 if (request_specific_address) {
495 discover_packet.options[opts++]=DHCP_OPTION_REQUESTED_ADDRESS; 540 discover_packet.options[opts++] = DHCP_OPTION_REQUESTED_ADDRESS;
496 discover_packet.options[opts++]='\x04'; 541 discover_packet.options[opts++] = '\x04';
497 memcpy(&discover_packet.options[opts],&requested_address,sizeof(requested_address)); 542 memcpy(&discover_packet.options[opts], &requested_address, sizeof(requested_address));
498 opts += sizeof(requested_address); 543 opts += sizeof(requested_address);
499 } 544 }
500 discover_packet.options[opts++]= (char)DHCP_OPTION_END; 545 discover_packet.options[opts++] = (char)DHCP_OPTION_END;
501 546
502 /* unicast fields */ 547 /* unicast fields */
503 if(unicast) 548 if (unicast) {
504 discover_packet.giaddr.s_addr = my_ip.s_addr; 549 discover_packet.giaddr.s_addr = my_ip.s_addr;
550 }
505 551
506 /* see RFC 1542, 4.1.1 */ 552 /* see RFC 1542, 4.1.1 */
507 discover_packet.hops = unicast ? 1 : 0; 553 discover_packet.hops = unicast ? 1 : 0;
508 554
509 /* send the DHCPDISCOVER packet to broadcast address */ 555 /* send the DHCPDISCOVER packet to broadcast address */
510 sockaddr_broadcast.sin_family=AF_INET; 556 struct sockaddr_in sockaddr_broadcast = {
511 sockaddr_broadcast.sin_port=htons(DHCP_SERVER_PORT); 557 .sin_family = AF_INET,
512 sockaddr_broadcast.sin_addr.s_addr = unicast ? dhcp_ip.s_addr : INADDR_BROADCAST; 558 .sin_port = htons(DHCP_SERVER_PORT),
513 bzero(&sockaddr_broadcast.sin_zero,sizeof(sockaddr_broadcast.sin_zero)); 559 .sin_addr.s_addr = unicast ? dhcp_ip.s_addr : INADDR_BROADCAST,
514 560 };
515 561
516 if(verbose){ 562 if (verbose) {
517 printf(_("DHCPDISCOVER to %s port %d\n"),inet_ntoa(sockaddr_broadcast.sin_addr),ntohs(sockaddr_broadcast.sin_port)); 563 printf(_("DHCPDISCOVER to %s port %d\n"), inet_ntoa(sockaddr_broadcast.sin_addr),
518 printf("DHCPDISCOVER XID: %u (0x%X)\n",ntohl(discover_packet.xid),ntohl(discover_packet.xid)); 564 ntohs(sockaddr_broadcast.sin_port));
519 printf("DHCDISCOVER ciaddr: %s\n",inet_ntoa(discover_packet.ciaddr)); 565 printf("DHCPDISCOVER XID: %u (0x%X)\n", ntohl(discover_packet.xid),
520 printf("DHCDISCOVER yiaddr: %s\n",inet_ntoa(discover_packet.yiaddr)); 566 ntohl(discover_packet.xid));
521 printf("DHCDISCOVER siaddr: %s\n",inet_ntoa(discover_packet.siaddr)); 567 printf("DHCDISCOVER ciaddr: %s\n", inet_ntoa(discover_packet.ciaddr));
522 printf("DHCDISCOVER giaddr: %s\n",inet_ntoa(discover_packet.giaddr)); 568 printf("DHCDISCOVER yiaddr: %s\n", inet_ntoa(discover_packet.yiaddr));
569 printf("DHCDISCOVER siaddr: %s\n", inet_ntoa(discover_packet.siaddr));
570 printf("DHCDISCOVER giaddr: %s\n", inet_ntoa(discover_packet.giaddr));
523 } 571 }
524 572
525 /* send the DHCPDISCOVER packet out */ 573 /* send the DHCPDISCOVER packet out */
526 send_dhcp_packet(&discover_packet,sizeof(discover_packet),sock,&sockaddr_broadcast); 574 send_dhcp_packet(&discover_packet, sizeof(discover_packet), sock, &sockaddr_broadcast);
527 575
528 if(verbose) 576 if (verbose) {
529 printf("\n\n"); 577 printf("\n\n");
578 }
530 579
531 return OK; 580 return result;
532} 581}
533 582
534
535
536
537/* waits for a DHCPOFFER message from one or more DHCP servers */ 583/* waits for a DHCPOFFER message from one or more DHCP servers */
538int get_dhcp_offer(int sock){ 584get_dhcp_offer_wrapper get_dhcp_offer(int sock, int dhcpoffer_timeout, uint32_t packet_xid,
539 dhcp_packet offer_packet; 585 dhcp_offer *dhcp_offer_list,
540 struct sockaddr_in source; 586 const unsigned char *client_hardware_address) {
541 struct sockaddr_in via;
542 int result=OK;
543 int responses=0;
544 int x;
545 time_t start_time; 587 time_t start_time;
546 time_t current_time;
547
548 time(&start_time); 588 time(&start_time);
549 589
590 int result = OK;
591 int responses = 0;
592 int valid_responses = 0;
550 /* receive as many responses as we can */ 593 /* receive as many responses as we can */
551 for(responses=0,valid_responses=0;;){ 594 for (;;) {
552 595 time_t current_time;
553 time(&current_time); 596 time(&current_time);
554 if((current_time-start_time)>=dhcpoffer_timeout) 597 if ((current_time - start_time) >= dhcpoffer_timeout) {
555 break; 598 break;
599 }
556 600
557 if(verbose) 601 if (verbose) {
558 printf("\n\n"); 602 printf("\n\n");
603 }
559 604
560 bzero(&source,sizeof(source)); 605 struct sockaddr_in source = {0};
561 bzero(&via,sizeof(via)); 606 dhcp_packet offer_packet = {0};
562 bzero(&offer_packet,sizeof(offer_packet));
563 607
564 result=OK; 608 result = OK;
565 result=receive_dhcp_packet(&offer_packet,sizeof(offer_packet),sock,dhcpoffer_timeout,&source); 609 result = receive_dhcp_packet(&offer_packet, sizeof(offer_packet), sock, dhcpoffer_timeout,
610 &source);
566 611
567 if(result!=OK){ 612 if (result != OK) {
568 if(verbose) 613 if (verbose) {
569 printf(_("Result=ERROR\n")); 614 printf(_("Result=ERROR\n"));
615 }
570 616
571 continue; 617 continue;
572 } 618 }
573 else{ 619 if (verbose) {
574 if(verbose) 620 printf(_("Result=OK\n"));
575 printf(_("Result=OK\n"));
576
577 responses++;
578 } 621 }
579 622
623 responses++;
624
580 /* The "source" is either a server or a relay. */ 625 /* The "source" is either a server or a relay. */
581 /* Save a copy of "source" into "via" even if it's via itself */ 626 /* Save a copy of "source" into "via" even if it's via itself */
582 memcpy(&via,&source,sizeof(source)) ; 627 struct sockaddr_in via = {0};
628 memcpy(&via, &source, sizeof(source));
583 629
584 if(verbose){ 630 if (verbose) {
585 printf(_("DHCPOFFER from IP address %s"),inet_ntoa(source.sin_addr)); 631 printf(_("DHCPOFFER from IP address %s"), inet_ntoa(source.sin_addr));
586 printf(_(" via %s\n"),inet_ntoa(via.sin_addr)); 632 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)); 633 printf("DHCPOFFER XID: %u (0x%X)\n", ntohl(offer_packet.xid), ntohl(offer_packet.xid));
588 } 634 }
589 635
590 /* check packet xid to see if its the same as the one we used in the discover packet */ 636 /* check packet xid to see if its the same as the one we used in the discover packet */
591 if(ntohl(offer_packet.xid)!=packet_xid){ 637 if (ntohl(offer_packet.xid) != packet_xid) {
592 if(verbose) 638 if (verbose) {
593 printf(_("DHCPOFFER XID (%u) did not match DHCPDISCOVER XID (%u) - ignoring packet\n"),ntohl(offer_packet.xid),packet_xid); 639 printf(
640 _("DHCPOFFER XID (%u) did not match DHCPDISCOVER XID (%u) - ignoring packet\n"),
641 ntohl(offer_packet.xid), packet_xid);
642 }
594 643
595 continue; 644 continue;
596 } 645 }
597 646
598 /* check hardware address */ 647 /* check hardware address */
599 result=OK; 648 result = OK;
600 if(verbose) 649 if (verbose) {
601 printf("DHCPOFFER chaddr: "); 650 printf("DHCPOFFER chaddr: ");
651 }
602 652
603 for(x=0;x<ETHERNET_HARDWARE_ADDRESS_LENGTH;x++){ 653 for (int i = 0; i < ETHERNET_HARDWARE_ADDRESS_LENGTH; i++) {
604 if(verbose) 654 if (verbose) {
605 printf("%02X",(unsigned char)offer_packet.chaddr[x]); 655 printf("%02X", offer_packet.chaddr[i]);
656 }
606 657
607 if(offer_packet.chaddr[x]!=client_hardware_address[x]) 658 if (offer_packet.chaddr[i] != client_hardware_address[i]) {
608 result=ERROR; 659 result = ERROR;
660 }
609 } 661 }
610 if(verbose) 662 if (verbose) {
611 printf("\n"); 663 printf("\n");
664 }
612 665
613 if(result==ERROR){ 666 if (result == ERROR) {
614 if(verbose) 667 if (verbose) {
615 printf(_("DHCPOFFER hardware address did not match our own - ignoring packet\n")); 668 printf(_("DHCPOFFER hardware address did not match our own - ignoring packet\n"));
669 }
616 670
617 continue; 671 continue;
618 } 672 }
619 673
620 if(verbose){ 674 if (verbose) {
621 printf("DHCPOFFER ciaddr: %s\n",inet_ntoa(offer_packet.ciaddr)); 675 printf("DHCPOFFER ciaddr: %s\n", inet_ntoa(offer_packet.ciaddr));
622 printf("DHCPOFFER yiaddr: %s\n",inet_ntoa(offer_packet.yiaddr)); 676 printf("DHCPOFFER yiaddr: %s\n", inet_ntoa(offer_packet.yiaddr));
623 printf("DHCPOFFER siaddr: %s\n",inet_ntoa(offer_packet.siaddr)); 677 printf("DHCPOFFER siaddr: %s\n", inet_ntoa(offer_packet.siaddr));
624 printf("DHCPOFFER giaddr: %s\n",inet_ntoa(offer_packet.giaddr)); 678 printf("DHCPOFFER giaddr: %s\n", inet_ntoa(offer_packet.giaddr));
625 } 679 }
626 680
627 add_dhcp_offer(source.sin_addr,&offer_packet); 681 add_dhcp_offer_wrapper add_res =
682 add_dhcp_offer(source.sin_addr, &offer_packet, dhcp_offer_list);
683 if (add_res.error != OK) {
684 // TODO
685 } else {
686 dhcp_offer_list = add_res.dhcp_offer_list;
687 }
628 688
629 valid_responses++; 689 valid_responses++;
630 } 690 }
631 691
632 if(verbose){ 692 if (verbose) {
633 printf(_("Total responses seen on the wire: %d\n"),responses); 693 printf(_("Total responses seen on the wire: %d\n"), responses);
634 printf(_("Valid responses for this machine: %d\n"),valid_responses); 694 printf(_("Valid responses for this machine: %d\n"), valid_responses);
635 } 695 }
636 696
637 return OK; 697 get_dhcp_offer_wrapper ret_val = {
698 .error = OK,
699 .valid_responses = valid_responses,
700 .dhcp_offer_list = dhcp_offer_list,
701 };
702 return ret_val;
638} 703}
639 704
640
641
642/* sends a DHCP packet */ 705/* sends a DHCP packet */
643int send_dhcp_packet(void *buffer, int buffer_size, int sock, struct sockaddr_in *dest){ 706int send_dhcp_packet(void *buffer, int buffer_size, int sock, struct sockaddr_in *dest) {
644 int result; 707 int result =
708 sendto(sock, (char *)buffer, buffer_size, 0, (struct sockaddr *)dest, sizeof(*dest));
645 709
646 result=sendto(sock,(char *)buffer,buffer_size,0,(struct sockaddr *)dest,sizeof(*dest)); 710 if (verbose) {
647 711 printf(_("send_dhcp_packet result: %d\n"), result);
648 if(verbose) 712 }
649 printf(_("send_dhcp_packet result: %d\n"),result);
650 713
651 if(result<0) 714 if (result < 0) {
652 return ERROR; 715 return ERROR;
716 }
653 717
654 return OK; 718 return OK;
655} 719}
656 720
657
658
659/* receives a DHCP packet */ 721/* receives a DHCP packet */
660int receive_dhcp_packet(void *buffer, int buffer_size, int sock, int timeout, struct sockaddr_in *address){ 722int receive_dhcp_packet(void *buffer, int buffer_size, int sock, int timeout,
661 struct timeval tv; 723 struct sockaddr_in *address) {
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) */ 724 /* wait for data to arrive (up time timeout) */
671 tv.tv_sec=timeout; 725 struct timeval timeout_val = {
672 tv.tv_usec=0; 726 .tv_sec = timeout,
727 .tv_usec = 0,
728 };
729 fd_set readfds;
673 FD_ZERO(&readfds); 730 FD_ZERO(&readfds);
731 fd_set oobfds;
674 FD_ZERO(&oobfds); 732 FD_ZERO(&oobfds);
675 FD_SET(sock,&readfds); 733 FD_SET(sock, &readfds);
676 FD_SET(sock,&oobfds); 734 FD_SET(sock, &oobfds);
677 nfound = select(sock+1,&readfds,NULL,&oobfds,&tv); 735 int nfound = select(sock + 1, &readfds, NULL, &oobfds, &timeout_val);
678 736
679 /* make sure some data has arrived */ 737 /* make sure some data has arrived */
680 if(!FD_ISSET(sock,&readfds)){ 738 if (!FD_ISSET(sock, &readfds)) {
681 if(verbose) 739 if (verbose) {
682 printf(_("No (more) data received (nfound: %d)\n"), nfound); 740 printf(_("No (more) data received (nfound: %d)\n"), nfound);
741 }
683 return ERROR; 742 return ERROR;
684 } 743 }
685 744
686 else{ 745 struct sockaddr_in source_address = {0};
687 bzero(&source_address,sizeof(source_address)); 746 socklen_t address_size = sizeof(source_address);
688 address_size=sizeof(source_address); 747 int recv_result = recvfrom(sock, (char *)buffer, buffer_size, 0,
689 recv_result=recvfrom(sock,(char *)buffer,buffer_size,0,(struct sockaddr *)&source_address,&address_size); 748 (struct sockaddr *)&source_address, &address_size);
690 if(verbose) 749 if (verbose) {
691 printf("recv_result: %d\n",recv_result); 750 printf("recv_result: %d\n", recv_result);
692 751 }
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 752
706 memcpy(address,&source_address,sizeof(source_address)); 753 if (recv_result == -1) {
707 return OK; 754 if (verbose) {
755 printf(_("recvfrom() failed, "));
756 printf("errno: (%d) -> %s\n", errno, strerror(errno));
708 } 757 }
758 return ERROR;
759 }
760 if (verbose) {
761 printf(_("receive_dhcp_packet() result: %d\n"), recv_result);
762 printf(_("receive_dhcp_packet() source: %s\n"), inet_ntoa(source_address.sin_addr));
709 } 763 }
710 764
765 memcpy(address, &source_address, sizeof(source_address));
711 return OK; 766 return OK;
712} 767}
713 768
714
715/* creates a socket for DHCP communication */ 769/* creates a socket for DHCP communication */
716int create_dhcp_socket(void){ 770int 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. */ 771 /* 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 */ 772 /* listen to DHCP server port if we're in unicast mode */
726 myname.sin_port = htons(unicast ? DHCP_SERVER_PORT : DHCP_CLIENT_PORT); 773 struct sockaddr_in myname = {
727 myname.sin_addr.s_addr = unicast ? my_ip.s_addr : INADDR_ANY; 774 .sin_family = AF_INET,
728 bzero(&myname.sin_zero,sizeof(myname.sin_zero)); 775 .sin_port = htons(unicast ? DHCP_SERVER_PORT : DHCP_CLIENT_PORT),
776 // TODO previously the next line was trying to use our own IP, we was not set
777 // until some point later, so it was removed. Recheck whether it is actually
778 // necessary/useful
779 .sin_addr.s_addr = INADDR_ANY,
780 };
729 781
730 /* create a socket for DHCP communications */ 782 /* create a socket for DHCP communications */
731 sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); 783 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
732 if(sock<0){ 784 if (sock < 0) {
733 printf(_("Error: Could not create socket!\n")); 785 printf(_("Error: Could not create socket!\n"));
734 exit(STATE_UNKNOWN); 786 exit(STATE_UNKNOWN);
735 } 787 }
736 788
737 if(verbose) 789 if (verbose) {
738 printf("DHCP socket: %d\n",sock); 790 printf("DHCP socket: %d\n", sock);
791 }
739 792
740 /* set the reuse address flag so we don't get errors when restarting */ 793 /* set the reuse address flag so we don't get errors when restarting */
741 flag=1; 794 int flag = 1;
742 if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&flag,sizeof(flag))<0){ 795 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof(flag)) < 0) {
743 printf(_("Error: Could not set reuse address option on DHCP socket!\n")); 796 printf(_("Error: Could not set reuse address option on DHCP socket!\n"));
744 exit(STATE_UNKNOWN); 797 exit(STATE_UNKNOWN);
745 } 798 }
746 799
747 /* set the broadcast option - we need this to listen to DHCP broadcast messages */ 800 /* 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){ 801 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")); 802 printf(_("Error: Could not set broadcast option on DHCP socket!\n"));
750 exit(STATE_UNKNOWN); 803 exit(STATE_UNKNOWN);
751 } 804 }
752 805
806 struct ifreq interface;
753 /* bind socket to interface */ 807 /* bind socket to interface */
754#if defined(__linux__) 808#if defined(__linux__)
755 strncpy(interface.ifr_ifrn.ifrn_name,network_interface_name,IFNAMSIZ-1); 809 strncpy(interface.ifr_ifrn.ifrn_name, network_interface_name, IFNAMSIZ - 1);
756 interface.ifr_ifrn.ifrn_name[IFNAMSIZ-1]='\0'; 810 interface.ifr_ifrn.ifrn_name[IFNAMSIZ - 1] = '\0';
757 if(setsockopt(sock,SOL_SOCKET,SO_BINDTODEVICE,(char *)&interface,sizeof(interface))<0){ 811 if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (char *)&interface, sizeof(interface)) < 0) {
758 printf(_("Error: Could not bind socket to interface %s. Check your privileges...\n"),network_interface_name); 812 printf(_("Error: Could not bind socket to interface %s. Check your privileges...\n"),
813 network_interface_name);
759 exit(STATE_UNKNOWN); 814 exit(STATE_UNKNOWN);
760 } 815 }
761 816
762#else 817#else
763 strncpy(interface.ifr_name,network_interface_name,IFNAMSIZ-1); 818 strncpy(interface.ifr_name, network_interface_name, IFNAMSIZ - 1);
764 interface.ifr_name[IFNAMSIZ-1]='\0'; 819 interface.ifr_name[IFNAMSIZ - 1] = '\0';
765#endif 820#endif
766 821
767 /* bind the socket */ 822 /* bind the socket */
768 if(bind(sock,(struct sockaddr *)&myname,sizeof(myname))<0){ 823 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); 824 printf(_("Error: Could not bind to DHCP socket (port %d)! Check your privileges...\n"),
825 DHCP_CLIENT_PORT);
770 exit(STATE_UNKNOWN); 826 exit(STATE_UNKNOWN);
771 } 827 }
772 828
773 return sock; 829 return sock;
774} 830}
775 831
776
777/* closes DHCP socket */ 832/* closes DHCP socket */
778int close_dhcp_socket(int sock){ 833int close_dhcp_socket(int sock) {
779
780 close(sock); 834 close(sock);
781
782 return OK; 835 return OK;
783} 836}
784 837
785
786/* adds a requested server address to list in memory */ 838/* adds a requested server address to list in memory */
787int add_requested_server(struct in_addr server_address){ 839int add_requested_server(struct in_addr server_address, int *requested_servers,
788 requested_server *new_server; 840 requested_server **requested_server_list) {
789 841 requested_server *new_server = (requested_server *)malloc(sizeof(requested_server));
790 new_server=(requested_server *)malloc(sizeof(requested_server)); 842 if (new_server == NULL) {
791 if(new_server==NULL)
792 return ERROR; 843 return ERROR;
844 }
793 845
794 new_server->server_address=server_address; 846 new_server->server_address = server_address;
795 new_server->answered=false; 847 new_server->answered = false;
796 848
797 new_server->next=requested_server_list; 849 new_server->next = *requested_server_list;
798 requested_server_list=new_server; 850 *requested_server_list = new_server;
799 851
800 requested_servers++; 852 *requested_servers += 1;
801 853
802 if(verbose) 854 if (verbose) {
803 printf(_("Requested server address: %s\n"),inet_ntoa(new_server->server_address)); 855 printf(_("Requested server address: %s\n"), inet_ntoa(new_server->server_address));
856 }
804 857
805 return OK; 858 return OK;
806} 859}
807 860
808
809
810
811/* adds a DHCP OFFER to list in memory */ 861/* adds a DHCP OFFER to list in memory */
812int add_dhcp_offer(struct in_addr source,dhcp_packet *offer_packet){ 862add_dhcp_offer_wrapper add_dhcp_offer(struct in_addr source, dhcp_packet *offer_packet,
863 dhcp_offer *dhcp_offer_list) {
864 if (offer_packet == NULL) {
865 add_dhcp_offer_wrapper tmp = {
866 .error = ERROR,
867 };
868 return tmp;
869 }
870
871 uint32_t dhcp_lease_time = 0;
872 uint32_t dhcp_renewal_time = 0;
873 uint32_t dhcp_rebinding_time = 0;
813 dhcp_offer *new_offer; 874 dhcp_offer *new_offer;
814 int x;
815 unsigned option_type;
816 unsigned option_length;
817 struct in_addr serv_ident = {0}; 875 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 */ 876 /* process all DHCP options present in the packet */
823 for(x=4;x<MAX_DHCP_OPTIONS_LENGTH-1;){ 877 for (int dchp_opt_idx = 4; dchp_opt_idx < MAX_DHCP_OPTIONS_LENGTH - 1;) {
824 878
825 if((int)offer_packet->options[x]==-1) 879 if ((int)offer_packet->options[dchp_opt_idx] == -1) {
826 break; 880 break;
881 }
827 882
828 /* get option type */ 883 /* get option type */
829 option_type=offer_packet->options[x++]; 884 unsigned option_type = offer_packet->options[dchp_opt_idx++];
830 885
831 /* get option length */ 886 /* get option length */
832 option_length=offer_packet->options[x++]; 887 unsigned option_length = offer_packet->options[dchp_opt_idx++];
833 888
834 if(verbose) 889 if (verbose) {
835 printf("Option: %d (0x%02X)\n",option_type,option_length); 890 printf("Option: %d (0x%02X)\n", option_type, option_length);
891 }
836 892
837 /* get option data */ 893 /* get option data */
838 switch(option_type){ 894 switch (option_type) {
839 case DHCP_OPTION_LEASE_TIME: 895 case DHCP_OPTION_LEASE_TIME:
840 memcpy(&dhcp_lease_time, &offer_packet->options[x],sizeof(dhcp_lease_time)); 896 memcpy(&dhcp_lease_time, &offer_packet->options[dchp_opt_idx], sizeof(dhcp_lease_time));
841 dhcp_lease_time = ntohl(dhcp_lease_time); 897 dhcp_lease_time = ntohl(dhcp_lease_time);
842 break; 898 break;
843 case DHCP_OPTION_RENEWAL_TIME: 899 case DHCP_OPTION_RENEWAL_TIME:
844 memcpy(&dhcp_renewal_time, &offer_packet->options[x],sizeof(dhcp_renewal_time)); 900 memcpy(&dhcp_renewal_time, &offer_packet->options[dchp_opt_idx],
845 dhcp_renewal_time = ntohl(dhcp_renewal_time); 901 sizeof(dhcp_renewal_time));
846 break; 902 dhcp_renewal_time = ntohl(dhcp_renewal_time);
847 case DHCP_OPTION_REBINDING_TIME: 903 break;
848 memcpy(&dhcp_rebinding_time, &offer_packet->options[x],sizeof(dhcp_rebinding_time)); 904 case DHCP_OPTION_REBINDING_TIME:
849 dhcp_rebinding_time = ntohl(dhcp_rebinding_time); 905 memcpy(&dhcp_rebinding_time, &offer_packet->options[dchp_opt_idx],
850 break; 906 sizeof(dhcp_rebinding_time));
851 case DHCP_OPTION_SERVER_IDENTIFIER: 907 dhcp_rebinding_time = ntohl(dhcp_rebinding_time);
852 memcpy(&serv_ident.s_addr, &offer_packet->options[x],sizeof(serv_ident.s_addr)); 908 break;
853 break; 909 case DHCP_OPTION_SERVER_IDENTIFIER:
910 memcpy(&serv_ident.s_addr, &offer_packet->options[dchp_opt_idx],
911 sizeof(serv_ident.s_addr));
912 break;
854 } 913 }
855 914
856 /* skip option data we're ignoring */ 915 /* skip option data we're ignoring */
857 if(option_type==0) /* "pad" option, see RFC 2132 (3.1) */ 916 if (option_type == 0) { /* "pad" option, see RFC 2132 (3.1) */
858 x+=1; 917 dchp_opt_idx += 1;
859 else 918 } else {
860 x+=option_length; 919 dchp_opt_idx += option_length;
920 }
861 } 921 }
862 922
863 if(verbose){ 923 if (verbose) {
864 if(dhcp_lease_time==DHCP_INFINITE_TIME) 924 if (dhcp_lease_time == DHCP_INFINITE_TIME) {
865 printf(_("Lease Time: Infinite\n")); 925 printf(_("Lease Time: Infinite\n"));
866 else 926 } else {
867 printf(_("Lease Time: %lu seconds\n"),(unsigned long)dhcp_lease_time); 927 printf(_("Lease Time: %lu seconds\n"), (unsigned long)dhcp_lease_time);
868 if(dhcp_renewal_time==DHCP_INFINITE_TIME) 928 }
929 if (dhcp_renewal_time == DHCP_INFINITE_TIME) {
869 printf(_("Renewal Time: Infinite\n")); 930 printf(_("Renewal Time: Infinite\n"));
870 else 931 } else {
871 printf(_("Renewal Time: %lu seconds\n"),(unsigned long)dhcp_renewal_time); 932 printf(_("Renewal Time: %lu seconds\n"), (unsigned long)dhcp_renewal_time);
872 if(dhcp_rebinding_time==DHCP_INFINITE_TIME) 933 }
934 if (dhcp_rebinding_time == DHCP_INFINITE_TIME) {
873 printf(_("Rebinding Time: Infinite\n")); 935 printf(_("Rebinding Time: Infinite\n"));
874 printf(_("Rebinding Time: %lu seconds\n"),(unsigned long)dhcp_rebinding_time); 936 }
937 printf(_("Rebinding Time: %lu seconds\n"), (unsigned long)dhcp_rebinding_time);
875 } 938 }
876 939
877 new_offer=(dhcp_offer *)malloc(sizeof(dhcp_offer)); 940 new_offer = (dhcp_offer *)malloc(sizeof(dhcp_offer));
878 941
879 if(new_offer==NULL) 942 if (new_offer == NULL) {
880 return ERROR; 943 add_dhcp_offer_wrapper tmp = {
944 .error = ERROR,
945 };
946 return tmp;
947 }
881 948
882 /* 949 /*
883 * RFC 2131 (2.) says: "DHCP clarifies the interpretation of the 950 * RFC 2131 (2.) says: "DHCP clarifies the interpretation of the
@@ -891,298 +958,358 @@ 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 958 * DHCPOFFER from. If 'serv_ident' isn't available for some reason, we
892 * use 'source'. 959 * use 'source'.
893 */ 960 */
894 new_offer->server_address=serv_ident.s_addr?serv_ident:source; 961 new_offer->server_address = serv_ident.s_addr ? serv_ident : source;
895 new_offer->offered_address=offer_packet->yiaddr; 962 new_offer->offered_address = offer_packet->yiaddr;
896 new_offer->lease_time=dhcp_lease_time; 963 new_offer->lease_time = dhcp_lease_time;
897 new_offer->renewal_time=dhcp_renewal_time; 964 new_offer->renewal_time = dhcp_renewal_time;
898 new_offer->rebinding_time=dhcp_rebinding_time; 965 new_offer->rebinding_time = dhcp_rebinding_time;
899 new_offer->desired=false; /* exclusive mode: we'll check that in get_results */ 966 new_offer->desired = false; /* exclusive mode: we'll check that in get_results */
900 967
901 968 if (verbose) {
902 if(verbose){ 969 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)); 970 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 } 971 }
906 972
907 /* add new offer to head of list */ 973 /* add new offer to head of list */
908 new_offer->next=dhcp_offer_list; 974 new_offer->next = dhcp_offer_list;
909 dhcp_offer_list=new_offer; 975 dhcp_offer_list = new_offer;
910 976
911 return OK; 977 add_dhcp_offer_wrapper result = {
912} 978 .error = OK,
979 .dhcp_offer_list = dhcp_offer_list,
980 };
913 981
982 return result;
983}
914 984
915/* frees memory allocated to DHCP OFFER list */ 985/* frees memory allocated to DHCP OFFER list */
916int free_dhcp_offer_list(void){ 986int free_dhcp_offer_list(dhcp_offer *dhcp_offer_list) {
917 dhcp_offer *this_offer;
918 dhcp_offer *next_offer; 987 dhcp_offer *next_offer;
919 988 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){ 989 next_offer = this_offer->next;
921 next_offer=this_offer->next;
922 free(this_offer); 990 free(this_offer);
923 } 991 }
924 992
925 return OK; 993 return OK;
926} 994}
927 995
928
929/* frees memory allocated to requested server list */ 996/* frees memory allocated to requested server list */
930int free_requested_server_list(void){ 997int free_requested_server_list(requested_server *requested_server_list) {
931 requested_server *this_server;
932 requested_server *next_server; 998 requested_server *next_server;
933 999 for (requested_server *this_server = requested_server_list; this_server != NULL;
934 for(this_server=requested_server_list;this_server!=NULL;this_server=next_server){ 1000 this_server = next_server) {
935 next_server=this_server->next; 1001 next_server = this_server->next;
936 free(this_server); 1002 free(this_server);
937 } 1003 }
938 1004
939 return OK; 1005 return OK;
940} 1006}
941 1007
942
943/* gets state and plugin output to return */ 1008/* gets state and plugin output to return */
944int get_results(void){ 1009mp_subcheck get_results(bool exclusive, const int requested_servers,
945 dhcp_offer *temp_offer, *undesired_offer=NULL; 1010 const struct in_addr requested_address, bool request_specific_address,
946 requested_server *temp_server; 1011 requested_server *requested_server_list, int valid_responses,
947 int result; 1012 dhcp_offer *dhcp_offer_list) {
948 uint32_t max_lease_time=0; 1013 mp_subcheck sc_dhcp_results = mp_subcheck_init();
1014 sc_dhcp_results = mp_set_subcheck_default_state(sc_dhcp_results, STATE_OK);
949 1015
950 received_requested_address=false; 1016 /* we didn't receive any DHCPOFFERs */
951 1017 if (dhcp_offer_list == NULL) {
952 /* checks responses from requested servers */ 1018 sc_dhcp_results = mp_set_subcheck_state(sc_dhcp_results, STATE_CRITICAL);
953 requested_responses=0; 1019 xasprintf(&sc_dhcp_results.output, "%s", "No DHCPOFFERs were received");
954 if(requested_servers>0){ 1020 return sc_dhcp_results;
1021 }
955 1022
956 for(temp_server=requested_server_list;temp_server!=NULL;temp_server=temp_server->next){ 1023 if (valid_responses == 0) {
1024 // No valid responses at all, so early exit here
1025 sc_dhcp_results = mp_set_subcheck_state(sc_dhcp_results, STATE_CRITICAL);
1026 xasprintf(&sc_dhcp_results.output, "No valid responses received");
1027 return sc_dhcp_results;
1028 }
957 1029
958 for(temp_offer=dhcp_offer_list;temp_offer!=NULL;temp_offer=temp_offer->next){ 1030 if (valid_responses == 1) {
1031 xasprintf(&sc_dhcp_results.output, "Received %d DHCPOFFER", valid_responses);
1032 } else {
1033 xasprintf(&sc_dhcp_results.output, "Received %d DHCPOFFERs", valid_responses);
1034 }
959 1035
1036 bool received_requested_address = false;
1037 dhcp_offer *undesired_offer = NULL;
1038 uint32_t max_lease_time = 0;
1039 /* checks responses from requested servers */
1040 int requested_responses = 0;
1041 if (requested_servers > 0) {
1042 for (requested_server *temp_server = requested_server_list; temp_server != NULL;
1043 temp_server = temp_server->next) {
1044 for (dhcp_offer *temp_offer = dhcp_offer_list; temp_offer != NULL;
1045 temp_offer = temp_offer->next) {
960 /* get max lease time we were offered */ 1046 /* get max lease time we were offered */
961 if(temp_offer->lease_time>max_lease_time || temp_offer->lease_time==DHCP_INFINITE_TIME) 1047 if (temp_offer->lease_time > max_lease_time ||
962 max_lease_time=temp_offer->lease_time; 1048 temp_offer->lease_time == DHCP_INFINITE_TIME) {
1049 max_lease_time = temp_offer->lease_time;
1050 }
963 1051
964 /* see if we got the address we requested */ 1052 /* see if we got the address we requested */
965 if(!memcmp(&requested_address,&temp_offer->offered_address,sizeof(requested_address))) 1053 if (!memcmp(&requested_address, &temp_offer->offered_address,
966 received_requested_address=true; 1054 sizeof(requested_address))) {
967 1055 received_requested_address = true;
968 /* see if the servers we wanted a response from talked to us or not */ 1056 }
969 if(!memcmp(&temp_offer->server_address,&temp_server->server_address,sizeof(temp_server->server_address))){ 1057
970 if(verbose){ 1058 /* see if the servers we wanted a response from, talked to us or not */
971 printf(_("DHCP Server Match: Offerer=%s"),inet_ntoa(temp_offer->server_address)); 1059 if (!memcmp(&temp_offer->server_address, &temp_server->server_address,
972 printf(_(" Requested=%s"),inet_ntoa(temp_server->server_address)); 1060 sizeof(temp_server->server_address))) {
973 if(temp_server->answered) 1061 if (verbose) {
1062 printf(_("DHCP Server Match: Offerer=%s"),
1063 inet_ntoa(temp_offer->server_address));
1064 printf(_(" Requested=%s"), inet_ntoa(temp_server->server_address));
1065 if (temp_server->answered) {
974 printf(_(" (duplicate)")); 1066 printf(_(" (duplicate)"));
1067 }
975 printf(_("\n")); 1068 printf(_("\n"));
976 } 1069 }
977 if(!temp_server->answered){ 1070
1071 if (!temp_server->answered) {
978 requested_responses++; 1072 requested_responses++;
979 temp_server->answered=true; 1073 temp_server->answered = true;
980 temp_offer->desired=true; 1074 temp_offer->desired = true;
981 } 1075 }
982 } 1076 }
983 } 1077 }
984 } 1078 }
985 1079
986 /* exclusive mode: check for undesired offers */ 1080 /* exclusive mode: check for undesired offers */
987 for(temp_offer=dhcp_offer_list;temp_offer!=NULL;temp_offer=temp_offer->next) { 1081 for (dhcp_offer *temp_offer = dhcp_offer_list; temp_offer != NULL;
1082 temp_offer = temp_offer->next) {
988 if (!temp_offer->desired) { 1083 if (!temp_offer->desired) {
989 undesired_offer=temp_offer; /* Checks only for the first undesired offer */ 1084 undesired_offer = temp_offer; /* Checks only for the first undesired offer */
990 break; /* no further checks needed */ 1085 break; /* no further checks needed */
991 } 1086 }
992 } 1087 }
993 }
994 1088
995 /* else check and see if we got our requested address from any server */ 1089 mp_subcheck sc_rqust_srvs = mp_subcheck_init();
996 else{ 1090 xasprintf(&sc_rqust_srvs.output, "%d of %d requested servers responded",
997 1091 requested_responses, requested_servers);
998 for(temp_offer=dhcp_offer_list;temp_offer!=NULL;temp_offer=temp_offer->next){ 1092
1093 if (requested_responses == requested_servers) {
1094 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_OK);
1095 } else if (requested_responses == 0) {
1096 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_CRITICAL);
1097 } else if (requested_responses < requested_servers) {
1098 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_WARNING);
1099 } else {
1100 // We received more(!) responses than we asked for?
1101 // This case shouldn't happen, but is here for completion
1102 sc_rqust_srvs = mp_set_subcheck_state(sc_rqust_srvs, STATE_WARNING);
1103 }
1104 mp_add_subcheck_to_subcheck(&sc_dhcp_results, sc_rqust_srvs);
999 1105
1106 } else {
1107 /* else check and see if we got our requested address from any server */
1108 for (dhcp_offer *temp_offer = dhcp_offer_list; temp_offer != NULL;
1109 temp_offer = temp_offer->next) {
1000 /* get max lease time we were offered */ 1110 /* get max lease time we were offered */
1001 if(temp_offer->lease_time>max_lease_time || temp_offer->lease_time==DHCP_INFINITE_TIME) 1111 if (temp_offer->lease_time > max_lease_time ||
1002 max_lease_time=temp_offer->lease_time; 1112 temp_offer->lease_time == DHCP_INFINITE_TIME) {
1113 max_lease_time = temp_offer->lease_time;
1114 }
1003 1115
1004 /* see if we got the address we requested */ 1116 /* see if we got the address we requested */
1005 if(!memcmp(&requested_address,&temp_offer->offered_address,sizeof(requested_address))) 1117 if (!memcmp(&requested_address, &temp_offer->offered_address,
1006 received_requested_address=true; 1118 sizeof(requested_address))) {
1119 received_requested_address = true;
1120 }
1007 } 1121 }
1008 } 1122 }
1009 1123
1010 result=STATE_OK; 1124 if (max_lease_time == DHCP_INFINITE_TIME) {
1011 if(valid_responses==0) 1125 xasprintf(&sc_dhcp_results.output, "%s, max lease time = Infinity", sc_dhcp_results.output);
1012 result=STATE_CRITICAL; 1126 } else {
1013 else if(requested_servers>0 && requested_responses==0) 1127 xasprintf(&sc_dhcp_results.output, "%s, max lease time = %" PRIu32 " seconds",
1014 result=STATE_CRITICAL; 1128 sc_dhcp_results.output, max_lease_time);
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 } 1129 }
1037 1130
1038 printf(_("Received %d DHCPOFFER(s)"),valid_responses); 1131 if (exclusive) {
1039 1132 mp_subcheck sc_rogue_server = mp_subcheck_init();
1040 1133
1041 if(exclusive && undesired_offer){ 1134 if (undesired_offer != NULL) {
1042 printf(_(", Rogue DHCP Server detected! Server %s"),inet_ntoa(undesired_offer->server_address)); 1135 // We wanted to get a DHCPOFFER exclusively from one machine, but another one
1043 printf(_(" offered %s \n"),inet_ntoa(undesired_offer->offered_address)); 1136 // sent one (too)
1044 return result; 1137 sc_rogue_server = mp_set_subcheck_state(sc_rogue_server, STATE_CRITICAL);
1045 }
1046 1138
1047 if(requested_servers>0) 1139 // Get the addresses for printout
1048 printf(_(", %s%d of %d requested servers responded"),((requested_responses<requested_servers) && requested_responses>0)?"only ":"",requested_responses,requested_servers); 1140 // 1.address of the sending server
1141 char server_address[INET_ADDRSTRLEN];
1142 const char *server_address_transformed = inet_ntop(
1143 AF_INET, &undesired_offer->server_address, server_address, sizeof(server_address));
1049 1144
1050 if(request_specific_address) 1145 if (server_address != server_address_transformed) {
1051 printf(_(", requested address (%s) was %soffered"),inet_ntoa(requested_address),(received_requested_address)?"":_("not ")); 1146 die(STATE_UNKNOWN, "inet_ntop failed");
1147 }
1052 1148
1053 printf(_(", max lease time = ")); 1149 // 2.address offered
1054 if(max_lease_time==DHCP_INFINITE_TIME) 1150 char offered_address[INET_ADDRSTRLEN];
1055 printf(_("Infinity")); 1151 const char *offered_address_transformed =
1056 else 1152 inet_ntop(AF_INET, &undesired_offer->offered_address, offered_address,
1057 printf("%lu sec",(unsigned long)max_lease_time); 1153 sizeof(offered_address));
1058 1154
1059 printf(".\n"); 1155 if (offered_address != offered_address_transformed) {
1156 die(STATE_UNKNOWN, "inet_ntop failed");
1157 }
1060 1158
1061 return result; 1159 xasprintf(&sc_rogue_server.output, "Rogue DHCP Server detected! Server %s offered %s",
1062} 1160 server_address, offered_address);
1161 } else {
1162 sc_rogue_server = mp_set_subcheck_state(sc_rogue_server, STATE_OK);
1163 xasprintf(&sc_rogue_server.output, "No Rogue DHCP Server detected");
1164 }
1165 mp_add_subcheck_to_subcheck(&sc_dhcp_results, sc_rogue_server);
1166 }
1063 1167
1168 if (request_specific_address) {
1169 mp_subcheck sc_rqustd_addr = mp_subcheck_init();
1170
1171 if (received_requested_address) {
1172 sc_rqustd_addr = mp_set_subcheck_state(sc_rqustd_addr, STATE_OK);
1173 xasprintf(&sc_rqustd_addr.output, "Requested address (%s) was offered",
1174 inet_ntoa(requested_address));
1175 } else {
1176 sc_rqustd_addr = mp_set_subcheck_state(sc_rqustd_addr, STATE_WARNING);
1177 xasprintf(&sc_rqustd_addr.output, "Requested address (%s) was NOT offered",
1178 inet_ntoa(requested_address));
1179 }
1064 1180
1065/* process command-line arguments */ 1181 mp_add_subcheck_to_subcheck(&sc_dhcp_results, sc_rqustd_addr);
1066int process_arguments(int argc, char **argv){ 1182 }
1067 if(argc<1)
1068 return ERROR;
1069 1183
1070 call_getopt(argc,argv); 1184 return sc_dhcp_results;
1071 return validate_arguments(argc);
1072} 1185}
1073 1186
1187/* process command-line arguments */
1188process_arguments_wrapper process_arguments(int argc, char **argv) {
1189 if (argc < 1) {
1190 process_arguments_wrapper tmp = {
1191 .error = ERROR,
1192 };
1193 return tmp;
1194 }
1074 1195
1075 1196 enum {
1076int call_getopt(int argc, char **argv){ 1197 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 }; 1198 };
1093 1199
1094 int c=0; 1200 int option_index = 0;
1095 while(true){ 1201 static struct option long_options[] = {
1096 c=getopt_long(argc,argv,"+hVvxt:s:r:t:i:m:u",long_options,&option_index); 1202 {"serverip", required_argument, 0, 's'},
1097 1203 {"requestedip", required_argument, 0, 'r'},
1098 if(c==-1||c==EOF||c==1) 1204 {"timeout", required_argument, 0, 't'},
1205 {"interface", required_argument, 0, 'i'},
1206 {"mac", required_argument, 0, 'm'},
1207 {"unicast", no_argument, 0, 'u'},
1208 {"exclusive", no_argument, 0, 'x'},
1209 {"verbose", no_argument, 0, 'v'},
1210 {"version", no_argument, 0, 'V'},
1211 {"help", no_argument, 0, 'h'},
1212 {"output-format", required_argument, 0, output_format_index},
1213 {0, 0, 0, 0}};
1214
1215 check_dhcp_config config = check_dhcp_config_init();
1216 int option_char = 0;
1217 while (true) {
1218 option_char = getopt_long(argc, argv, "+hVvxt:s:r:t:i:m:u", long_options, &option_index);
1219
1220 if (option_char == -1 || option_char == EOF || option_char == 1) {
1099 break; 1221 break;
1222 }
1100 1223
1101 switch(c){ 1224 switch (option_char) {
1102 1225 case 's': /* DHCP server address */
1103 case 's': /* DHCP server address */ 1226 resolve_host(optarg, &config.dhcp_ip);
1104 resolve_host(optarg,&dhcp_ip); 1227 add_requested_server(config.dhcp_ip, &config.num_of_requested_servers,
1105 add_requested_server(dhcp_ip); 1228 &config.requested_server_list);
1106 break; 1229 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 1230
1126 case 'm': /* MAC address */ 1231 case 'r': /* address we are requested from DHCP servers */
1232 resolve_host(optarg, &config.requested_address);
1233 config.request_specific_address = true;
1234 break;
1127 1235
1128 if((user_specified_mac=mac_aton(optarg)) == NULL) 1236 case 't': /* timeout */
1129 usage("Cannot parse MAC address.\n"); 1237 if (atoi(optarg) > 0) {
1130 if(verbose) 1238 config.dhcpoffer_timeout = atoi(optarg);
1131 print_hardware_address(user_specified_mac); 1239 }
1240 break;
1132 1241
1133 break; 1242 case 'm': /* MAC address */
1243 if ((config.user_specified_mac = mac_aton(optarg)) == NULL) {
1244 usage("Cannot parse MAC address.\n");
1245 }
1246 if (verbose) {
1247 print_hardware_address(config.user_specified_mac);
1248 }
1249 break;
1134 1250
1135 case 'i': /* interface name */ 1251 case 'i': /* interface name */
1252 strncpy(config.network_interface_name, optarg,
1253 sizeof(config.network_interface_name) - 1);
1254 config.network_interface_name[sizeof(config.network_interface_name) - 1] = '\x0';
1255 break;
1136 1256
1137 strncpy(network_interface_name,optarg,sizeof(network_interface_name)-1); 1257 case 'u': /* unicast testing */
1138 network_interface_name[sizeof(network_interface_name)-1]='\x0'; 1258 config.unicast_mode = true;
1259 break;
1139 1260
1140 break; 1261 case 'x': /* exclusive testing aka "rogue DHCP server detection" */
1262 config.exclusive_mode = true;
1263 break;
1141 1264
1142 case 'u': /* unicast testing */ 1265 case 'V': /* version */
1143 unicast=true; 1266 print_revision(progname, NP_VERSION);
1144 break; 1267 exit(STATE_UNKNOWN);
1145 case 'x': /* exclusive testing aka "rogue DHCP server detection" */
1146 exclusive=true;
1147 break;
1148 1268
1149 case 'V': /* version */ 1269 case 'h': /* help */
1150 print_revision(progname, NP_VERSION); 1270 print_help();
1151 exit(STATE_UNKNOWN); 1271 exit(STATE_UNKNOWN);
1152 1272
1153 case 'h': /* help */ 1273 case 'v': /* verbose */
1154 print_help(); 1274 verbose = 1;
1275 break;
1276 case output_format_index: {
1277 parsed_output_format parser = mp_parse_output_format(optarg);
1278 if (!parser.parsing_success) {
1279 // TODO List all available formats here, maybe add anothoer usage function
1280 printf("Invalid output format: %s\n", optarg);
1155 exit(STATE_UNKNOWN); 1281 exit(STATE_UNKNOWN);
1282 }
1156 1283
1157 case 'v': /* verbose */ 1284 config.output_format_is_set = true;
1158 verbose=1; 1285 config.output_format = parser.output_format;
1159 break; 1286 break;
1160 case '?': /* help */ 1287 }
1161 usage5 (); 1288 case '?': /* help */
1162 break; 1289 usage5();
1290 break;
1163 1291
1164 default: 1292 default:
1165 break; 1293 break;
1166 } 1294 }
1167 } 1295 }
1168 return optind;
1169}
1170 1296
1171 1297 if (argc - optind > 0) {
1172int validate_arguments(int argc){
1173
1174 if(argc - optind > 0)
1175 usage(_("Got unexpected non-option argument")); 1298 usage(_("Got unexpected non-option argument"));
1299 }
1176 1300
1177 return OK; 1301 process_arguments_wrapper result = {
1302 .config = config,
1303 .error = OK,
1304 };
1305 return result;
1178} 1306}
1179 1307
1180
1181#if defined(__sun__) || defined(__solaris__) || defined(__hpux__) 1308#if defined(__sun__) || defined(__solaris__) || defined(__hpux__)
1182/* Kompf 2000-2003 see ACKNOWLEDGEMENTS */ 1309/* Kompf 2000-2003 see ACKNOWLEDGEMENTS */
1183 1310
1184/* get a message from a stream; return type of message */ 1311/* get a message from a stream; return type of message */
1185static int get_msg(int fd){ 1312static int get_msg(int fd) {
1186 int flags = 0; 1313 int flags = 0;
1187 int res, ret; 1314 int res, ret;
1188 ctl_area[0] = 0; 1315 ctl_area[0] = 0;
@@ -1190,30 +1317,29 @@ static int get_msg(int fd){
1190 ret = 0; 1317 ret = 0;
1191 res = getmsg(fd, &ctl, &dat, &flags); 1318 res = getmsg(fd, &ctl, &dat, &flags);
1192 1319
1193 if(res < 0){ 1320 if (res < 0) {
1194 if(errno == EINTR){ 1321 if (errno == EINTR) {
1195 return(GOT_INTR); 1322 return (GOT_INTR);
1196 } 1323 } else {
1197 else{
1198 printf("%s\n", "get_msg FAILED."); 1324 printf("%s\n", "get_msg FAILED.");
1199 return(GOT_ERR); 1325 return (GOT_ERR);
1200 } 1326 }
1201 } 1327 }
1202 if(ctl.len > 0){ 1328 if (ctl.len > 0) {
1203 ret |= GOT_CTRL; 1329 ret |= GOT_CTRL;
1204 } 1330 }
1205 if(dat.len > 0){ 1331 if (dat.len > 0) {
1206 ret |= GOT_DATA; 1332 ret |= GOT_DATA;
1207 } 1333 }
1208 1334
1209 return(ret); 1335 return (ret);
1210} 1336}
1211 1337
1212/* verify that dl_primitive in ctl_area = prim */ 1338/* verify that dl_primitive in ctl_area = prim */
1213static int check_ctrl(int prim){ 1339static int check_ctrl(int prim) {
1214 dl_error_ack_t *err_ack = (dl_error_ack_t *)ctl_area; 1340 dl_error_ack_t *err_ack = (dl_error_ack_t *)ctl_area;
1215 1341
1216 if(err_ack->dl_primitive != prim){ 1342 if (err_ack->dl_primitive != prim) {
1217 printf(_("Error: DLPI stream API failed to get MAC in check_ctrl: %s.\n"), strerror(errno)); 1343 printf(_("Error: DLPI stream API failed to get MAC in check_ctrl: %s.\n"), strerror(errno));
1218 exit(STATE_UNKNOWN); 1344 exit(STATE_UNKNOWN);
1219 } 1345 }
@@ -1222,36 +1348,39 @@ static int check_ctrl(int prim){
1222} 1348}
1223 1349
1224/* put a control message on a stream */ 1350/* put a control message on a stream */
1225static int put_ctrl(int fd, int len, int pri){ 1351static int put_ctrl(int fd, int len, int pri) {
1226 1352
1227 ctl.len = len; 1353 ctl.len = len;
1228 if(putmsg(fd, &ctl, 0, pri) < 0){ 1354 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)); 1355 printf(_("Error: DLPI stream API failed to get MAC in put_ctrl/putmsg(): %s.\n"),
1356 strerror(errno));
1230 exit(STATE_UNKNOWN); 1357 exit(STATE_UNKNOWN);
1231 } 1358 }
1232 1359
1233 return 0; 1360 return 0;
1234} 1361}
1235 1362
1236/* put a control + data message on a stream */ 1363/* put a control + data message on a stream */
1237static int put_both(int fd, int clen, int dlen, int pri){ 1364static int put_both(int fd, int clen, int dlen, int pri) {
1238 1365
1239 ctl.len = clen; 1366 ctl.len = clen;
1240 dat.len = dlen; 1367 dat.len = dlen;
1241 if(putmsg(fd, &ctl, &dat, pri) < 0){ 1368 if (putmsg(fd, &ctl, &dat, pri) < 0) {
1242 printf(_("Error: DLPI stream API failed to get MAC in put_both/putmsg().\n"), strerror(errno)); 1369 printf(_("Error: DLPI stream API failed to get MAC in put_both/putmsg().\n"),
1370 strerror(errno));
1243 exit(STATE_UNKNOWN); 1371 exit(STATE_UNKNOWN);
1244 } 1372 }
1245 1373
1246 return 0; 1374 return 0;
1247} 1375}
1248 1376
1249/* open file descriptor and attach */ 1377/* open file descriptor and attach */
1250static int dl_open(const char *dev, int unit, int *fd){ 1378static int dl_open(const char *dev, int unit, int *fd) {
1251 dl_attach_req_t *attach_req = (dl_attach_req_t *)ctl_area; 1379 dl_attach_req_t *attach_req = (dl_attach_req_t *)ctl_area;
1252 1380
1253 if((*fd = open(dev, O_RDWR)) == -1){ 1381 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)); 1382 printf(_("Error: DLPI stream API failed to get MAC in dl_attach_req/open(%s..): %s.\n"),
1383 dev, strerror(errno));
1255 exit(STATE_UNKNOWN); 1384 exit(STATE_UNKNOWN);
1256 } 1385 }
1257 attach_req->dl_primitive = DL_ATTACH_REQ; 1386 attach_req->dl_primitive = DL_ATTACH_REQ;
@@ -1262,7 +1391,7 @@ static int dl_open(const char *dev, int unit, int *fd){
1262} 1391}
1263 1392
1264/* send DL_BIND_REQ */ 1393/* send DL_BIND_REQ */
1265static int dl_bind(int fd, int sap, u_char *addr){ 1394static int dl_bind(int fd, int sap, u_char *addr) {
1266 dl_bind_req_t *bind_req = (dl_bind_req_t *)ctl_area; 1395 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; 1396 dl_bind_ack_t *bind_ack = (dl_bind_ack_t *)ctl_area;
1268 1397
@@ -1274,12 +1403,12 @@ static int dl_bind(int fd, int sap, u_char *addr){
1274 bind_req->dl_xidtest_flg = 0; 1403 bind_req->dl_xidtest_flg = 0;
1275 put_ctrl(fd, sizeof(dl_bind_req_t), 0); 1404 put_ctrl(fd, sizeof(dl_bind_req_t), 0);
1276 get_msg(fd); 1405 get_msg(fd);
1277 if (GOT_ERR == check_ctrl(DL_BIND_ACK)){ 1406 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)); 1407 printf(_("Error: DLPI stream API failed to get MAC in dl_bind/check_ctrl(): %s.\n"),
1408 strerror(errno));
1279 exit(STATE_UNKNOWN); 1409 exit(STATE_UNKNOWN);
1280 } 1410 }
1281 bcopy((u_char *)bind_ack + bind_ack->dl_addr_offset, addr, 1411 bcopy((u_char *)bind_ack + bind_ack->dl_addr_offset, addr, bind_ack->dl_addr_length);
1282 bind_ack->dl_addr_length);
1283 1412
1284 return 0; 1413 return 0;
1285} 1414}
@@ -1296,13 +1425,13 @@ static int dl_bind(int fd, int sap, u_char *addr){
1296 * 1425 *
1297 ***********************************************************************/ 1426 ***********************************************************************/
1298 1427
1299long mac_addr_dlpi( const char *dev, int unit, u_char *addr){ 1428long mac_addr_dlpi(const char *dev, int unit, u_char *addr) {
1300 int fd; 1429 int fd;
1301 u_char mac_addr[25]; 1430 u_char mac_addr[25];
1302 1431
1303 if(GOT_ERR != dl_open(dev, unit, &fd)){ 1432 if (GOT_ERR != dl_open(dev, unit, &fd)) {
1304 if(GOT_ERR != dl_bind(fd, INSAP, mac_addr)){ 1433 if (GOT_ERR != dl_bind(fd, INSAP, mac_addr)) {
1305 bcopy( mac_addr, addr, 6); 1434 bcopy(mac_addr, addr, 6);
1306 return 0; 1435 return 0;
1307 } 1436 }
1308 } 1437 }
@@ -1314,99 +1443,94 @@ long mac_addr_dlpi( const char *dev, int unit, u_char *addr){
1314/* Kompf 2000-2003 */ 1443/* Kompf 2000-2003 */
1315#endif 1444#endif
1316 1445
1317
1318/* resolve host name or die (TODO: move this to netutils.c!) */ 1446/* resolve host name or die (TODO: move this to netutils.c!) */
1319void resolve_host(const char *in,struct in_addr *out){ 1447void resolve_host(const char *name, struct in_addr *out) {
1320 struct addrinfo hints, *ai; 1448 struct addrinfo hints = {
1449 .ai_family = PF_INET,
1450 };
1451 struct addrinfo *addr_info;
1321 1452
1322 memset(&hints,0,sizeof(hints)); 1453 if (getaddrinfo(name, NULL, &hints, &addr_info) != 0) {
1323 hints.ai_family=PF_INET; 1454 usage_va(_("Invalid hostname/address - %s"), optarg);
1324 if (getaddrinfo(in,NULL,&hints,&ai) != 0) 1455 }
1325 usage_va(_("Invalid hostname/address - %s"),optarg);
1326 1456
1327 memcpy(out,&((struct sockaddr_in *)ai->ai_addr)->sin_addr,sizeof(*out)); 1457 memcpy(out, &((struct sockaddr_in *)addr_info->ai_addr)->sin_addr, sizeof(*out));
1328 freeaddrinfo(ai); 1458 freeaddrinfo(addr_info);
1329} 1459}
1330 1460
1331
1332/* parse MAC address string, return 6 bytes (unterminated) or NULL */ 1461/* parse MAC address string, return 6 bytes (unterminated) or NULL */
1333unsigned char *mac_aton(const char *string){ 1462unsigned char *mac_aton(const char *string) {
1334 static unsigned char result[6]; 1463 static unsigned char result[MAC_ADDR_LEN];
1335 char tmp[3]; 1464 char tmp[3];
1336 unsigned i, j; 1465 unsigned byte_counter = 0;
1337 1466
1338 for(i=0, j=0; string[i] != '\0' && j < sizeof(result); i++){ 1467 for (int i = 0; string[i] != '\0' && byte_counter < sizeof(result); i++) {
1339 /* ignore ':' and any other non-hex character */ 1468 /* ignore ':' and any other non-hex character */
1340 if(!isxdigit(string[i]) || !isxdigit(string[i+1])) 1469 if (!isxdigit(string[i]) || !isxdigit(string[i + 1])) {
1341 continue; 1470 continue;
1342 tmp[0]=string[i]; 1471 }
1343 tmp[1]=string[i+1]; 1472 tmp[0] = string[i];
1344 tmp[2]='\0'; 1473 tmp[1] = string[i + 1];
1345 result[j]=strtol(tmp,(char **)NULL,16); 1474 tmp[2] = '\0';
1475 result[byte_counter] = strtol(tmp, (char **)NULL, 16);
1346 i++; 1476 i++;
1347 j++; 1477 byte_counter++;
1348 } 1478 }
1349 1479
1350 return (j==6) ? result : NULL; 1480 return (byte_counter == MAC_ADDR_LEN) ? result : NULL;
1351} 1481}
1352 1482
1353 1483void print_hardware_address(const unsigned char *address) {
1354void print_hardware_address(const unsigned char *address){
1355 int i;
1356 1484
1357 printf(_("Hardware address: ")); 1485 printf(_("Hardware address: "));
1358 for (i=0; i<5; i++) 1486 for (int addr_idx = 0; addr_idx < MAC_ADDR_LEN; addr_idx++) {
1359 printf("%2.2x:", address[i]); 1487 printf("%2.2x:", address[addr_idx]);
1360 printf("%2.2x", address[i]); 1488 }
1361 putchar('\n'); 1489 putchar('\n');
1362} 1490}
1363 1491
1364
1365/* print usage help */ 1492/* print usage help */
1366void print_help(void){ 1493void print_help(void) {
1367 1494
1368 print_revision(progname, NP_VERSION); 1495 print_revision(progname, NP_VERSION);
1369 1496
1370 printf("Copyright (c) 2001-2004 Ethan Galstad (nagios@nagios.org)\n"); 1497 printf("Copyright (c) 2001-2004 Ethan Galstad (nagios@nagios.org)\n");
1371 printf (COPYRIGHT, copyright, email); 1498 printf(COPYRIGHT, copyright, email);
1372 1499
1373 printf("%s\n", _("This plugin tests the availability of DHCP servers on a network.")); 1500 printf("%s\n", _("This plugin tests the availability of DHCP servers on a network."));
1374 1501
1375 printf ("\n\n"); 1502 printf("\n\n");
1376 1503
1377 print_usage(); 1504 print_usage();
1378 1505
1379 printf (UT_HELP_VRSN); 1506 printf(UT_HELP_VRSN);
1380 printf (UT_EXTRA_OPTS); 1507 printf(UT_EXTRA_OPTS);
1381 1508
1382 printf (UT_VERBOSE); 1509 printf(UT_OUTPUT_FORMAT);
1383 1510 printf(UT_VERBOSE);
1384 printf (" %s\n", "-s, --serverip=IPADDRESS"); 1511
1385 printf (" %s\n", _("IP address of DHCP server that we must hear from")); 1512 printf(" %s\n", "-s, --serverip=IPADDRESS");
1386 printf (" %s\n", "-r, --requestedip=IPADDRESS"); 1513 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")); 1514 printf(" %s\n", "-r, --requestedip=IPADDRESS");
1388 printf (" %s\n", "-t, --timeout=INTEGER"); 1515 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")); 1516 printf(" %s\n", "-t, --timeout=INTEGER");
1390 printf (" %s\n", "-i, --interface=STRING"); 1517 printf(" %s\n", _("Seconds to wait for DHCPOFFER before timeout occurs"));
1391 printf (" %s\n", _("Interface to to use for listening (i.e. eth0)")); 1518 printf(" %s\n", "-i, --interface=STRING");
1392 printf (" %s\n", "-m, --mac=STRING"); 1519 printf(" %s\n", _("Interface to to use for listening (i.e. eth0)"));
1393 printf (" %s\n", _("MAC address to use in the DHCP request")); 1520 printf(" %s\n", "-m, --mac=STRING");
1394 printf (" %s\n", "-u, --unicast"); 1521 printf(" %s\n", _("MAC address to use in the DHCP request"));
1395 printf (" %s\n", _("Unicast testing: mimic a DHCP relay, requires -s")); 1522 printf(" %s\n", "-u, --unicast");
1396 printf (" %s\n", "-x, --exclusive"); 1523 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")); 1524 printf(" %s\n", "-x, --exclusive");
1398 1525 printf(" %s\n",
1399 printf (UT_SUPPORT); 1526 _("Only requested DHCP server may response (rogue DHCP server detection), requires -s"));
1400 return; 1527
1528 printf(UT_SUPPORT);
1401} 1529}
1402 1530
1531void print_usage(void) {
1403 1532
1404void 1533 printf("%s\n", _("Usage:"));
1405print_usage(void){ 1534 printf(" %s [-v] [-u] [-x] [-s serverip] [-r requestedip] [-t timeout]\n", progname);
1406 1535 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} 1536}
diff --git a/plugins-root/check_dhcp.d/config.h b/plugins-root/check_dhcp.d/config.h
new file mode 100644
index 00000000..f189068b
--- /dev/null
+++ b/plugins-root/check_dhcp.d/config.h
@@ -0,0 +1,50 @@
1#pragma once
2
3#include "../../config.h"
4#include "../lib/states.h"
5#include <stdbool.h>
6#include <netinet/in.h>
7#include "net/if.h"
8#include "output.h"
9
10typedef struct requested_server_struct {
11 struct in_addr server_address;
12 bool answered;
13 struct requested_server_struct *next;
14} requested_server;
15
16typedef struct check_dhcp_config {
17 bool unicast_mode; /* unicast mode: mimic a DHCP relay */
18 bool exclusive_mode; /* exclusive mode aka "rogue DHCP server detection" */
19 int num_of_requested_servers;
20 struct in_addr dhcp_ip; /* server to query (if in unicast mode) */
21 struct in_addr requested_address;
22 bool request_specific_address;
23
24 int dhcpoffer_timeout;
25 unsigned char *user_specified_mac;
26 char network_interface_name[IFNAMSIZ];
27 requested_server *requested_server_list;
28
29 mp_output_format output_format;
30 bool output_format_is_set;
31} check_dhcp_config;
32
33check_dhcp_config check_dhcp_config_init(void) {
34 check_dhcp_config tmp = {
35 .unicast_mode = false,
36 .exclusive_mode = false,
37 .num_of_requested_servers = 0,
38 .dhcp_ip = {0},
39 .requested_address = {0},
40 .request_specific_address = false,
41
42 .dhcpoffer_timeout = 2,
43 .user_specified_mac = NULL,
44 .network_interface_name = "eth0",
45 .requested_server_list = NULL,
46
47 .output_format_is_set = false,
48 };
49 return tmp;
50}
diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c
index 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..1b96a392
--- /dev/null
+++ b/plugins-root/check_icmp.d/check_icmp_helpers.c
@@ -0,0 +1,134 @@
1#include "./config.h"
2#include <math.h>
3#include <netinet/in.h>
4#include <sys/socket.h>
5#include "./check_icmp_helpers.h"
6#include "../../plugins/netutils.h"
7
8// timeout as a global variable to make it available to the timeout handler
9unsigned int timeout = DEFAULT_TIMEOUT;
10
11check_icmp_config check_icmp_config_init() {
12 check_icmp_config tmp = {
13 .modes =
14 {
15 .order_mode = false,
16 .mos_mode = false,
17 .rta_mode = false,
18 .pl_mode = false,
19 .jitter_mode = false,
20 .score_mode = false,
21 },
22
23 .min_hosts_alive = -1,
24 .crit = {.pl = DEFAULT_CRIT_PL,
25 .rta = DEFAULT_CRIT_RTA,
26 .jitter = 50.0,
27 .mos = 3.0,
28 .score = 70.0},
29 .warn = {.pl = DEFAULT_WARN_PL,
30 .rta = DEFAULT_WARN_RTA,
31 .jitter = 40.0,
32 .mos = 3.5,
33 .score = 80.0},
34
35 .ttl = DEFAULT_TTL,
36 .icmp_data_size = DEFAULT_PING_DATA_SIZE,
37 .target_interval = 0,
38 .number_of_packets = DEFAULT_NUMBER_OF_PACKETS,
39
40 .source_ip = NULL,
41 .need_v4 = false,
42 .need_v6 = false,
43
44 .sender_id = 0,
45
46 .mode = MODE_RTA,
47
48 .number_of_targets = 0,
49 .targets = NULL,
50
51 .number_of_hosts = 0,
52 .hosts = NULL,
53
54 .output_format_is_set = false,
55 };
56 return tmp;
57}
58
59ping_target ping_target_init() {
60 ping_target tmp = {
61 .rtmin = INFINITY,
62
63 .jitter_min = INFINITY,
64
65 .found_out_of_order_packets = false,
66 };
67
68 return tmp;
69}
70
71check_icmp_state check_icmp_state_init() {
72 check_icmp_state tmp = {.icmp_sent = 0, .icmp_lost = 0, .icmp_recv = 0, .targets_down = 0};
73
74 return tmp;
75}
76
77ping_target_create_wrapper ping_target_create(struct sockaddr_storage address) {
78 ping_target_create_wrapper result = {
79 .errorcode = 0,
80 };
81
82 struct sockaddr_storage *tmp_addr = &address;
83
84 /* disregard obviously stupid addresses
85 * (I didn't find an ipv6 equivalent to INADDR_NONE) */
86 if (((tmp_addr->ss_family == AF_INET &&
87 (((struct sockaddr_in *)tmp_addr)->sin_addr.s_addr == INADDR_NONE ||
88 ((struct sockaddr_in *)tmp_addr)->sin_addr.s_addr == INADDR_ANY))) ||
89 (tmp_addr->ss_family == AF_INET6 &&
90 (((struct sockaddr_in6 *)tmp_addr)->sin6_addr.s6_addr == in6addr_any.s6_addr))) {
91 result.errorcode = 1;
92 return result;
93 }
94
95 /* add the fresh ip */
96 ping_target target = ping_target_init();
97
98 /* fill out the sockaddr_storage struct */
99 target.address = address;
100
101 result.host = target;
102
103 return result;
104}
105
106check_icmp_target_container check_icmp_target_container_init() {
107 check_icmp_target_container tmp = {
108 .name = NULL,
109 .number_of_targets = 0,
110 .target_list = NULL,
111 };
112 return tmp;
113}
114
115unsigned int ping_target_list_append(ping_target *list, ping_target *elem) {
116 if (elem == NULL || list == NULL) {
117 return 0;
118 }
119
120 while (list->next != NULL) {
121 list = list->next;
122 }
123
124 list->next = elem;
125
126 unsigned int result = 1;
127
128 while (elem->next != NULL) {
129 result++;
130 elem = elem->next;
131 }
132
133 return result;
134}
diff --git a/plugins-root/check_icmp.d/check_icmp_helpers.h b/plugins-root/check_icmp.d/check_icmp_helpers.h
new file mode 100644
index 00000000..dc6ea40b
--- /dev/null
+++ b/plugins-root/check_icmp.d/check_icmp_helpers.h
@@ -0,0 +1,68 @@
1#pragma once
2
3#include "../../lib/states.h"
4#include <netinet/in_systm.h>
5#include <netinet/in.h>
6#include <netinet/ip.h>
7#include <netinet/ip6.h>
8#include <netinet/ip_icmp.h>
9#include <netinet/icmp6.h>
10#include <arpa/inet.h>
11
12typedef struct ping_target {
13 unsigned short id; /* id in **table, and icmp pkts */
14 char *msg; /* icmp error message, if any */
15
16 struct sockaddr_storage address; /* the address of this host */
17 struct sockaddr_storage error_addr; /* stores address of error replies */
18 time_t time_waited; /* total time waited, in usecs */
19 unsigned int icmp_sent, icmp_recv, icmp_lost; /* counters */
20 unsigned char icmp_type, icmp_code; /* type and code from errors */
21 unsigned short flags; /* control/status flags */
22
23 double rtmax; /* max rtt */
24 double rtmin; /* min rtt */
25
26 double jitter; /* measured jitter */
27 double jitter_max; /* jitter rtt maximum */
28 double jitter_min; /* jitter rtt minimum */
29
30 time_t last_tdiff;
31 unsigned int last_icmp_seq; /* Last ICMP_SEQ to check out of order pkts */
32
33 bool found_out_of_order_packets;
34
35 struct ping_target *next;
36} ping_target;
37
38ping_target ping_target_init();
39
40typedef struct {
41 char *name;
42 ping_target *target_list;
43 unsigned int number_of_targets;
44} check_icmp_target_container;
45
46check_icmp_target_container check_icmp_target_container_init();
47
48typedef struct {
49 unsigned int icmp_sent;
50 unsigned int icmp_recv;
51 unsigned int icmp_lost;
52 unsigned short targets_down;
53} check_icmp_state;
54
55check_icmp_state check_icmp_state_init();
56
57typedef struct {
58 int errorcode;
59 ping_target host;
60} ping_target_create_wrapper;
61
62typedef struct {
63 int socket4;
64 int socket6;
65} check_icmp_socket_set;
66
67ping_target_create_wrapper ping_target_create(struct sockaddr_storage address);
68unsigned int ping_target_list_append(ping_target *list, ping_target *elem);
diff --git a/plugins-root/check_icmp.d/config.h b/plugins-root/check_icmp.d/config.h
new file mode 100644
index 00000000..be388d0a
--- /dev/null
+++ b/plugins-root/check_icmp.d/config.h
@@ -0,0 +1,115 @@
1#pragma once
2
3#include "../../config.h"
4#include "../../lib/states.h"
5#include <stddef.h>
6#include <netinet/in_systm.h>
7#include <netinet/in.h>
8#include <netinet/ip.h>
9#include <netinet/ip6.h>
10#include <netinet/ip_icmp.h>
11#include <netinet/icmp6.h>
12#include <arpa/inet.h>
13#include <stdint.h>
14#include "./check_icmp_helpers.h"
15#include "output.h"
16
17/* threshold structure. all values are maximum allowed, exclusive */
18typedef struct {
19 unsigned char pl; /* max allowed packet loss in percent */
20 time_t rta; /* roundtrip time average, microseconds */
21 double jitter; /* jitter time average, microseconds */
22 double mos; /* MOS */
23 double score; /* Score */
24} check_icmp_threshold;
25
26/* the different modes of this program are as follows:
27 * MODE_RTA: send all packets no matter what (mimic check_icmp and check_ping)
28 * MODE_HOSTCHECK: Return immediately upon any sign of life
29 * In addition, sends packets to ALL addresses assigned
30 * to this host (as returned by gethostbyname() or
31 * gethostbyaddr() and expects one host only to be checked at
32 * a time. Therefore, any packet response what so ever will
33 * count as a sign of life, even when received outside
34 * crit.rta limit. Do not misspell any additional IP's.
35 * MODE_ALL: Requires packets from ALL requested IP to return OK (default).
36 * MODE_ICMP: Default Mode
37 */
38typedef enum {
39 MODE_RTA,
40 MODE_HOSTCHECK,
41 MODE_ALL,
42 MODE_ICMP,
43} check_icmp_execution_mode;
44
45typedef struct {
46 bool order_mode;
47 bool mos_mode;
48 bool rta_mode;
49 bool pl_mode;
50 bool jitter_mode;
51 bool score_mode;
52} check_icmp_mode_switches;
53
54typedef struct {
55 check_icmp_mode_switches modes;
56
57 int min_hosts_alive;
58 check_icmp_threshold crit;
59 check_icmp_threshold warn;
60
61 unsigned long ttl;
62 unsigned short icmp_data_size;
63 time_t target_interval;
64 unsigned short number_of_packets;
65
66 char *source_ip;
67 bool need_v4;
68 bool need_v6;
69
70 uint16_t sender_id; // PID of the main process, which is used as an ID in packets
71
72 check_icmp_execution_mode mode;
73
74 unsigned short number_of_targets;
75 ping_target *targets;
76
77 unsigned short number_of_hosts;
78 check_icmp_target_container *hosts;
79
80 mp_output_format output_format;
81 bool output_format_is_set;
82} check_icmp_config;
83
84check_icmp_config check_icmp_config_init();
85
86/* the data structure */
87typedef struct icmp_ping_data {
88 struct timeval stime; /* timestamp (saved in protocol struct as well) */
89 unsigned short ping_id;
90} icmp_ping_data;
91
92#define MAX_IP_PKT_SIZE 65536 /* (theoretical) max IP packet size */
93#define IP_HDR_SIZE 20
94#define MAX_PING_DATA (MAX_IP_PKT_SIZE - IP_HDR_SIZE - ICMP_MINLEN)
95#define MIN_PING_DATA_SIZE sizeof(struct icmp_ping_data)
96#define DEFAULT_PING_DATA_SIZE (MIN_PING_DATA_SIZE + 44)
97
98/* 80 msec packet interval by default */
99// DEPRECATED, remove when removing the option
100#define DEFAULT_PKT_INTERVAL 80000
101
102#define DEFAULT_TARGET_INTERVAL 0
103
104#define DEFAULT_WARN_RTA 200000
105#define DEFAULT_CRIT_RTA 500000
106#define DEFAULT_WARN_PL 40
107#define DEFAULT_CRIT_PL 80
108
109#define DEFAULT_TIMEOUT 10
110#define DEFAULT_TTL 64
111
112#define DEFAULT_NUMBER_OF_PACKETS 5
113
114#define PACKET_BACKOFF_FACTOR 1.5
115#define TARGET_BACKOFF_FACTOR 1.5
diff --git a/plugins-root/pst3.c b/plugins-root/pst3.c
index 1f69f3a6..1bfe3d35 100644
--- a/plugins-root/pst3.c
+++ b/plugins-root/pst3.c
@@ -1,45 +1,45 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* pst3 3 * pst3
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2008 Monitoring Plugins Development Team 6 * Copyright (c) 2008 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the pst3 executable. This is a replacement ps command 10 * This file contains the pst3 executable. This is a replacement ps command
11* for Solaris to get output which provides a long argument listing, which 11 * for Solaris to get output which provides a long argument listing, which
12* is not possible with the standard ps command (due to truncation). /usr/ucb/ps 12 * is not possible with the standard ps command (due to truncation). /usr/ucb/ps
13* also has issues where some fields run into each other. 13 * also has issues where some fields run into each other.
14* 14 *
15* This executable works by reading process address structures, so needs 15 * This executable works by reading process address structures, so needs
16* to be executed as root 16 * to be executed as root
17* 17 *
18* Originally written by R.W.Ingraham 18 * Originally written by R.W.Ingraham
19* Rewritten by Duncan Ferguson (Altinity Ltd, June 2008) 19 * Rewritten by Duncan Ferguson (Altinity Ltd, June 2008)
20* The rewrite was necessary as /dev/kmem is not available within 20 * The rewrite was necessary as /dev/kmem is not available within
21* non-global zones on Solaris 10 21 * non-global zones on Solaris 10
22* 22 *
23* Details for rewrite came from 23 * Details for rewrite came from
24* source of /usr/ucb/ps on Solaris: 24 * source of /usr/ucb/ps on Solaris:
25* http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/ucbcmd/ps/ps.c#argvoff 25 * http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/ucbcmd/ps/ps.c#argvoff
26* usenet group posting 26 * usenet group posting
27* http://groups.google.com/group/comp.unix.solaris/tree/browse_frm/month/2001-09/bfa40c08bac819a2?rnum=141&_done=%2Fgroup%2Fcomp.unix.solaris%2Fbrowse_frm%2Fmonth%2F2001-09%3F 27 * http://groups.google.com/group/comp.unix.solaris/tree/browse_frm/month/2001-09/bfa40c08bac819a2?rnum=141&_done=%2Fgroup%2Fcomp.unix.solaris%2Fbrowse_frm%2Fmonth%2F2001-09%3F
28* 28 *
29* This program is free software: you can redistribute it and/or modify 29 * This program is free software: you can redistribute it and/or modify
30* it under the terms of the GNU General Public License as published by 30 * it under the terms of the GNU General Public License as published by
31* the Free Software Foundation, either version 3 of the License, or 31 * the Free Software Foundation, either version 3 of the License, or
32* (at your option) any later version. 32 * (at your option) any later version.
33* 33 *
34* This program is distributed in the hope that it will be useful, 34 * This program is distributed in the hope that it will be useful,
35* but WITHOUT ANY WARRANTY; without even the implied warranty of 35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37* GNU General Public License for more details. 37 * GNU General Public License for more details.
38* 38 *
39* You should have received a copy of the GNU General Public License 39 * You should have received a copy of the GNU General Public License
40* along with this program. If not, see <http://www.gnu.org/licenses/>. 40 * along with this program. If not, see <http://www.gnu.org/licenses/>.
41* 41 *
42*****************************************************************************/ 42 *****************************************************************************/
43 43
44#include <stdio.h> 44#include <stdio.h>
45#include <stdlib.h> 45#include <stdlib.h>
@@ -55,14 +55,14 @@
55 * Constants 55 * Constants
56 */ 56 */
57 57
58#define PROC_DIR "/proc" 58#define PROC_DIR "/proc"
59#define ARGS 30 59#define ARGS 30
60 60
61/* 61/*
62 * Globals 62 * Globals
63 */ 63 */
64 64
65static char * szProg; 65static char *szProg;
66 66
67/* 67/*
68 * Prototypes 68 * Prototypes
@@ -71,192 +71,179 @@ void usage();
71 71
72/*----------------------------------------------------------------------------*/ 72/*----------------------------------------------------------------------------*/
73 73
74int main (int argc, char **argv) 74int main(int argc, char **argv) {
75{ 75 DIR *procdir;
76 DIR *procdir; 76 struct dirent *proc;
77 struct dirent *proc; 77 char ps_name[ARGS];
78 char ps_name[ARGS]; 78 char as_name[ARGS];
79 char as_name[ARGS]; 79 psinfo_t psinfo;
80 psinfo_t psinfo; 80
81 81 /* Set our program name global */
82 /* Set our program name global */ 82 if ((szProg = strrchr(argv[0], '/')) != NULL) {
83 if ((szProg = strrchr(argv[0], '/')) != NULL) 83 szProg++;
84 szProg++; 84 } else {
85 else 85 szProg = argv[0];
86 szProg = argv[0]; 86 }
87 87
88 /* if given any parameters, print out help */ 88 /* if given any parameters, print out help */
89 if(argc > 1) { 89 if (argc > 1) {
90 (void)usage(); 90 (void)usage();
91 exit(1); 91 exit(1);
92 } 92 }
93 93
94 /* Make sure that our euid is root */ 94 /* Make sure that our euid is root */
95 if (geteuid() != 0) 95 if (geteuid() != 0) {
96 { 96 fprintf(stderr, "%s: This program can only be run by the root user!\n", szProg);
97 fprintf(stderr, "%s: This program can only be run by the root user!\n", szProg); 97 exit(1);
98 exit(1); 98 }
99 } 99
100 100 if ((procdir = opendir(PROC_DIR)) == NULL) {
101 if ((procdir = opendir(PROC_DIR)) == NULL) { 101 fprintf(stderr, "%s: cannot open PROC directory %s\n", szProg, PROC_DIR);
102 fprintf(stderr, "%s: cannot open PROC directory %s\n", szProg, PROC_DIR); 102 exit(1);
103 exit(1); 103 }
104 } 104
105 105 /* Display column headings */
106 /* Display column headings */ 106 printf("%c %5s %5s %5s %6s %6s %4s %s %s\n", 'S', "UID", "PID", "PPID", "VSZ", "RSS", "%CPU",
107 printf("%c %5s %5s %5s %6s %6s %4s %s %s\n", 107 "COMMAND", "ARGS");
108 'S', 108
109 "UID", 109 /* Zip through all of the process entries */
110 "PID", 110 while ((proc = readdir(procdir))) {
111 "PPID", 111 int ps_fd;
112 "VSZ", 112 int as_fd;
113 "RSS", 113 off_t argoff;
114 "%CPU", 114 int i;
115 "COMMAND", 115 char *args;
116 "ARGS" 116 char *procname;
117 ); 117 char *ptr;
118 118 int argslen;
119 /* Zip through all of the process entries */ 119 uintptr_t args_addr;
120 while((proc = readdir(procdir))) { 120 ;
121 int ps_fd; 121 uintptr_t *args_vecs;
122 int as_fd; 122 ;
123 off_t argoff; 123 int args_count;
124 int i; 124
125 char *args; 125 if (proc->d_name[0] == '.') {
126 char *procname; 126 continue;
127 char *ptr; 127 }
128 int argslen; 128
129 uintptr_t args_addr;; 129 sprintf(ps_name, "%s/%s/%s", PROC_DIR, proc->d_name, "psinfo");
130 uintptr_t *args_vecs;; 130 sprintf(as_name, "%s/%s/%s", PROC_DIR, proc->d_name, "as");
131 int args_count; 131 try_again:
132 132 if ((ps_fd = open(ps_name, O_RDONLY)) == -1) {
133 if(proc->d_name[0] == '.') 133 continue;
134 continue; 134 }
135 135
136 sprintf(ps_name,"%s/%s/%s",PROC_DIR,proc->d_name,"psinfo"); 136 if ((as_fd = open(as_name, O_RDONLY)) == -1) {
137 sprintf(as_name,"%s/%s/%s",PROC_DIR,proc->d_name,"as"); 137 close(ps_fd);
138try_again: 138 continue;
139 if((ps_fd = open(ps_name, O_RDONLY)) == -1) 139 }
140 continue; 140
141 141 if (read(ps_fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) {
142 if((as_fd = open(as_name, O_RDONLY)) == -1) { 142 int err = errno;
143 close(ps_fd); 143 close(ps_fd);
144 continue; 144 close(as_fd);
145 } 145 if (err == EAGAIN) {
146 146 goto try_again;
147 if(read(ps_fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) { 147 }
148 int err = errno; 148 if (err != ENOENT) {
149 close(ps_fd); 149 fprintf(stderr, "%s: read() on %s: %s\n", szProg, ps_name, strerror(err));
150 close(as_fd); 150 }
151 if(err == EAGAIN) goto try_again; 151 continue;
152 if(err != ENOENT) 152 }
153 fprintf(stderr, "%s: read() on %s: %s\n", szProg, 153 close(ps_fd);
154 ps_name, strerror(err)); 154
155 continue; 155 /* system process, ignore since the previous version did */
156 } 156 if (psinfo.pr_nlwp == 0 || strcmp(psinfo.pr_lwp.pr_clname, "SYS") == 0) {
157 close(ps_fd); 157 continue;
158 158 }
159 /* system process, ignore since the previous version did */ 159
160 if( 160 /* get the procname to match previous versions */
161 psinfo.pr_nlwp == 0 || 161 procname = strdup(psinfo.pr_psargs);
162 strcmp(psinfo.pr_lwp.pr_clname, "SYS") == 0 162 if ((ptr = strchr(procname, ' ')) != NULL) {
163 ) { 163 *ptr = '\0';
164 continue; 164 }
165 } 165 if ((ptr = strrchr(procname, '/')) != NULL) {
166 166 ptr++;
167 /* get the procname to match previous versions */ 167 } else {
168 procname = strdup(psinfo.pr_psargs); 168 ptr = procname;
169 if((ptr = strchr(procname, ' ')) != NULL) 169 }
170 *ptr = '\0'; 170
171 if((ptr = strrchr(procname, '/')) != NULL) 171 /*
172 ptr++; 172 * print out what we currently know
173 else 173 */
174 ptr = procname; 174 printf("%c %5d %5d %5d %6lu %6lu %4.1f %s ", psinfo.pr_lwp.pr_sname, psinfo.pr_euid,
175 175 psinfo.pr_pid, psinfo.pr_ppid, psinfo.pr_size, psinfo.pr_rssize,
176 /* 176 ((float)(psinfo.pr_pctcpu) / 0x8000 * 100.0), ptr);
177 * print out what we currently know 177 free(procname);
178 */ 178
179 printf("%c %5d %5d %5d %6lu %6lu %4.1f %s ", 179 /*
180 psinfo.pr_lwp.pr_sname, 180 * and now for the command line stuff
181 psinfo.pr_euid, 181 */
182 psinfo.pr_pid, 182
183 psinfo.pr_ppid, 183 args_addr = psinfo.pr_argv;
184 psinfo.pr_size, 184 args_count = psinfo.pr_argc;
185 psinfo.pr_rssize, 185 args_vecs = malloc(args_count * sizeof(uintptr_t));
186 ((float)(psinfo.pr_pctcpu) / 0x8000 * 100.0), 186
187 ptr 187 if (psinfo.pr_dmodel == PR_MODEL_NATIVE) {
188 ); 188 /* this process matches target process */
189 free(procname); 189 pread(as_fd, args_vecs, args_count * sizeof(uintptr_t), args_addr);
190 190 } else {
191 /* 191 /* this process is 64bit, target process is 32 bit*/
192 * and now for the command line stuff 192 caddr32_t *args_vecs32 = (caddr32_t *)args_vecs;
193 */ 193 pread(as_fd, args_vecs32, args_count * sizeof(caddr32_t), args_addr);
194 194 for (i = args_count - 1; i >= 0; --i) {
195 args_addr = psinfo.pr_argv; 195 args_vecs[i] = args_vecs32[i];
196 args_count = psinfo.pr_argc; 196 }
197 args_vecs = malloc(args_count * sizeof(uintptr_t)); 197 }
198 198
199 if(psinfo.pr_dmodel == PR_MODEL_NATIVE) { 199 /*
200 /* this process matches target process */ 200 * now read in the args - if what we read in fills buffer
201 pread(as_fd,args_vecs, args_count * sizeof(uintptr_t), 201 * resize buffer and reread that bit again
202 args_addr); 202 */
203 } else { 203 argslen = ARGS;
204 /* this process is 64bit, target process is 32 bit*/ 204 args = malloc(argslen + 1);
205 caddr32_t *args_vecs32 = (caddr32_t *)args_vecs; 205 for (i = 0; i < args_count; i++) {
206 pread(as_fd,args_vecs32,args_count * sizeof(caddr32_t), 206 memset(args, '\0', argslen + 1);
207 args_addr); 207 if (pread(as_fd, args, argslen, args_vecs[i]) <= 0) {
208 for (i=args_count-1;i>=0;--i) 208 break;
209 args_vecs[i]=args_vecs32[i]; 209 }
210 } 210 args[argslen] = '\0';
211 211 if (strlen(args) == argslen) {
212 /* 212 argslen += ARGS;
213 * now read in the args - if what we read in fills buffer 213 args = realloc(args, argslen + 1);
214 * resize buffer and reread that bit again 214 i--;
215 */ 215 continue;
216 argslen=ARGS; 216 }
217 args=malloc(argslen+1); 217 printf(" %s", args);
218 for(i=0;i<args_count;i++) { 218 }
219 memset(args,'\0',argslen+1); 219 free(args_vecs);
220 if(pread(as_fd, args, argslen, args_vecs[i]) <= 0) { 220 free(args);
221 break; 221 close(as_fd);
222 } 222 printf("\n");
223 args[argslen]='\0'; 223 }
224 if(strlen(args) == argslen){ 224
225 argslen += ARGS; 225 (void)closedir(procdir);
226 args = realloc(args, argslen + 1); 226
227 i--; 227 return (0);
228 continue;
229 }
230 printf(" %s", args);
231 }
232 free(args_vecs);
233 free(args);
234 close(as_fd);
235 printf("\n");
236 }
237
238 (void) closedir(procdir);
239
240 return (0);
241} 228}
242 229
243/*----------------------------------------------------------------------------*/ 230/*----------------------------------------------------------------------------*/
244 231
245void usage() { 232void usage() {
246 printf("%s: Help output\n\n", szProg); 233 printf("%s: Help output\n\n", szProg);
247 printf("If this program is given any arguments, this help is displayed.\n"); 234 printf("If this program is given any arguments, this help is displayed.\n");
248 printf("This command is used to print out the full command line for all\n"); 235 printf("This command is used to print out the full command line for all\n");
249 printf("running processes because /usr/bin/ps is limited to 80 chars and\n"); 236 printf("running processes because /usr/bin/ps is limited to 80 chars and\n");
250 printf("/usr/ucb/ps can merge columns together.\n\n"); 237 printf("/usr/ucb/ps can merge columns together.\n\n");
251 printf("Columns are:\n"); 238 printf("Columns are:\n");
252 printf("\tS - State of process - see 'ps' man page\n"); 239 printf("\tS - State of process - see 'ps' man page\n");
253 printf("\tUID - UID of the process owner\n"); 240 printf("\tUID - UID of the process owner\n");
254 printf("\tPID - PID of the process\n"); 241 printf("\tPID - PID of the process\n");
255 printf("\tPPID - PID of the parent process\n"); 242 printf("\tPPID - PID of the parent process\n");
256 printf("\tVSZ - Virtual memory usage (kilobytes)\n"); 243 printf("\tVSZ - Virtual memory usage (kilobytes)\n");
257 printf("\tRSS - Real memory usage (kilobytes)\n"); 244 printf("\tRSS - Real memory usage (kilobytes)\n");
258 printf("\t%%CPU - CPU usage\n"); 245 printf("\t%%CPU - CPU usage\n");
259 printf("\tCOMMAND - Command being run\n"); 246 printf("\tCOMMAND - Command being run\n");
260 printf("\tARGS - Full command line with arguments\n"); 247 printf("\tARGS - Full command line with arguments\n");
261 return; 248 return;
262} 249}
diff --git a/plugins-root/t/check_dhcp.t b/plugins-root/t/check_dhcp.t
index ce627736..70392154 100644
--- a/plugins-root/t/check_dhcp.t
+++ b/plugins-root/t/check_dhcp.t
@@ -12,14 +12,14 @@ my $allow_sudo = getTestParameter( "NP_ALLOW_SUDO",
12 "no" ); 12 "no" );
13 13
14if ($allow_sudo eq "yes" or $> == 0) { 14if ($allow_sudo eq "yes" or $> == 0) {
15 plan tests => 6; 15 plan tests => 7;
16} else { 16} else {
17 plan skip_all => "Need sudo to test check_dhcp"; 17 plan skip_all => "Need sudo to test check_dhcp";
18} 18}
19my $sudo = $> == 0 ? '' : 'sudo'; 19my $sudo = $> == 0 ? '' : 'sudo';
20 20
21my $successOutput = '/OK: Received \d+ DHCPOFFER\(s\), \d+ of 1 requested servers responded, max lease time = \d+ sec\./'; 21my $successOutput = '/Received \d+ DHCPOFFER(s)*, max lease time = \d+ seconds/';
22my $failureOutput = '/CRITICAL: (No DHCPOFFERs were received|Received \d+ DHCPOFFER\(s\), 0 of 1 requested servers responded, max lease time = \d+ sec\.)/'; 22my $failureOutput = '/(No DHCPOFFERs were received|Received \d+ DHCPOFFER\(s\), 0 of 1 requested servers responded, max lease time = \d+ sec\.)/';
23my $invalidOutput = '/Invalid hostname/'; 23my $invalidOutput = '/Invalid hostname/';
24 24
25my $host_responsive = getTestParameter( "NP_HOST_DHCP_RESPONSIVE", 25my $host_responsive = getTestParameter( "NP_HOST_DHCP_RESPONSIVE",
@@ -34,6 +34,8 @@ my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
34 "An invalid (not known to DNS) hostname", 34 "An invalid (not known to DNS) hostname",
35 "nosuchhost" ); 35 "nosuchhost" );
36 36
37my $output_format = "--output-format mp-test-json";
38
37# try to determince interface 39# try to determince interface
38my $interface = ''; 40my $interface = '';
39 41
@@ -49,19 +51,21 @@ my $res;
49SKIP: { 51SKIP: {
50 skip('need responsive test host', 2) unless $host_responsive; 52 skip('need responsive test host', 2) unless $host_responsive;
51 $res = NPTest->testCmd( 53 $res = NPTest->testCmd(
52 "$sudo ./check_dhcp $interface -u -s $host_responsive" 54 "$sudo ./check_dhcp $interface -u -s $host_responsive $output_format"
53 ); 55 );
54 is( $res->return_code, 0, "Syntax ok" ); 56 is( $res->return_code, 0, "with JSON test format result should always be OK" );
55 like( $res->output, $successOutput, "Output OK" ); 57 like( $res->{'mp_test_result'}->{'state'}, "/OK/", "Output OK" );
58 like( $res->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $successOutput, "Output OK" );
56}; 59};
57 60
58SKIP: { 61SKIP: {
59 skip('need nonresponsive test host', 2) unless $host_nonresponsive; 62 skip('need nonresponsive test host', 2) unless $host_nonresponsive;
60 $res = NPTest->testCmd( 63 $res = NPTest->testCmd(
61 "$sudo ./check_dhcp $interface -u -s $host_nonresponsive" 64 "$sudo ./check_dhcp $interface -u -s $host_nonresponsive $output_format"
62 ); 65 );
63 is( $res->return_code, 2, "Exit code - host nonresponsive" ); 66 is( $res->return_code, 0, "with JSON test format result should always be OK" );
64 like( $res->output, $failureOutput, "Output OK" ); 67 like( $res->{'mp_test_result'}->{'state'}, "/CRITICAL/", "Exit code - host nonresponsive" );
68 like( $res->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $failureOutput, "Output OK" );
65}; 69};
66 70
67SKIP: { 71SKIP: {
@@ -69,6 +73,6 @@ SKIP: {
69 $res = NPTest->testCmd( 73 $res = NPTest->testCmd(
70 "$sudo ./check_dhcp $interface -u -s $hostname_invalid" 74 "$sudo ./check_dhcp $interface -u -s $hostname_invalid"
71 ); 75 );
72 is( $res->return_code, 3, "Exit code - host invalid" ); 76 is( $res->return_code, 3, "invalid hostname/address should return UNKNOWN" );
73 like( $res->output, $invalidOutput, "Output OK" ); 77 like( $res->output, $invalidOutput, "Output OK" );
74}; 78};
diff --git a/plugins-root/t/check_icmp.t b/plugins-root/t/check_icmp.t
index de1d88d2..d414c3c7 100644
--- a/plugins-root/t/check_icmp.t
+++ b/plugins-root/t/check_icmp.t
@@ -12,15 +12,12 @@ my $allow_sudo = getTestParameter( "NP_ALLOW_SUDO",
12 "no" ); 12 "no" );
13 13
14if ($allow_sudo eq "yes" or $> == 0) { 14if ($allow_sudo eq "yes" or $> == 0) {
15 plan tests => 40; 15 plan tests => 17;
16} else { 16} else {
17 plan skip_all => "Need sudo to test check_icmp"; 17 plan skip_all => "Need sudo to test check_icmp";
18} 18}
19my $sudo = $> == 0 ? '' : 'sudo'; 19my $sudo = $> == 0 ? '' : 'sudo';
20 20
21my $successOutput = '/OK - .*? rta (?:[\d\.]+ms)|(?:nan), lost \d+%/';
22my $failureOutput = '/(WARNING|CRITICAL) - .*? rta (?:[\d\.]+ms > [\d\.]+ms|nan)/';
23
24my $host_responsive = getTestParameter( "NP_HOST_RESPONSIVE", 21my $host_responsive = getTestParameter( "NP_HOST_RESPONSIVE",
25 "The hostname of system responsive to network requests", 22 "The hostname of system responsive to network requests",
26 "localhost" ); 23 "localhost" );
@@ -36,108 +33,85 @@ my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
36my $res; 33my $res;
37 34
38$res = NPTest->testCmd( 35$res = NPTest->testCmd(
39 "$sudo ./check_icmp -H $host_responsive -w 10000ms,100% -c 10000ms,100%" 36 "$sudo ./check_icmp -H $host_responsive -w 100ms,100% -c 100ms,100%"
40 ); 37 );
41is( $res->return_code, 0, "Syntax ok" ); 38is( $res->return_code, 0, "Syntax ok" );
42like( $res->output, $successOutput, "Output OK" );
43 39
44$res = NPTest->testCmd( 40$res = NPTest->testCmd(
45 "$sudo ./check_icmp -H $host_responsive -w 0ms,0% -c 10000ms,100%" 41 "$sudo ./check_icmp -H $host_responsive -w 0ms,0% -c 100ms,100%"
46 ); 42 );
47is( $res->return_code, 1, "Syntax ok, with forced warning" ); 43is( $res->return_code, 1, "Syntax ok, with forced warning" );
48like( $res->output, $failureOutput, "Output OK" );
49 44
50$res = NPTest->testCmd( 45$res = NPTest->testCmd(
51 "$sudo ./check_icmp -H $host_responsive -w 0,0% -c 0,0%" 46 "$sudo ./check_icmp -H $host_responsive -w 0,0% -c 0,0%"
52 ); 47 );
53is( $res->return_code, 2, "Syntax ok, with forced critical" ); 48is( $res->return_code, 2, "Syntax ok, with forced critical" );
54like( $res->output, $failureOutput, "Output OK" );
55 49
56$res = NPTest->testCmd( 50$res = NPTest->testCmd(
57 "$sudo ./check_icmp -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -t 2" 51 "$sudo ./check_icmp -H $host_nonresponsive -w 100ms,100% -c 100ms,100%"
58 ); 52 );
59is( $res->return_code, 2, "Timeout - host nonresponsive" ); 53is( $res->return_code, 2, "Timeout - host nonresponsive" );
60like( $res->output, '/pl=100%/', "Error contains 'pl=100%' string (for 100% packet loss)" );
61like( $res->output, '/rta=U/', "Error contains 'rta=U' string" );
62 54
63$res = NPTest->testCmd( 55$res = NPTest->testCmd(
64 "$sudo ./check_icmp -w 10000ms,100% -c 10000ms,100%" 56 "$sudo ./check_icmp -w 100ms,100% -c 100ms,100%"
65 ); 57 );
66is( $res->return_code, 3, "No hostname" ); 58is( $res->return_code, 3, "No hostname" );
67like( $res->output, '/No hosts to check/', "Output with appropriate error message");
68 59
69$res = NPTest->testCmd( 60$res = NPTest->testCmd(
70 "$sudo ./check_icmp -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -n 1 -m 0 -t 2" 61 "$sudo ./check_icmp -H $host_nonresponsive -w 100ms,100% -c 100ms,100% -n 1 -m 0"
71 ); 62 );
72is( $res->return_code, 0, "One host nonresponsive - zero required" ); 63is( $res->return_code, 0, "One host nonresponsive - zero required" );
73like( $res->output, $successOutput, "Output OK" );
74 64
75$res = NPTest->testCmd( 65$res = NPTest->testCmd(
76 "$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -n 1 -m 1 -t 2" 66 "$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 100ms,100% -c 100ms,100% -n 1 -m 1"
77 ); 67 );
78is( $res->return_code, 0, "One of two host nonresponsive - one required" ); 68is( $res->return_code, 0, "One of two host nonresponsive - one required" );
79like( $res->output, $successOutput, "Output OK" );
80 69
81$res = NPTest->testCmd( 70$res = NPTest->testCmd(
82 "$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -n 1 -m 2" 71 "$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 100ms,100% -c 100ms,100% -n 1 -m 2"
83 ); 72 );
84is( $res->return_code, 2, "One of two host nonresponsive - two required" ); 73is( $res->return_code, 2, "One of two host nonresponsive - two required" );
85like( $res->output, $failureOutput, "Output OK" );
86 74
87$res = NPTest->testCmd( 75$res = NPTest->testCmd(
88 "$sudo ./check_icmp -H $host_responsive -s 127.0.15.15 -w 10000ms,100% -c 10000ms,100% -n 1 -m 2" 76 "$sudo ./check_icmp -H $host_responsive -s 127.0.15.15 -w 100ms,100% -c 100ms,100% -n 1"
89 ); 77 );
90is( $res->return_code, 0, "IPv4 source_ip accepted" ); 78is( $res->return_code, 0, "IPv4 source_ip accepted" );
91like( $res->output, $successOutput, "Output OK" );
92 79
93$res = NPTest->testCmd( 80$res = NPTest->testCmd(
94 "$sudo ./check_icmp -H $host_responsive -b 65507" 81 "$sudo ./check_icmp -H $host_responsive -b 65507"
95 ); 82 );
96is( $res->return_code, 0, "Try max packet size" ); 83is( $res->return_code, 0, "Try max packet size" );
97like( $res->output, $successOutput, "Output OK - Didn't overflow" );
98 84
99$res = NPTest->testCmd( 85$res = NPTest->testCmd(
100 "$sudo ./check_icmp -H $host_responsive -R 100,100 -n 1 -t 2" 86 "$sudo ./check_icmp -H $host_responsive -R 100,100 -n 1"
101 ); 87 );
102is( $res->return_code, 0, "rta works" ); 88is( $res->return_code, 0, "rta works" );
103like( $res->output, $successOutput, "Output OK" );
104$res = NPTest->testCmd( 89$res = NPTest->testCmd(
105 "$sudo ./check_icmp -H $host_responsive -P 80,90 -n 1 -t 2" 90 "$sudo ./check_icmp -H $host_responsive -P 80,90 -n 1"
106 ); 91 );
107is( $res->return_code, 0, "pl works" ); 92is( $res->return_code, 0, "pl works" );
108like( $res->output, '/lost 0%/', "Output OK" );
109 93
110$res = NPTest->testCmd( 94$res = NPTest->testCmd(
111 "$sudo ./check_icmp -H $host_responsive -J 80,90 -t 2" 95 "$sudo ./check_icmp -H $host_responsive -J 80,90"
112 ); 96 );
113is( $res->return_code, 0, "jitter works" ); 97is( $res->return_code, 0, "jitter works" );
114like( $res->output, '/jitter \d/', "Output OK" );
115 98
116$res = NPTest->testCmd( 99$res = NPTest->testCmd(
117 "$sudo ./check_icmp -H $host_responsive -M 4,3 -t 2" 100 "$sudo ./check_icmp -H $host_responsive -M 4,3"
118 ); 101 );
119is( $res->return_code, 0, "mos works" ); 102is( $res->return_code, 0, "mos works" );
120like( $res->output, '/MOS \d/', "Output OK" );
121 103
122$res = NPTest->testCmd( 104$res = NPTest->testCmd(
123 "$sudo ./check_icmp -H $host_responsive -S 80,70 -t 2" 105 "$sudo ./check_icmp -H $host_responsive -S 80,70"
124 ); 106 );
125is( $res->return_code, 0, "score works" ); 107is( $res->return_code, 0, "score works" );
126like( $res->output, '/Score \d/', "Output OK" );
127 108
128$res = NPTest->testCmd( 109$res = NPTest->testCmd(
129 "$sudo ./check_icmp -H $host_responsive -O -t 2" 110 "$sudo ./check_icmp -H $host_responsive -O"
130 ); 111 );
131is( $res->return_code, 0, "order works" ); 112is( $res->return_code, 0, "order works" );
132like( $res->output, '/Packets in order/', "Output OK" );
133 113
134$res = NPTest->testCmd( 114$res = NPTest->testCmd(
135 "$sudo ./check_icmp -H $host_responsive -O -S 80,70 -M 4,3 -J 80,90 -P 80,90 -R 100,100 -t 2" 115 "$sudo ./check_icmp -H $host_responsive -O -S 80,70 -M 4,3 -J 80,90 -P 80,90 -R 100,100"
136 ); 116 );
137is( $res->return_code, 0, "order works" ); 117is( $res->return_code, 0, "order works" );
138like( $res->output, '/Packets in order/', "Output OK" );
139like( $res->output, '/Score \d/', "Output OK" );
140like( $res->output, '/MOS \d/', "Output OK" );
141like( $res->output, '/jitter \d/', "Output OK" );
142like( $res->output, '/lost 0%/', "Output OK" );
143like( $res->output, $successOutput, "Output OK" );
diff --git a/plugins-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..1a9399f0 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -13,8 +13,14 @@ AM_CFLAGS = -DNP_VERSION='"$(NP_VERSION)"'
13 13
14VPATH = $(top_srcdir) $(top_srcdir)/lib $(top_srcdir)/plugins $(top_srcdir)/plugins/t 14VPATH = $(top_srcdir) $(top_srcdir)/lib $(top_srcdir)/plugins $(top_srcdir)/plugins/t
15 15
16AM_CPPFLAGS = -I.. -I$(top_srcdir)/lib -I$(top_srcdir)/gl -I$(top_srcdir)/intl \ 16AM_CPPFLAGS = -I.. \
17 @LDAPINCLUDE@ @PGINCLUDE@ @SSLINCLUDE@ 17 -I$(top_srcdir)/lib \
18 -I$(top_srcdir)/gl \
19 -I$(top_srcdir)/intl \
20 -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \
21 @LDAPINCLUDE@ \
22 @PGINCLUDE@ \
23 @SSLINCLUDE@
18 24
19localedir = $(datadir)/locale 25localedir = $(datadir)/locale
20# gettext docs say to use AM_CPPFLAGS, but per module_CPPFLAGS override this 26# gettext docs say to use AM_CPPFLAGS, but per module_CPPFLAGS override this
@@ -27,30 +33,82 @@ MATHLIBS = @MATHLIBS@
27#AM_CFLAGS = -Wall 33#AM_CFLAGS = -Wall
28 34
29libexec_PROGRAMS = check_apt check_cluster check_disk check_dummy check_http check_load \ 35libexec_PROGRAMS = check_apt check_cluster check_disk check_dummy check_http check_load \
30 check_mrtg check_mrtgtraf check_ntp check_ntp_peer check_nwstat check_overcr check_ping \ 36 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 \ 37 check_real check_smtp check_ssh check_tcp check_time check_ntp_time \
32 check_ups check_users negate \ 38 check_ups check_users negate \
33 urlize @EXTRAS@ 39 urlize @EXTRAS@ \
40 check_snmp
34 41
35check_tcp_programs = check_ftp check_imap check_nntp check_pop \ 42check_tcp_programs = check_ftp check_imap check_nntp check_pop \
36 check_udp check_clamd @check_tcp_ssl@ 43 check_udp check_clamd @check_tcp_ssl@
37 44
38EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \ 45EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_hpjd \
39 check_swap check_fping check_ldap check_game check_dig \ 46 check_swap check_fping check_ldap check_game check_dig \
40 check_nagios check_by_ssh check_dns check_nt check_ide_smart \ 47 check_nagios check_by_ssh check_dns check_nt check_ide_smart \
41 check_procs check_mysql_query check_apt check_dbi check_curl 48 check_procs check_mysql_query check_apt check_dbi check_curl \
49 \
50 tests/test_check_swap \
51 tests/test_check_snmp \
52 tests/test_check_disk
42 53
43SUBDIRS = picohttpparser 54SUBDIRS = picohttpparser
44 55
45EXTRA_DIST = t tests 56np_test_scripts = tests/test_check_swap.t \
57 tests/test_check_snmp.t \
58 tests/test_check_disk.t
59
60EXTRA_DIST = t \
61 tests \
62 $(np_test_scripts) \
63 negate.d \
64 check_swap.d \
65 check_ldap.d \
66 check_hpjd.d \
67 check_game.d \
68 check_radius.d \
69 check_curl.d \
70 check_disk.d \
71 check_time.d \
72 check_users.d \
73 check_load.d \
74 check_nagios.d \
75 check_dbi.d \
76 check_tcp.d \
77 check_real.d \
78 check_ssh.d \
79 check_nt.d \
80 check_dns.d \
81 check_mrtgtraf.d \
82 check_mysql_query.d \
83 check_mrtg.d \
84 check_ntp_peer.d \
85 check_apt.d \
86 check_pgsql.d \
87 check_procs.d \
88 check_ping.d \
89 check_by_ssh.d \
90 check_smtp.d \
91 check_snmp.d \
92 check_mysql.d \
93 check_ntp_time.d \
94 check_dig.d \
95 check_cluster.d \
96 check_curl.d \
97 check_cluster.d \
98 check_ups.d \
99 check_fping.d
46 100
47PLUGINHDRS = common.h 101PLUGINHDRS = common.h
48 102
49noinst_LIBRARIES = libnpcommon.a 103noinst_LIBRARIES = libnpcommon.a
104noinst_PROGRAMS = @EXTRA_PLUGIN_TESTS@
105# These two lines support "make check", but we use "make test"
106check_PROGRAMS = @EXTRA_PLUGIN_TESTS@
50 107
51libnpcommon_a_SOURCES = utils.c netutils.c sslutils.c runcmd.c \ 108libnpcommon_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 109 popen.c utils.h netutils.h popen.h common.h runcmd.c runcmd.h
53 110
111
54BASEOBJS = libnpcommon.a ../lib/libmonitoringplug.a ../gl/libgnu.a $(LIB_CRYPTO) 112BASEOBJS = libnpcommon.a ../lib/libmonitoringplug.a ../gl/libgnu.a $(LIB_CRYPTO)
55NETOBJS = $(BASEOBJS) $(EXTRA_NETOBLS) 113NETOBJS = $(BASEOBJS) $(EXTRA_NETOBLS)
56NETLIBS = $(NETOBJS) $(SOCKETLIBS) 114NETLIBS = $(NETOBJS) $(SOCKETLIBS)
@@ -58,7 +116,10 @@ SSLOBJS = $(BASEOBJS) $(NETLIBS) $(SSLLIBS) $(LIB_CRYPTO)
58 116
59TESTS_ENVIRONMENT = perl -I $(top_builddir) -I $(top_srcdir) 117TESTS_ENVIRONMENT = perl -I $(top_builddir) -I $(top_srcdir)
60 118
61TESTS = @PLUGIN_TEST@ 119tap_ldflags = -L$(top_srcdir)/tap
120
121TESTS = @PLUGIN_TEST@ @EXTRA_PLUGIN_TESTS@
122
62 123
63test: 124test:
64 perl -I $(top_builddir) -I $(top_srcdir) ../test.pl 125 perl -I $(top_builddir) -I $(top_srcdir) ../test.pl
@@ -74,9 +135,11 @@ check_cluster_LDADD = $(BASEOBJS)
74check_curl_CFLAGS = $(AM_CFLAGS) $(LIBCURLCFLAGS) $(URIPARSERCFLAGS) $(LIBCURLINCLUDE) $(URIPARSERINCLUDE) -Ipicohttpparser 135check_curl_CFLAGS = $(AM_CFLAGS) $(LIBCURLCFLAGS) $(URIPARSERCFLAGS) $(LIBCURLINCLUDE) $(URIPARSERINCLUDE) -Ipicohttpparser
75check_curl_CPPFLAGS = $(AM_CPPFLAGS) $(LIBCURLCFLAGS) $(URIPARSERCFLAGS) $(LIBCURLINCLUDE) $(URIPARSERINCLUDE) -Ipicohttpparser 136check_curl_CPPFLAGS = $(AM_CPPFLAGS) $(LIBCURLCFLAGS) $(URIPARSERCFLAGS) $(LIBCURLINCLUDE) $(URIPARSERINCLUDE) -Ipicohttpparser
76check_curl_LDADD = $(NETLIBS) $(LIBCURLLIBS) $(SSLOBJS) $(URIPARSERLIBS) picohttpparser/libpicohttpparser.a 137check_curl_LDADD = $(NETLIBS) $(LIBCURLLIBS) $(SSLOBJS) $(URIPARSERLIBS) picohttpparser/libpicohttpparser.a
138check_curl_SOURCES = check_curl.c check_curl.d/check_curl_helpers.c
77check_dbi_LDADD = $(NETLIBS) $(DBILIBS) 139check_dbi_LDADD = $(NETLIBS) $(DBILIBS)
78check_dig_LDADD = $(NETLIBS) 140check_dig_LDADD = $(NETLIBS)
79check_disk_LDADD = $(BASEOBJS) 141check_disk_LDADD = $(BASEOBJS)
142check_disk_SOURCES = check_disk.c check_disk.d/utils_disk.c
80check_dns_LDADD = $(NETLIBS) 143check_dns_LDADD = $(NETLIBS)
81check_dummy_LDADD = $(BASEOBJS) 144check_dummy_LDADD = $(BASEOBJS)
82check_fping_LDADD = $(NETLIBS) 145check_fping_LDADD = $(NETLIBS)
@@ -97,21 +160,24 @@ check_nagios_LDADD = $(BASEOBJS)
97check_nt_LDADD = $(NETLIBS) 160check_nt_LDADD = $(NETLIBS)
98check_ntp_LDADD = $(NETLIBS) $(MATHLIBS) 161check_ntp_LDADD = $(NETLIBS) $(MATHLIBS)
99check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS) 162check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS)
100check_nwstat_LDADD = $(NETLIBS)
101check_overcr_LDADD = $(NETLIBS)
102check_pgsql_LDADD = $(NETLIBS) $(PGLIBS) 163check_pgsql_LDADD = $(NETLIBS) $(PGLIBS)
103check_ping_LDADD = $(NETLIBS) 164check_ping_LDADD = $(NETLIBS)
104check_procs_LDADD = $(BASEOBJS) 165check_procs_LDADD = $(BASEOBJS)
105check_radius_LDADD = $(NETLIBS) $(RADIUSLIBS) 166check_radius_LDADD = $(NETLIBS) $(RADIUSLIBS)
106check_real_LDADD = $(NETLIBS) 167check_real_LDADD = $(NETLIBS)
168check_snmp_SOURCES = check_snmp.c check_snmp.d/check_snmp_helpers.c
107check_snmp_LDADD = $(BASEOBJS) 169check_snmp_LDADD = $(BASEOBJS)
170check_snmp_LDFLAGS = $(AM_LDFLAGS) `net-snmp-config --libs`
171check_snmp_CFLAGS = $(AM_CFLAGS) `net-snmp-config --cflags`
108check_smtp_LDADD = $(SSLOBJS) 172check_smtp_LDADD = $(SSLOBJS)
109check_ssh_LDADD = $(NETLIBS) 173check_ssh_LDADD = $(NETLIBS)
174check_swap_SOURCES = check_swap.c check_swap.d/swap.c
110check_swap_LDADD = $(MATHLIBS) $(BASEOBJS) 175check_swap_LDADD = $(MATHLIBS) $(BASEOBJS)
111check_tcp_LDADD = $(SSLOBJS) 176check_tcp_LDADD = $(SSLOBJS)
112check_time_LDADD = $(NETLIBS) 177check_time_LDADD = $(NETLIBS)
113check_ntp_time_LDADD = $(NETLIBS) $(MATHLIBS) 178check_ntp_time_LDADD = $(NETLIBS) $(MATHLIBS)
114check_ups_LDADD = $(NETLIBS) 179check_ups_LDADD = $(NETLIBS)
180check_users_SOURCES = check_users.c check_users.d/users.c
115check_users_LDADD = $(BASEOBJS) $(WTSAPI32LIBS) $(SYSTEMDLIBS) 181check_users_LDADD = $(BASEOBJS) $(WTSAPI32LIBS) $(SYSTEMDLIBS)
116check_by_ssh_LDADD = $(NETLIBS) 182check_by_ssh_LDADD = $(NETLIBS)
117check_ide_smart_LDADD = $(BASEOBJS) 183check_ide_smart_LDADD = $(BASEOBJS)
@@ -122,6 +188,13 @@ if !HAVE_UTMPX
122check_users_LDADD += popen.o 188check_users_LDADD += popen.o
123endif 189endif
124 190
191tests_test_check_swap_LDADD = $(BASEOBJS) $(tap_ldflags) -ltap
192tests_test_check_swap_SOURCES = tests/test_check_swap.c check_swap.d/swap.c
193tests_test_check_snmp_LDADD = $(BASEOBJS) $(tap_ldflags) -ltap
194tests_test_check_snmp_SOURCES = tests/test_check_snmp.c check_snmp.d/check_snmp_helpers.c
195tests_test_check_disk_LDADD = $(BASEOBJS) $(tap_ldflags) check_disk.d/utils_disk.c -ltap
196tests_test_check_disk_SOURCES = tests/test_check_disk.c
197
125############################################################################## 198##############################################################################
126# secondary dependencies 199# secondary dependencies
127 200
diff --git a/plugins/check_apt.c b/plugins/check_apt.c
index 5c0f6e28..9ed5b6cf 100644
--- a/plugins/check_apt.c
+++ b/plugins/check_apt.c
@@ -1,188 +1,250 @@
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 "perfdata.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
37#include "states.h"
38#include "output.h"
36#include "common.h" 39#include "common.h"
37#include "runcmd.h" 40#include "runcmd.h"
38#include "utils.h" 41#include "utils.h"
39#include "regex.h" 42#include "regex.h"
43#include "check_apt.d/config.h"
40 44
41/* some constants */
42typedef enum { UPGRADE, DIST_UPGRADE, NO_UPGRADE } upgrade_type;
43
44/* Character for hidden input file option (for testing). */
45#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" 46const char *UPGRADE_DEFAULT_OPTS = "-o 'Debug::NoLocking=true' -s -qq";
48#define UPDATE_DEFAULT_OPTS "-q" 47const char *UPDATE_DEFAULT_OPTS = "-q";
48
49/* until i commit the configure.in patch which gets this, i'll define 49/* until i commit the configure.in patch which gets this, i'll define
50 * it here as well */ 50 * it here as well */
51#ifndef PATH_TO_APTGET 51#ifndef PATH_TO_APTGET
52# define PATH_TO_APTGET "/usr/bin/apt-get" 52# define PATH_TO_APTGET "/usr/bin/apt-get"
53#endif /* PATH_TO_APTGET */ 53#endif /* PATH_TO_APTGET */
54
54/* String found at the beginning of the apt output lines we're interested in */ 55/* String found at the beginning of the apt output lines we're interested in */
55#define PKGINST_PREFIX "Inst " 56const char *PKGINST_PREFIX = "Inst ";
56/* the RE that catches security updates */ 57/* the RE that catches security updates */
57#define SECURITY_RE "^[^\\(]*\\(.* (Debian-Security:|Ubuntu:[^/]*/[^-]*-security)" 58const char *SECURITY_RE = "^[^\\(]*\\(.* (Debian-Security:|Ubuntu:[^/]*/[^-]*-security)";
58 59
59/* some standard functions */ 60/* some standard functions */
60int process_arguments(int, char **); 61typedef struct {
61void print_help(void); 62 int errorcode;
63 check_apt_config config;
64} check_apt_config_wrapper;
65static check_apt_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
66static void print_help(void);
62void print_usage(void); 67void print_usage(void);
63 68
64/* construct the appropriate apt-get cmdline */ 69/* construct the appropriate apt-get cmdline */
65char* construct_cmdline(upgrade_type u, const char *opts); 70static char *construct_cmdline(upgrade_type /*u*/, const char * /*opts*/);
71
66/* run an apt-get update */ 72/* run an apt-get update */
67int run_update(void); 73typedef struct {
74 mp_subcheck sc;
75 bool stderr_warning;
76 bool exec_warning;
77} run_update_result;
78static run_update_result run_update(char *update_opts);
79
80typedef struct {
81 int errorcode;
82 size_t package_count;
83 size_t security_package_count;
84 char **packages_list;
85 char **secpackages_list;
86 bool exec_warning;
87} run_upgrade_result;
88
68/* run an apt-get upgrade */ 89/* run an apt-get upgrade */
69int run_upgrade(int *pkgcount, int *secpkgcount, char ***pkglist, char ***secpkglist); 90run_upgrade_result run_upgrade(upgrade_type upgrade, const char *do_include, const char *do_exclude,
91 const char *do_critical, const char *upgrade_opts,
92 const char *input_filename);
93
70/* add another clause to a regexp */ 94/* add another clause to a regexp */
71char* add_to_regexp(char *expr, const char *next); 95static char *add_to_regexp(char * /*expr*/, const char * /*next*/);
72/* extract package name from Inst line */ 96/* extract package name from Inst line */
73char* pkg_name(char *line); 97static char *pkg_name(char * /*line*/);
74/* string comparison function for qsort */ 98/* string comparison function for qsort */
75int cmpstringp(const void *p1, const void *p2); 99static int cmpstringp(const void * /*p1*/, const void * /*p2*/);
76 100
77/* configuration variables */ 101/* configuration variables */
78static int verbose = 0; /* -v */ 102static 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 103
92/* other global variables */ 104/* other global variables */
93static int stderr_warning = 0; /* if a cmd issued output on stderr */ 105static bool stderr_warning = false; /* if a cmd issued output on stderr */
94static int exec_warning = 0; /* if a cmd exited non-zero */ 106static 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 107
108int main(int argc, char **argv) {
100 /* Parse extra opts if any */ 109 /* Parse extra opts if any */
101 argv=np_extra_opts(&argc, argv, progname); 110 argv = np_extra_opts(&argc, argv, progname);
102 111
103 if (process_arguments(argc, argv) == ERROR) 112 check_apt_config_wrapper tmp_config = process_arguments(argc, argv);
113
114 if (tmp_config.errorcode == ERROR) {
104 usage_va(_("Could not parse arguments")); 115 usage_va(_("Could not parse arguments"));
116 }
117
118 const check_apt_config config = tmp_config.config;
119
120 if (config.output_format_is_set) {
121 mp_set_format(config.output_format);
122 }
105 123
106 /* Set signal handling and alarm timeout */ 124 /* Set signal handling and alarm timeout */
107 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 125 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
108 usage_va(_("Cannot catch SIGALRM")); 126 usage_va(_("Cannot catch SIGALRM"));
109 } 127 }
110 128
111 /* handle timeouts gracefully... */ 129 /* handle timeouts gracefully... */
112 alarm (timeout_interval); 130 alarm(timeout_interval);
113 131
132 mp_check overall = mp_check_init();
114 /* if they want to run apt-get update first... */ 133 /* if they want to run apt-get update first... */
115 if(do_update) result = run_update(); 134 if (config.do_update) {
135 run_update_result update_result = run_update(config.update_opts);
136
137 mp_add_subcheck_to_check(&overall, update_result.sc);
138 }
116 139
117 /* apt-get upgrade */ 140 /* apt-get upgrade */
118 result = max_state(result, run_upgrade(&packages_available, &sec_count, &packages_list, &secpackages_list)); 141 run_upgrade_result upgrad_res =
119 142 run_upgrade(config.upgrade, config.do_include, config.do_exclude, config.do_critical,
120 if(sec_count > 0){ 143 config.upgrade_opts, config.input_filename);
121 result = max_state(result, STATE_CRITICAL); 144
122 } else if(packages_available >= packages_warning && only_critical == false){ 145 mp_subcheck sc_run_upgrade = mp_subcheck_init();
123 result = max_state(result, STATE_WARNING); 146 if (upgrad_res.errorcode == OK) {
124 } else if(result > STATE_UNKNOWN){ 147 sc_run_upgrade = mp_set_subcheck_state(sc_run_upgrade, STATE_OK);
125 result = STATE_UNKNOWN; 148 }
149 xasprintf(&sc_run_upgrade.output, "Executed apt upgrade (dry run)");
150
151 mp_add_subcheck_to_check(&overall, sc_run_upgrade);
152
153 size_t packages_available = upgrad_res.package_count;
154 size_t number_of_security_updates = upgrad_res.security_package_count;
155 char **packages_list = upgrad_res.packages_list;
156 char **secpackages_list = upgrad_res.secpackages_list;
157
158 mp_perfdata pd_security_updates = perfdata_init();
159 pd_security_updates.value = mp_create_pd_value(number_of_security_updates);
160 pd_security_updates.label = "critical_updates";
161
162 mp_subcheck sc_security_updates = mp_subcheck_init();
163 xasprintf(&sc_security_updates.output, "Security updates available: %zu",
164 number_of_security_updates);
165 mp_add_perfdata_to_subcheck(&sc_security_updates, pd_security_updates);
166
167 if (number_of_security_updates > 0) {
168 sc_security_updates = mp_set_subcheck_state(sc_security_updates, STATE_CRITICAL);
169 } else {
170 sc_security_updates = mp_set_subcheck_state(sc_security_updates, STATE_OK);
171 }
172
173 mp_perfdata pd_other_updates = perfdata_init();
174 pd_other_updates.value = mp_create_pd_value(packages_available);
175 pd_other_updates.label = "available_upgrades";
176
177 mp_subcheck sc_other_updates = mp_subcheck_init();
178
179 xasprintf(&sc_other_updates.output, "Updates available: %zu", packages_available);
180 sc_other_updates = mp_set_subcheck_default_state(sc_other_updates, STATE_OK);
181 mp_add_perfdata_to_subcheck(&sc_other_updates, pd_other_updates);
182
183 if (packages_available >= config.packages_warning && !config.only_critical) {
184 sc_other_updates = mp_set_subcheck_state(sc_other_updates, STATE_WARNING);
126 } 185 }
127 186
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"), 187 if (config.list) {
129 state_text(result), 188 qsort(secpackages_list, number_of_security_updates, sizeof(char *), cmpstringp);
130 packages_available, 189 qsort(packages_list, packages_available - number_of_security_updates, sizeof(char *),
131 (upgrade==DIST_UPGRADE)?"dist-upgrade":"upgrade", 190 cmpstringp);
132 sec_count, 191
133 (stderr_warning)?" warnings detected":"", 192 for (size_t i = 0; i < number_of_security_updates; i++) {
134 (stderr_warning && exec_warning)?",":"", 193 xasprintf(&sc_security_updates.output, "%s\n%s (security)", sc_security_updates.output,
135 (exec_warning)?" errors detected":"", 194 secpackages_list[i]);
136 (stderr_warning||exec_warning)?".":"", 195 }
137 packages_available, 196
138 sec_count 197 if (!config.only_critical) {
139 ); 198 for (size_t i = 0; i < packages_available - number_of_security_updates; i++) {
140 199 xasprintf(&sc_other_updates.output, "%s\n%s", sc_other_updates.output,
141 if(list) { 200 packages_list[i]);
142 qsort(secpackages_list, sec_count, sizeof(char*), cmpstringp); 201 }
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]);
147
148 if (only_critical == false) {
149 for(int i = 0; i < packages_available - sec_count; i++)
150 printf("%s\n", packages_list[i]);
151 } 202 }
152 } 203 }
204 mp_add_subcheck_to_check(&overall, sc_security_updates);
205 mp_add_subcheck_to_check(&overall, sc_other_updates);
153 206
154 return result; 207 mp_exit(overall);
155} 208}
156 209
157/* process command-line arguments */ 210/* process command-line arguments */
158int process_arguments (int argc, char **argv) { 211check_apt_config_wrapper process_arguments(int argc, char **argv) {
159 int c; 212 enum {
160 213 /* Character for hidden input file option (for testing). */
161 static struct option longopts[] = { 214 INPUT_FILE_OPT = CHAR_MAX + 1,
162 {"version", no_argument, 0, 'V'}, 215 output_format_index,
163 {"help", no_argument, 0, 'h'}, 216 };
164 {"verbose", no_argument, 0, 'v'}, 217 static struct option longopts[] = {{"version", no_argument, 0, 'V'},
165 {"timeout", required_argument, 0, 't'}, 218 {"help", no_argument, 0, 'h'},
166 {"update", optional_argument, 0, 'u'}, 219 {"verbose", no_argument, 0, 'v'},
167 {"upgrade", optional_argument, 0, 'U'}, 220 {"timeout", required_argument, 0, 't'},
168 {"no-upgrade", no_argument, 0, 'n'}, 221 {"update", optional_argument, 0, 'u'},
169 {"dist-upgrade", optional_argument, 0, 'd'}, 222 {"upgrade", optional_argument, 0, 'U'},
170 {"list", no_argument, false, 'l'}, 223 {"no-upgrade", no_argument, 0, 'n'},
171 {"include", required_argument, 0, 'i'}, 224 {"dist-upgrade", optional_argument, 0, 'd'},
172 {"exclude", required_argument, 0, 'e'}, 225 {"list", no_argument, 0, 'l'},
173 {"critical", required_argument, 0, 'c'}, 226 {"include", required_argument, 0, 'i'},
174 {"only-critical", no_argument, 0, 'o'}, 227 {"exclude", required_argument, 0, 'e'},
175 {"input-file", required_argument, 0, INPUT_FILE_OPT}, 228 {"critical", required_argument, 0, 'c'},
176 {"packages-warning", required_argument, 0, 'w'}, 229 {"only-critical", no_argument, 0, 'o'},
177 {0, 0, 0, 0} 230 {"input-file", required_argument, 0, INPUT_FILE_OPT},
231 {"packages-warning", required_argument, 0, 'w'},
232 {"output-format", required_argument, 0, output_format_index},
233 {0, 0, 0, 0}};
234
235 check_apt_config_wrapper result = {
236 .errorcode = OK,
237 .config = check_apt_config_init(),
178 }; 238 };
179 239
180 while(1) { 240 while (true) {
181 c = getopt_long(argc, argv, "hVvt:u::U::d::nli:e:c:ow:", longopts, NULL); 241 int option_char = getopt_long(argc, argv, "hVvt:u::U::d::nli:e:c:ow:", longopts, NULL);
182 242
183 if(c == -1 || c == EOF || c == 1) break; 243 if (option_char == -1 || option_char == EOF || option_char == 1) {
244 break;
245 }
184 246
185 switch(c) { 247 switch (option_char) {
186 case 'h': 248 case 'h':
187 print_help(); 249 print_help();
188 exit(STATE_UNKNOWN); 250 exit(STATE_UNKNOWN);
@@ -193,124 +255,153 @@ int process_arguments (int argc, char **argv) {
193 verbose++; 255 verbose++;
194 break; 256 break;
195 case 't': 257 case 't':
196 timeout_interval=atoi(optarg); 258 timeout_interval = atoi(optarg);
197 break; 259 break;
198 case 'd': 260 case 'd':
199 upgrade=DIST_UPGRADE; 261 result.config.upgrade = DIST_UPGRADE;
200 if(optarg!=NULL){ 262 if (optarg != NULL) {
201 upgrade_opts=strdup(optarg); 263 result.config.upgrade_opts = strdup(optarg);
202 if(upgrade_opts==NULL) die(STATE_UNKNOWN, "strdup failed"); 264 if (result.config.upgrade_opts == NULL) {
265 die(STATE_UNKNOWN, "strdup failed");
266 }
203 } 267 }
204 break; 268 break;
205 case 'U': 269 case 'U':
206 upgrade=UPGRADE; 270 result.config.upgrade = UPGRADE;
207 if(optarg!=NULL){ 271 if (optarg != NULL) {
208 upgrade_opts=strdup(optarg); 272 result.config.upgrade_opts = strdup(optarg);
209 if(upgrade_opts==NULL) die(STATE_UNKNOWN, "strdup failed"); 273 if (result.config.upgrade_opts == NULL) {
274 die(STATE_UNKNOWN, "strdup failed");
275 }
210 } 276 }
211 break; 277 break;
212 case 'n': 278 case 'n':
213 upgrade=NO_UPGRADE; 279 result.config.upgrade = NO_UPGRADE;
214 break; 280 break;
215 case 'u': 281 case 'u':
216 do_update=true; 282 result.config.do_update = true;
217 if(optarg!=NULL){ 283 if (optarg != NULL) {
218 update_opts=strdup(optarg); 284 result.config.update_opts = strdup(optarg);
219 if(update_opts==NULL) die(STATE_UNKNOWN, "strdup failed"); 285 if (result.config.update_opts == NULL) {
286 die(STATE_UNKNOWN, "strdup failed");
287 }
220 } 288 }
221 break; 289 break;
222 case 'l': 290 case 'l':
223 list=true; 291 result.config.list = true;
224 break; 292 break;
225 case 'i': 293 case 'i':
226 do_include=add_to_regexp(do_include, optarg); 294 result.config.do_include = add_to_regexp(result.config.do_include, optarg);
227 break; 295 break;
228 case 'e': 296 case 'e':
229 do_exclude=add_to_regexp(do_exclude, optarg); 297 result.config.do_exclude = add_to_regexp(result.config.do_exclude, optarg);
230 break; 298 break;
231 case 'c': 299 case 'c':
232 do_critical=add_to_regexp(do_critical, optarg); 300 result.config.do_critical = add_to_regexp(result.config.do_critical, optarg);
233 break; 301 break;
234 case 'o': 302 case 'o':
235 only_critical=true; 303 result.config.only_critical = true;
236 break; 304 break;
237 case INPUT_FILE_OPT: 305 case INPUT_FILE_OPT:
238 input_filename = optarg; 306 result.config.input_filename = optarg;
239 break; 307 break;
240 case 'w': 308 case 'w':
241 packages_warning = atoi(optarg); 309 result.config.packages_warning = atoi(optarg);
310 break;
311 case output_format_index: {
312 parsed_output_format parser = mp_parse_output_format(optarg);
313 if (!parser.parsing_success) {
314 // TODO List all available formats here, maybe add anothoer usage function
315 printf("Invalid output format: %s\n", optarg);
316 exit(STATE_UNKNOWN);
317 }
318
319 result.config.output_format_is_set = true;
320 result.config.output_format = parser.output_format;
242 break; 321 break;
322 }
243 default: 323 default:
244 /* print short usage statement if args not parsable */ 324 /* print short usage statement if args not parsable */
245 usage5(); 325 usage5();
246 } 326 }
247 } 327 }
248 328
249 return OK; 329 return result;
250} 330}
251 331
252
253/* run an apt-get upgrade */ 332/* run an apt-get upgrade */
254int run_upgrade(int *pkgcount, int *secpkgcount, char ***pkglist, char ***secpkglist){ 333run_upgrade_result run_upgrade(const upgrade_type upgrade, const char *do_include,
255 int result=STATE_UNKNOWN, regres=0, pc=0, spc=0; 334 const char *do_exclude, const char *do_critical,
256 struct output chld_out, chld_err; 335 const char *upgrade_opts, const char *input_filename) {
257 regex_t ireg, ereg, sreg; 336 regex_t exclude_regex;
258 char *cmdline=NULL, rerrbuf[64];
259
260 /* initialize ereg as it is possible it is printed while uninitialized */ 337 /* initialize ereg as it is possible it is printed while uninitialized */
261 memset(&ereg, '\0', sizeof(ereg.buffer)); 338 memset(&exclude_regex, '\0', sizeof(exclude_regex.buffer));
262 339
263 if(upgrade==NO_UPGRADE) return STATE_OK; 340 run_upgrade_result result = {
341 .errorcode = OK,
342 };
264 343
344 if (upgrade == NO_UPGRADE) {
345 result.errorcode = OK;
346 return result;
347 }
348
349 int regres = 0;
350 regex_t include_regex;
351 char rerrbuf[64];
265 /* compile the regexps */ 352 /* compile the regexps */
266 if (do_include != NULL) { 353 if (do_include != NULL) {
267 regres=regcomp(&ireg, do_include, REG_EXTENDED); 354 regres = regcomp(&include_regex, do_include, REG_EXTENDED);
268 if (regres!=0) { 355 if (regres != 0) {
269 regerror(regres, &ireg, rerrbuf, 64); 356 regerror(regres, &include_regex, rerrbuf, 64);
270 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf); 357 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf);
271 } 358 }
272 } 359 }
273 360
274 if(do_exclude!=NULL){ 361 if (do_exclude != NULL) {
275 regres=regcomp(&ereg, do_exclude, REG_EXTENDED); 362 regres = regcomp(&exclude_regex, do_exclude, REG_EXTENDED);
276 if(regres!=0) { 363 if (regres != 0) {
277 regerror(regres, &ereg, rerrbuf, 64); 364 regerror(regres, &exclude_regex, rerrbuf, 64);
278 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), 365 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf);
279 progname, rerrbuf);
280 } 366 }
281 } 367 }
282 368
369 regex_t sreg;
283 const char *crit_ptr = (do_critical != NULL) ? do_critical : SECURITY_RE; 370 const char *crit_ptr = (do_critical != NULL) ? do_critical : SECURITY_RE;
284 regres=regcomp(&sreg, crit_ptr, REG_EXTENDED); 371 regres = regcomp(&sreg, crit_ptr, REG_EXTENDED);
285 if(regres!=0) { 372 if (regres != 0) {
286 regerror(regres, &ereg, rerrbuf, 64); 373 regerror(regres, &exclude_regex, rerrbuf, 64);
287 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), 374 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf);
288 progname, rerrbuf);
289 } 375 }
290 376
291 cmdline=construct_cmdline(upgrade, upgrade_opts); 377 output chld_out;
378 output chld_err;
379 char *cmdline = NULL;
380 cmdline = construct_cmdline(upgrade, upgrade_opts);
292 if (input_filename != NULL) { 381 if (input_filename != NULL) {
293 /* read input from a file for testing */ 382 /* read input from a file for testing */
294 result = cmd_file_read(input_filename, &chld_out, 0); 383 result.errorcode = cmd_file_read(input_filename, &chld_out, 0);
295 } else { 384 } else {
296 /* run the upgrade */ 385 /* run the upgrade */
297 result = np_runcmd(cmdline, &chld_out, &chld_err, 0); 386 result.errorcode = np_runcmd(cmdline, &chld_out, &chld_err, 0);
298 } 387 }
299 388
300 /* apt-get upgrade only changes exit status if there is an 389 // apt-get upgrade only changes exit status if there is an
301 * internal error when run in dry-run mode. therefore we will 390 // internal error when run in dry-run mode.
302 * treat such an error as UNKNOWN */ 391 if (result.errorcode != 0) {
303 if(result != 0){ 392 result.exec_warning = true;
304 exec_warning=1; 393 result.errorcode = ERROR;
305 result = STATE_UNKNOWN; 394 // fprintf(stderr, _("'%s' exited with non-zero status.\n"), cmdline);
306 fprintf(stderr, _("'%s' exited with non-zero status.\n"),
307 cmdline);
308 } 395 }
309 396
310 *pkglist=malloc(sizeof(char *) * chld_out.lines); 397 char **pkglist = malloc(sizeof(char *) * chld_out.lines);
311 if(!pkglist) die(STATE_UNKNOWN, "malloc failed!\n"); 398 if (!pkglist) {
312 *secpkglist=malloc(sizeof(char *) * chld_out.lines); 399 die(STATE_UNKNOWN, "malloc failed!\n");
313 if(!secpkglist) die(STATE_UNKNOWN, "malloc failed!\n"); 400 }
401 char **secpkglist = malloc(sizeof(char *) * chld_out.lines);
402 if (!secpkglist) {
403 die(STATE_UNKNOWN, "malloc failed!\n");
404 }
314 405
315 /* parse the output, which should only consist of lines like 406 /* parse the output, which should only consist of lines like
316 * 407 *
@@ -321,242 +412,293 @@ int run_upgrade(int *pkgcount, int *secpkgcount, char ***pkglist, char ***secpkg
321 * we may need to switch to the --print-uris output format, 412 * we may need to switch to the --print-uris output format,
322 * in which case the logic here will slightly change. 413 * in which case the logic here will slightly change.
323 */ 414 */
324 for(size_t i = 0; i < chld_out.lines; i++) { 415 size_t package_counter = 0;
325 if(verbose){ 416 size_t security_package_counter = 0;
417 for (size_t i = 0; i < chld_out.lines; i++) {
418 if (verbose) {
326 printf("%s\n", chld_out.line[i]); 419 printf("%s\n", chld_out.line[i]);
327 } 420 }
421
328 /* if it is a package we care about */ 422 /* if it is a package we care about */
329 if (strncmp(PKGINST_PREFIX, chld_out.line[i], strlen(PKGINST_PREFIX)) == 0 && 423 if (strncmp(PKGINST_PREFIX, chld_out.line[i], strlen(PKGINST_PREFIX)) == 0 &&
330 (do_include == NULL || regexec(&ireg, chld_out.line[i], 0, NULL, 0) == 0)) { 424 (do_include == NULL || regexec(&include_regex, chld_out.line[i], 0, NULL, 0) == 0)) {
331 /* if we're not excluding, or it's not in the 425 /* if we're not excluding, or it's not in the
332 * list of stuff to exclude */ 426 * list of stuff to exclude */
333 if(do_exclude==NULL || 427 if (do_exclude == NULL || regexec(&exclude_regex, chld_out.line[i], 0, NULL, 0) != 0) {
334 regexec(&ereg, chld_out.line[i], 0, NULL, 0)!=0){ 428 package_counter++;
335 pc++; 429 if (regexec(&sreg, chld_out.line[i], 0, NULL, 0) == 0) {
336 if(regexec(&sreg, chld_out.line[i], 0, NULL, 0)==0){ 430 security_package_counter++;
337 spc++; 431
338 if(verbose) printf("*"); 432 if (verbose) {
339 (*secpkglist)[spc-1] = pkg_name(chld_out.line[i]); 433 printf("*");
434 }
435
436 (secpkglist)[security_package_counter - 1] = pkg_name(chld_out.line[i]);
340 } else { 437 } else {
341 (*pkglist)[pc-spc-1] = pkg_name(chld_out.line[i]); 438 (pkglist)[package_counter - security_package_counter - 1] =
439 pkg_name(chld_out.line[i]);
342 } 440 }
343 if(verbose){ 441 if (verbose) {
344 printf("*%s\n", chld_out.line[i]); 442 printf("*%s\n", chld_out.line[i]);
345 } 443 }
346 } 444 }
347 } 445 }
348 } 446 }
349 *pkgcount=pc; 447
350 *secpkgcount=spc; 448 result.package_count = package_counter;
449 result.security_package_count = security_package_counter;
450 result.packages_list = pkglist;
451 result.secpackages_list = secpkglist;
351 452
352 /* If we get anything on stderr, at least set warning */ 453 /* If we get anything on stderr, at least set warning */
353 if (input_filename == NULL && chld_err.buflen) { 454 if (input_filename == NULL && chld_err.buflen) {
354 stderr_warning=1; 455 stderr_warning = true;
355 result = max_state(result, STATE_WARNING); 456 result.errorcode = ERROR;
356 if(verbose){ 457
357 for(size_t i = 0; i < chld_err.lines; i++) { 458 if (verbose) {
459 for (size_t i = 0; i < chld_err.lines; i++) {
358 fprintf(stderr, "%s\n", chld_err.line[i]); 460 fprintf(stderr, "%s\n", chld_err.line[i]);
359 } 461 }
360 } 462 }
361 } 463 }
362 if (do_include != NULL) regfree(&ireg); 464
465 if (do_include != NULL) {
466 regfree(&include_regex);
467 }
468
363 regfree(&sreg); 469 regfree(&sreg);
364 if(do_exclude!=NULL) regfree(&ereg); 470
471 if (do_exclude != NULL) {
472 regfree(&exclude_regex);
473 }
474
365 free(cmdline); 475 free(cmdline);
476
366 return result; 477 return result;
367} 478}
368 479
369/* run an apt-get update (needs root) */ 480/* run an apt-get update (needs root) */
370int run_update(void){ 481run_update_result run_update(char *update_opts) {
371 int result=STATE_UNKNOWN;
372 struct output chld_out, chld_err;
373 char *cmdline; 482 char *cmdline;
374
375 /* run the update */ 483 /* run the update */
376 cmdline = construct_cmdline(NO_UPGRADE, update_opts); 484 cmdline = construct_cmdline(NO_UPGRADE, update_opts);
377 result = np_runcmd(cmdline, &chld_out, &chld_err, 0); 485
486 run_update_result result = {
487 .exec_warning = false,
488 .stderr_warning = false,
489 .sc = mp_subcheck_init(),
490 };
491
492 result.sc = mp_set_subcheck_default_state(result.sc, STATE_OK);
493 xasprintf(&result.sc.output, "executing '%s' first", cmdline);
494
495 output chld_out;
496 output chld_err;
497 int cmd_error = np_runcmd(cmdline, &chld_out, &chld_err, 0);
378 /* apt-get update changes exit status if it can't fetch packages. 498 /* apt-get update changes exit status if it can't fetch packages.
379 * since we were explicitly asked to do so, this is treated as 499 * since we were explicitly asked to do so, this is treated as
380 * a critical error. */ 500 * a critical error. */
381 if(result != 0){ 501 if (cmd_error != 0) {
382 exec_warning=1; 502 exec_warning = true;
383 result = STATE_CRITICAL; 503 result.sc = mp_set_subcheck_state(result.sc, STATE_CRITICAL);
384 fprintf(stderr, _("'%s' exited with non-zero status.\n"), 504 xasprintf(&result.sc.output, _("'%s' exited with non-zero status.\n"), cmdline);
385 cmdline);
386 } 505 }
387 506
388 if(verbose){ 507 if (verbose) {
389 for(size_t i = 0; i < chld_out.lines; i++) { 508 for (size_t i = 0; i < chld_out.lines; i++) {
390 printf("%s\n", chld_out.line[i]); 509 printf("%s\n", chld_out.line[i]);
391 } 510 }
392 } 511 }
393 512
394 /* If we get anything on stderr, at least set warning */ 513 /* If we get anything on stderr, at least set warning */
395 if(chld_err.buflen){ 514 if (chld_err.buflen) {
396 stderr_warning=1; 515 stderr_warning = true;
397 result = max_state(result, STATE_WARNING); 516 result.sc = mp_set_subcheck_state(
398 if(verbose){ 517 result.sc, max_state(mp_compute_subcheck_state(result.sc), STATE_WARNING));
399 for(size_t i = 0; i < chld_err.lines; i++) { 518 if (verbose) {
519 for (size_t i = 0; i < chld_err.lines; i++) {
400 fprintf(stderr, "%s\n", chld_err.line[i]); 520 fprintf(stderr, "%s\n", chld_err.line[i]);
401 } 521 }
402 } 522 }
403 } 523 }
524
404 free(cmdline); 525 free(cmdline);
526
405 return result; 527 return result;
406} 528}
407 529
408char* pkg_name(char *line){ 530char *pkg_name(char *line) {
409 char *start=NULL, *space=NULL, *pkg=NULL; 531 char *start = line + strlen(PKGINST_PREFIX);
410 int len=0;
411 532
412 start = line + strlen(PKGINST_PREFIX); 533 size_t len = strlen(start);
413 len = strlen(start);
414 534
415 space = index(start, ' '); 535 char *space = index(start, ' ');
416 if(space!=NULL){ 536 if (space != NULL) {
417 len = space - start; 537 len = space - start;
418 } 538 }
419 539
420 pkg=malloc(sizeof(char)*(len+1)); 540 char *pkg = malloc(sizeof(char) * (len + 1));
421 if(!pkg) die(STATE_UNKNOWN, "malloc failed!\n"); 541 if (!pkg) {
542 die(STATE_UNKNOWN, "malloc failed!\n");
543 }
422 544
423 strncpy(pkg, start, len); 545 strncpy(pkg, start, len);
424 pkg[len]='\0'; 546 pkg[len] = '\0';
425 547
426 return pkg; 548 return pkg;
427} 549}
428 550
429int cmpstringp(const void *p1, const void *p2){ 551int cmpstringp(const void *left_string, const void *right_string) {
430 return strcmp(* (char * const *) p1, * (char * const *) p2); 552 return strcmp(*(char *const *)left_string, *(char *const *)right_string);
431} 553}
432 554
433char* add_to_regexp(char *expr, const char *next){ 555char *add_to_regexp(char *expr, const char *next) {
434 char *re=NULL; 556 char *regex_string = NULL;
435 557
436 if(expr==NULL){ 558 if (expr == NULL) {
437 re=malloc(sizeof(char)*(strlen("()")+strlen(next)+1)); 559 regex_string = malloc(sizeof(char) * (strlen("()") + strlen(next) + 1));
438 if(!re) die(STATE_UNKNOWN, "malloc failed!\n"); 560 if (!regex_string) {
439 sprintf(re, "(%s)", next); 561 die(STATE_UNKNOWN, "malloc failed!\n");
562 }
563 sprintf(regex_string, "(%s)", next);
440 } else { 564 } else {
441 /* resize it, adding an extra char for the new '|' separator */ 565 /* resize it, adding an extra char for the new '|' separator */
442 re=realloc(expr, sizeof(char)*(strlen(expr)+1+strlen(next)+1)); 566 regex_string = realloc(expr, sizeof(char) * (strlen(expr) + 1 + strlen(next) + 1));
443 if(!re) die(STATE_UNKNOWN, "realloc failed!\n"); 567 if (!regex_string) {
568 die(STATE_UNKNOWN, "realloc failed!\n");
569 }
444 /* append it starting at ')' in the old re */ 570 /* append it starting at ')' in the old re */
445 sprintf((char*)(re+strlen(re)-1), "|%s)", next); 571 sprintf((char *)(regex_string + strlen(regex_string) - 1), "|%s)", next);
446 } 572 }
447 573
448 return re; 574 return regex_string;
449} 575}
450 576
451char* construct_cmdline(upgrade_type u, const char *opts){ 577char *construct_cmdline(upgrade_type upgrade, const char *opts) {
452 int len=0; 578 const char *opts_ptr = NULL;
453 const char *opts_ptr=NULL, *aptcmd=NULL; 579 const char *aptcmd = NULL;
454 char *cmd=NULL;
455 580
456 switch(u){ 581 switch (upgrade) {
457 case UPGRADE: 582 case UPGRADE:
458 if(opts==NULL) opts_ptr=UPGRADE_DEFAULT_OPTS; 583 if (opts == NULL) {
459 else opts_ptr=opts; 584 opts_ptr = UPGRADE_DEFAULT_OPTS;
460 aptcmd="upgrade"; 585 } else {
586 opts_ptr = opts;
587 }
588 aptcmd = "upgrade";
461 break; 589 break;
462 case DIST_UPGRADE: 590 case DIST_UPGRADE:
463 if(opts==NULL) opts_ptr=UPGRADE_DEFAULT_OPTS; 591 if (opts == NULL) {
464 else opts_ptr=opts; 592 opts_ptr = UPGRADE_DEFAULT_OPTS;
465 aptcmd="dist-upgrade"; 593 } else {
594 opts_ptr = opts;
595 }
596 aptcmd = "dist-upgrade";
466 break; 597 break;
467 case NO_UPGRADE: 598 case NO_UPGRADE:
468 if(opts==NULL) opts_ptr=UPDATE_DEFAULT_OPTS; 599 if (opts == NULL) {
469 else opts_ptr=opts; 600 opts_ptr = UPDATE_DEFAULT_OPTS;
470 aptcmd="update"; 601 } else {
602 opts_ptr = opts;
603 }
604 aptcmd = "update";
471 break; 605 break;
472 } 606 }
473 607
474 len+=strlen(PATH_TO_APTGET)+1; /* "/usr/bin/apt-get " */ 608 size_t len = 0;
475 len+=strlen(opts_ptr)+1; /* "opts " */ 609 len += strlen(PATH_TO_APTGET) + 1; /* "/usr/bin/apt-get " */
476 len+=strlen(aptcmd)+1; /* "upgrade\0" */ 610 len += strlen(opts_ptr) + 1; /* "opts " */
611 len += strlen(aptcmd) + 1; /* "upgrade\0" */
477 612
478 cmd=(char*)malloc(sizeof(char)*len); 613 char *cmd = (char *)malloc(sizeof(char) * len);
479 if(cmd==NULL) die(STATE_UNKNOWN, "malloc failed"); 614 if (cmd == NULL) {
615 die(STATE_UNKNOWN, "malloc failed");
616 }
480 sprintf(cmd, "%s %s %s", PATH_TO_APTGET, opts_ptr, aptcmd); 617 sprintf(cmd, "%s %s %s", PATH_TO_APTGET, opts_ptr, aptcmd);
481 return cmd; 618 return cmd;
482} 619}
483 620
484/* informative help message */ 621/* informative help message */
485void 622void print_help(void) {
486print_help (void) 623 print_revision(progname, NP_VERSION);
487{ 624
488 print_revision(progname, NP_VERSION); 625 printf(_(COPYRIGHT), copyright, email);
489 626
490 printf(_(COPYRIGHT), copyright, email); 627 printf("%s\n", _("This plugin checks for software updates on systems that use"));
491 628 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")); 629 printf("%s\n", _("found in Debian GNU/Linux"));
493 printf("%s\n", _("package management systems based on the apt-get(8) command")); 630
494 printf("%s\n", _("found in Debian GNU/Linux")); 631 printf("\n\n");
495 632
496 printf ("\n\n"); 633 print_usage();
497 634
498 print_usage(); 635 printf(UT_HELP_VRSN);
499 636 printf(UT_EXTRA_OPTS);
500 printf(UT_HELP_VRSN); 637
501 printf(UT_EXTRA_OPTS); 638 printf(UT_PLUG_TIMEOUT, timeout_interval);
502 639
503 printf(UT_PLUG_TIMEOUT, timeout_interval); 640 printf(" %s\n", "-n, --no-upgrade");
504 641 printf(" %s\n", _("Do not run the upgrade. Probably not useful (without -u at least)."));
505 printf (" %s\n", "-n, --no-upgrade"); 642 printf(" %s\n", "-l, --list");
506 printf (" %s\n", _("Do not run the upgrade. Probably not useful (without -u at least).")); 643 printf(" %s\n", _("List packages available for upgrade. Packages are printed sorted by"));
507 printf (" %s\n", "-l, --list"); 644 printf(" %s\n", _("name with security packages listed first."));
508 printf (" %s\n", _("List packages available for upgrade. Packages are printed sorted by")); 645 printf(" %s\n", "-i, --include=REGEXP");
509 printf (" %s\n", _("name with security packages listed first.")); 646 printf(" %s\n",
510 printf (" %s\n", "-i, --include=REGEXP"); 647 _("Include only packages matching REGEXP. Can be specified multiple times"));
511 printf (" %s\n", _("Include only packages matching REGEXP. Can be specified multiple times")); 648 printf(" %s\n", _("the values will be combined together. Any packages matching this list"));
512 printf (" %s\n", _("the values will be combined together. Any packages matching this list")); 649 printf(" %s\n", _("cause the plugin to return WARNING status. Others will be ignored."));
513 printf (" %s\n", _("cause the plugin to return WARNING status. Others will be ignored.")); 650 printf(" %s\n", _("Default is to include all packages."));
514 printf (" %s\n", _("Default is to include all packages.")); 651 printf(" %s\n", "-e, --exclude=REGEXP");
515 printf (" %s\n", "-e, --exclude=REGEXP"); 652 printf(" %s\n", _("Exclude packages matching REGEXP from the list of packages that would"));
516 printf (" %s\n", _("Exclude packages matching REGEXP from the list of packages that would")); 653 printf(" %s\n", _("otherwise be included. Can be specified multiple times; the values"));
517 printf (" %s\n", _("otherwise be included. Can be specified multiple times; the values")); 654 printf(" %s\n", _("will be combined together. Default is to exclude no packages."));
518 printf (" %s\n", _("will be combined together. Default is to exclude no packages.")); 655 printf(" %s\n", "-c, --critical=REGEXP");
519 printf (" %s\n", "-c, --critical=REGEXP"); 656 printf(" %s\n",
520 printf (" %s\n", _("If the full package information of any of the upgradable packages match")); 657 _("If the full package information of any of the upgradable packages match"));
521 printf (" %s\n", _("this REGEXP, the plugin will return CRITICAL status. Can be specified")); 658 printf(" %s\n", _("this REGEXP, the plugin will return CRITICAL status. Can be specified"));
522 printf (" %s\n", _("multiple times like above. Default is a regexp matching security")); 659 printf(" %s\n", _("multiple times like above. Default is a regexp matching security"));
523 printf (" %s\n", _("upgrades for Debian and Ubuntu:")); 660 printf(" %s\n", _("upgrades for Debian and Ubuntu:"));
524 printf (" \t%s\n", SECURITY_RE); 661 printf(" \t%s\n", SECURITY_RE);
525 printf (" %s\n", _("Note that the package must first match the include list before its")); 662 printf(" %s\n", _("Note that the package must first match the include list before its"));
526 printf (" %s\n", _("information is compared against the critical list.")); 663 printf(" %s\n", _("information is compared against the critical list."));
527 printf (" %s\n", "-o, --only-critical"); 664 printf(" %s\n", "-o, --only-critical");
528 printf (" %s\n", _("Only warn about upgrades matching the critical list. The total number")); 665 printf(" %s\n", _("Only warn about upgrades matching the critical list. The total number"));
529 printf (" %s\n", _("of upgrades will be printed, but any non-critical upgrades will not cause")); 666 printf(" %s\n",
530 printf (" %s\n", _("the plugin to return WARNING status.")); 667 _("of upgrades will be printed, but any non-critical upgrades will not cause"));
531 printf (" %s\n", "-w, --packages-warning"); 668 printf(" %s\n", _("the plugin to return WARNING status."));
532 printf (" %s\n", _("Minimum number of packages available for upgrade to return WARNING status.")); 669 printf(" %s\n", "-w, --packages-warning");
533 printf (" %s\n\n", _("Default is 1 package.")); 670 printf(" %s\n",
534 671 _("Minimum number of packages available for upgrade to return WARNING status."));
535 printf ("%s\n\n", _("The following options require root privileges and should be used with care:")); 672 printf(" %s\n\n", _("Default is 1 package."));
536 printf (" %s\n", "-u, --update=OPTS"); 673
537 printf (" %s\n", _("First perform an 'apt-get update'. An optional OPTS parameter overrides")); 674 printf(UT_OUTPUT_FORMAT);
538 printf (" %s\n", _("the default options. Note: you may also need to adjust the global")); 675
539 printf (" %s\n", _("timeout (with -t) to prevent the plugin from timing out if apt-get")); 676 printf("%s\n\n",
540 printf (" %s\n", _("upgrade is expected to take longer than the default timeout.")); 677 _("The following options require root privileges and should be used with care:"));
541 printf (" %s\n", "-U, --upgrade=OPTS"); 678 printf(" %s\n", "-u, --update=OPTS");
542 printf (" %s\n", _("Perform an upgrade. If an optional OPTS argument is provided,")); 679 printf(" %s\n",
543 printf (" %s\n", _("apt-get will be run with these command line options instead of the")); 680 _("First perform an 'apt-get update'. An optional OPTS parameter overrides"));
544 printf (" %s", _("default ")); 681 printf(" %s\n", _("the default options. Note: you may also need to adjust the global"));
545 printf ("(%s).\n", UPGRADE_DEFAULT_OPTS); 682 printf(" %s\n", _("timeout (with -t) to prevent the plugin from timing out if apt-get"));
546 printf (" %s\n", _("Note that you may be required to have root privileges if you do not use")); 683 printf(" %s\n", _("upgrade is expected to take longer than the default timeout."));
547 printf (" %s\n", _("the default options, which will only run a simulation and NOT perform the upgrade")); 684 printf(" %s\n", "-U, --upgrade=OPTS");
548 printf (" %s\n", "-d, --dist-upgrade=OPTS"); 685 printf(" %s\n", _("Perform an upgrade. If an optional OPTS argument is provided,"));
549 printf (" %s\n", _("Perform a dist-upgrade instead of normal upgrade. Like with -U OPTS")); 686 printf(" %s\n", _("apt-get will be run with these command line options instead of the"));
550 printf (" %s\n", _("can be provided to override the default options.")); 687 printf(" %s", _("default "));
551 688 printf("(%s).\n", UPGRADE_DEFAULT_OPTS);
552 printf(UT_SUPPORT); 689 printf(" %s\n",
690 _("Note that you may be required to have root privileges if you do not use"));
691 printf(" %s\n",
692 _("the default options, which will only run a simulation and NOT perform the upgrade"));
693 printf(" %s\n", "-d, --dist-upgrade=OPTS");
694 printf(" %s\n", _("Perform a dist-upgrade instead of normal upgrade. Like with -U OPTS"));
695 printf(" %s\n", _("can be provided to override the default options."));
696
697 printf(UT_SUPPORT);
553} 698}
554 699
555
556/* simple usage heading */ 700/* simple usage heading */
557void 701void print_usage(void) {
558print_usage(void) 702 printf("%s\n", _("Usage:"));
559{ 703 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} 704}
diff --git a/plugins/check_apt.d/config.h b/plugins/check_apt.d/config.h
new file mode 100644
index 00000000..e4d622f1
--- /dev/null
+++ b/plugins/check_apt.d/config.h
@@ -0,0 +1,46 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5#include "../lib/output.h"
6
7/* some constants */
8typedef enum {
9 UPGRADE,
10 DIST_UPGRADE,
11 NO_UPGRADE
12} upgrade_type;
13
14typedef struct {
15 bool do_update; /* whether to call apt-get update */
16 upgrade_type upgrade; /* which type of upgrade to do */
17 bool only_critical; /* whether to warn about non-critical updates */
18 bool list; /* list packages available for upgrade */
19 /* number of packages available for upgrade to return WARNING status */
20 size_t packages_warning;
21
22 char *upgrade_opts; /* options to override defaults for upgrade */
23 char *update_opts; /* options to override defaults for update */
24 char *do_include; /* regexp to only include certain packages */
25 char *do_exclude; /* regexp to only exclude certain packages */
26 char *do_critical; /* regexp specifying critical packages */
27 char *input_filename; /* input filename for testing */
28
29 bool output_format_is_set;
30 mp_output_format output_format;
31} check_apt_config;
32
33check_apt_config check_apt_config_init() {
34 check_apt_config tmp = {.do_update = false,
35 .upgrade = UPGRADE,
36 .only_critical = false,
37 .list = false,
38 .packages_warning = 1,
39 .update_opts = NULL,
40 .do_include = NULL,
41 .do_exclude = NULL,
42 .do_critical = NULL,
43 .input_filename = NULL,
44 .output_format_is_set = false};
45 return tmp;
46}
diff --git a/plugins/check_by_ssh.c b/plugins/check_by_ssh.c
index 2a23b397..a43c0d34 100644
--- a/plugins/check_by_ssh.c
+++ b/plugins/check_by_ssh.c
@@ -1,186 +1,183 @@
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
48unsigned int commands = 0; 49 validate_arguments(check_by_ssh_config_wrapper /*config_wrapper*/);
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 50
68 char *status_text; 51static command_construct comm_append(command_construct /*cmd*/, const char * /*str*/);
69 int cresult; 52static void print_help(void);
70 int result = STATE_UNKNOWN; 53void print_usage(void);
71 time_t local_time;
72 FILE *fp = NULL;
73 output chld_out, chld_err;
74 54
75 remotecmd = ""; 55static bool verbose = false;
76 comm_append(SSH_COMMAND);
77 56
78 setlocale (LC_ALL, ""); 57int main(int argc, char **argv) {
79 bindtextdomain (PACKAGE, LOCALEDIR); 58 setlocale(LC_ALL, "");
80 textdomain (PACKAGE); 59 bindtextdomain(PACKAGE, LOCALEDIR);
60 textdomain(PACKAGE);
81 61
82 /* Parse extra opts if any */ 62 /* Parse extra opts if any */
83 argv=np_extra_opts (&argc, argv, progname); 63 argv = np_extra_opts(&argc, argv, progname);
64
65 check_by_ssh_config_wrapper tmp_config = process_arguments(argc, argv);
84 66
85 /* process arguments */ 67 /* process arguments */
86 if (process_arguments (argc, argv) == ERROR) 68 if (tmp_config.errorcode == ERROR) {
87 usage_va(_("Could not parse arguments")); 69 usage_va(_("Could not parse arguments"));
70 }
71
72 const check_by_ssh_config config = tmp_config.config;
88 73
89 /* Set signal handling and alarm timeout */ 74 /* Set signal handling and alarm timeout */
90 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 75 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
91 usage_va(_("Cannot catch SIGALRM")); 76 usage_va(_("Cannot catch SIGALRM"));
92 } 77 }
93 alarm (timeout_interval); 78 alarm(timeout_interval);
94 79
95 /* run the command */ 80 /* run the command */
96 if (verbose) { 81 if (verbose) {
97 printf ("Command: %s\n", commargv[0]); 82 printf("Command: %s\n", config.cmd.commargv[0]);
98 for (int i = 1; i < commargc; i++) 83 for (int i = 1; i < config.cmd.commargc; i++) {
99 printf ("Argument %i: %s\n", i, commargv[i]); 84 printf("Argument %i: %s\n", i, config.cmd.commargv[i]);
85 }
100 } 86 }
101 87
102 result = cmd_run_array (commargv, &chld_out, &chld_err, 0); 88 output chld_out;
89 output chld_err;
90 mp_state_enum result = cmd_run_array(config.cmd.commargv, &chld_out, &chld_err, 0);
103 91
104 /* SSH returns 255 if connection attempt fails; include the first line of error output */ 92 /* SSH returns 255 if connection attempt fails; include the first line of error output */
105 if (result == 255 && unknown_timeout) { 93 if (result == 255 && config.unknown_timeout) {
106 printf (_("SSH connection failed: %s\n"), 94 printf(_("SSH connection failed: %s\n"),
107 chld_err.lines > 0 ? chld_err.line[0] : "(no error output)"); 95 chld_err.lines > 0 ? chld_err.line[0] : "(no error output)");
108 return STATE_UNKNOWN; 96 return STATE_UNKNOWN;
109 } 97 }
110 98
111 if (verbose) { 99 if (verbose) {
112 for(size_t i = 0; i < chld_out.lines; i++) 100 for (size_t i = 0; i < chld_out.lines; i++) {
113 printf("stdout: %s\n", chld_out.line[i]); 101 printf("stdout: %s\n", chld_out.line[i]);
114 for(size_t i = 0; i < chld_err.lines; i++) 102 }
103 for (size_t i = 0; i < chld_err.lines; i++) {
115 printf("stderr: %s\n", chld_err.line[i]); 104 printf("stderr: %s\n", chld_err.line[i]);
105 }
116 } 106 }
117 107
118 if (skip_stdout == -1) /* --skip-stdout specified without argument */ 108 size_t skip_stdout = 0;
109 if (config.skip_stdout == -1) { /* --skip-stdout specified without argument */
119 skip_stdout = chld_out.lines; 110 skip_stdout = chld_out.lines;
120 if (skip_stderr == -1) /* --skip-stderr specified without argument */ 111 } else {
112 skip_stdout = config.skip_stdout;
113 }
114
115 size_t skip_stderr = 0;
116 if (config.skip_stderr == -1) { /* --skip-stderr specified without argument */
121 skip_stderr = chld_err.lines; 117 skip_stderr = chld_err.lines;
118 } else {
119 skip_stderr = config.skip_stderr;
120 }
122 121
123 /* UNKNOWN or worse if (non-skipped) output found on stderr */ 122 /* Allow UNKNOWN or WARNING state for (non-skipped) output found on stderr */
124 if(chld_err.lines > (size_t)skip_stderr) { 123 if (chld_err.lines > (size_t)skip_stderr && (config.unknown_on_stderr || config.warn_on_stderr)) {
125 printf (_("Remote command execution failed: %s\n"), 124 printf(_("Remote command execution failed: %s\n"), chld_err.line[skip_stderr]);
126 chld_err.line[skip_stderr]); 125 if (config.unknown_on_stderr) {
127 if ( warn_on_stderr )
128 return max_state_alt(result, STATE_WARNING);
129 else
130 return max_state_alt(result, STATE_UNKNOWN); 126 return max_state_alt(result, STATE_UNKNOWN);
127 } else if (config.warn_on_stderr) {
128 return max_state_alt(result, STATE_WARNING);
129 }
131 } 130 }
132 131
133 /* this is simple if we're not supposed to be passive. 132 /* this is simple if we're not supposed to be passive.
134 * Wrap up quickly and keep the tricks below */ 133 * Wrap up quickly and keep the tricks below */
135 if(!passive) { 134 if (!config.passive) {
136 if (chld_out.lines > (size_t)skip_stdout) 135 if (chld_out.lines > (size_t)skip_stdout) {
137 for (size_t i = skip_stdout; i < chld_out.lines; i++) 136 for (size_t i = skip_stdout; i < chld_out.lines; i++) {
138 puts (chld_out.line[i]); 137 puts(chld_out.line[i]);
139 else 138 }
140 printf (_("%s - check_by_ssh: Remote command '%s' returned status %d\n"), 139 } else {
141 state_text(result), remotecmd, result); 140 printf(_("%s - check_by_ssh: Remote command '%s' returned status %d\n"),
142 return result; /* return error status from remote command */ 141 state_text(result), config.remotecmd, result);
142 }
143 return result; /* return error status from remote command */
143 } 144 }
144 145
145
146 /* 146 /*
147 * Passive mode 147 * Passive mode
148 */ 148 */
149 149
150 /* process output */ 150 /* process output */
151 if (!(fp = fopen (outputfile, "a"))) { 151 FILE *file_pointer = NULL;
152 printf (_("SSH WARNING: could not open %s\n"), outputfile); 152 if (!(file_pointer = fopen(config.outputfile, "a"))) {
153 exit (STATE_UNKNOWN); 153 printf(_("SSH WARNING: could not open %s\n"), config.outputfile);
154 exit(STATE_UNKNOWN);
154 } 155 }
155 156
156 local_time = time (NULL); 157 time_t local_time = time(NULL);
157 commands = 0; 158 unsigned int commands = 0;
158 for(size_t i = skip_stdout; i < chld_out.lines; i++) { 159 char *status_text;
160 int cresult;
161 for (size_t i = skip_stdout; i < chld_out.lines; i++) {
159 status_text = chld_out.line[i++]; 162 status_text = chld_out.line[i++];
160 if (i == chld_out.lines || strstr (chld_out.line[i], "STATUS CODE: ") == NULL) 163 if (i == chld_out.lines || strstr(chld_out.line[i], "STATUS CODE: ") == NULL) {
161 die (STATE_UNKNOWN, _("%s: Error parsing output\n"), progname); 164 die(STATE_UNKNOWN, _("%s: Error parsing output\n"), progname);
162 165 }
163 if (service[commands] && status_text 166
164 && sscanf (chld_out.line[i], "STATUS CODE: %d", &cresult) == 1) 167 if (config.service[commands] && status_text &&
165 { 168 sscanf(chld_out.line[i], "STATUS CODE: %d", &cresult) == 1) {
166 fprintf (fp, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n", 169 fprintf(file_pointer, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n",
167 (int) local_time, host_shortname, service[commands++], 170 (int)local_time, config.host_shortname, config.service[commands++], cresult,
168 cresult, status_text); 171 status_text);
169 } 172 }
170 } 173 }
171 174
172 /* Multiple commands and passive checking should always return OK */ 175 /* Multiple commands and passive checking should always return OK */
173 return result; 176 exit(result);
174} 177}
175 178
176/* process command-line arguments */ 179/* process command-line arguments */
177int 180check_by_ssh_config_wrapper process_arguments(int argc, char **argv) {
178process_arguments (int argc, char **argv)
179{
180 int c;
181 char *p1, *p2;
182
183 int option = 0;
184 static struct option longopts[] = { 181 static struct option longopts[] = {
185 {"version", no_argument, 0, 'V'}, 182 {"version", no_argument, 0, 'V'},
186 {"help", no_argument, 0, 'h'}, 183 {"help", no_argument, 0, 'h'},
@@ -188,19 +185,20 @@ process_arguments (int argc, char **argv)
188 {"fork", no_argument, 0, 'f'}, 185 {"fork", no_argument, 0, 'f'},
189 {"timeout", required_argument, 0, 't'}, 186 {"timeout", required_argument, 0, 't'},
190 {"unknown-timeout", no_argument, 0, 'U'}, 187 {"unknown-timeout", no_argument, 0, 'U'},
191 {"host", required_argument, 0, 'H'}, /* backward compatibility */ 188 {"host", required_argument, 0, 'H'}, /* backward compatibility */
192 {"hostname", required_argument, 0, 'H'}, 189 {"hostname", required_argument, 0, 'H'},
193 {"port", required_argument,0,'p'}, 190 {"port", required_argument, 0, 'p'},
194 {"output", required_argument, 0, 'O'}, 191 {"output", required_argument, 0, 'O'},
195 {"name", required_argument, 0, 'n'}, 192 {"name", required_argument, 0, 'n'},
196 {"services", required_argument, 0, 's'}, 193 {"services", required_argument, 0, 's'},
197 {"identity", required_argument, 0, 'i'}, 194 {"identity", required_argument, 0, 'i'},
198 {"user", required_argument, 0, 'u'}, 195 {"user", required_argument, 0, 'u'}, /* backwards compatibility */
199 {"logname", required_argument, 0, 'l'}, 196 {"logname", required_argument, 0, 'l'},
200 {"command", required_argument, 0, 'C'}, 197 {"command", required_argument, 0, 'C'},
201 {"skip", optional_argument, 0, 'S'}, /* backwards compatibility */ 198 {"skip", optional_argument, 0, 'S'}, /* backwards compatibility */
202 {"skip-stdout", optional_argument, 0, 'S'}, 199 {"skip-stdout", optional_argument, 0, 'S'},
203 {"skip-stderr", optional_argument, 0, 'E'}, 200 {"skip-stderr", optional_argument, 0, 'E'},
201 {"unknown-on-stderr", no_argument, 0, 'e'},
204 {"warn-on-stderr", no_argument, 0, 'W'}, 202 {"warn-on-stderr", no_argument, 0, 'W'},
205 {"proto1", no_argument, 0, '1'}, 203 {"proto1", no_argument, 0, '1'},
206 {"proto2", no_argument, 0, '2'}, 204 {"proto2", no_argument, 0, '2'},
@@ -209,287 +207,330 @@ process_arguments (int argc, char **argv)
209 {"ssh-option", required_argument, 0, 'o'}, 207 {"ssh-option", required_argument, 0, 'o'},
210 {"quiet", no_argument, 0, 'q'}, 208 {"quiet", no_argument, 0, 'q'},
211 {"configfile", optional_argument, 0, 'F'}, 209 {"configfile", optional_argument, 0, 'F'},
212 {0, 0, 0, 0} 210 {0, 0, 0, 0}};
211
212 check_by_ssh_config_wrapper result = {
213 .errorcode = OK,
214 .config = check_by_ssh_config_init(),
213 }; 215 };
214 216
215 if (argc < 2) 217 if (argc < 2) {
216 return ERROR; 218 result.errorcode = ERROR;
219 return result;
220 }
221
222 for (int index = 1; index < argc; index++) {
223 if (strcmp("-to", argv[index]) == 0) {
224 strcpy(argv[index], "-t");
225 }
226 }
217 227
218 for (c = 1; c < argc; c++) 228 result.config.cmd = comm_append(result.config.cmd, SSH_COMMAND);
219 if (strcmp ("-to", argv[c]) == 0)
220 strcpy (argv[c], "-t");
221 229
222 while (1) { 230 int option = 0;
223 c = getopt_long (argc, argv, "Vvh1246fqt:UH:O:p:i:u:l:C:S::E::n:s:o:F:", longopts, 231 while (true) {
224 &option); 232 int opt_index =
233 getopt_long(argc, argv, "Vvh1246fqt:UH:O:p:i:u:l:C:S::E::n:s:o:F:", longopts, &option);
225 234
226 if (c == -1 || c == EOF) 235 if (opt_index == -1 || opt_index == EOF) {
227 break; 236 break;
237 }
228 238
229 switch (c) { 239 switch (opt_index) {
230 case 'V': /* version */ 240 case 'V': /* version */
231 print_revision (progname, NP_VERSION); 241 print_revision(progname, NP_VERSION);
232 exit (STATE_UNKNOWN); 242 exit(STATE_UNKNOWN);
233 case 'h': /* help */ 243 case 'h': /* help */
234 print_help (); 244 print_help();
235 exit (STATE_UNKNOWN); 245 exit(STATE_UNKNOWN);
236 case 'v': /* help */ 246 case 'v': /* help */
237 verbose = true; 247 verbose = true;
238 break; 248 break;
239 case 't': /* timeout period */ 249 case 't': /* timeout period */
240 if (!is_integer (optarg)) 250 if (!is_integer(optarg)) {
241 usage_va(_("Timeout interval must be a positive integer")); 251 usage_va(_("Timeout interval must be a positive integer"));
242 else 252 } else {
243 timeout_interval = atoi (optarg); 253 timeout_interval = atoi(optarg);
254 }
244 break; 255 break;
245 case 'U': 256 case 'U':
246 unknown_timeout = true; 257 result.config.unknown_timeout = true;
247 break; 258 break;
248 case 'H': /* host */ 259 case 'H': /* host */
249 hostname = optarg; 260 result.config.hostname = optarg;
250 break; 261 break;
251 case 'p': /* port number */ 262 case 'p': /* port number */
252 if (!is_integer (optarg)) 263 if (!is_integer(optarg)) {
253 usage_va(_("Port must be a positive integer")); 264 usage_va(_("Port must be a positive integer"));
254 comm_append("-p"); 265 }
255 comm_append(optarg); 266 result.config.cmd = comm_append(result.config.cmd, "-p");
267 result.config.cmd = comm_append(result.config.cmd, optarg);
256 break; 268 break;
257 case 'O': /* output file */ 269 case 'O': /* output file */
258 outputfile = optarg; 270 result.config.outputfile = optarg;
259 passive = true; 271 result.config.passive = true;
260 break; 272 break;
261 case 's': /* description of service to check */ 273 case 's': /* description of service to check */ {
274 char *p1;
275 char *p2;
276
262 p1 = optarg; 277 p1 = optarg;
263 service = realloc (service, (++services) * sizeof(char *)); 278 result.config.service = realloc(result.config.service,
264 while ((p2 = index (p1, ':'))) { 279 (++result.config.number_of_services) * sizeof(char *));
280 while ((p2 = index(p1, ':'))) {
265 *p2 = '\0'; 281 *p2 = '\0';
266 service[services - 1] = p1; 282 result.config.service[result.config.number_of_services - 1] = p1;
267 service = realloc (service, (++services) * sizeof(char *)); 283 result.config.service = realloc(
284 result.config.service, (++result.config.number_of_services) * sizeof(char *));
268 p1 = p2 + 1; 285 p1 = p2 + 1;
269 } 286 }
270 service[services - 1] = p1; 287 result.config.service[result.config.number_of_services - 1] = p1;
271 break;
272 case 'n': /* short name of host in the monitoring configuration */
273 host_shortname = optarg;
274 break; 288 break;
275 289 case 'n': /* short name of host in the monitoring configuration */
290 result.config.host_shortname = optarg;
291 } break;
276 case 'u': 292 case 'u':
277 comm_append("-l"); 293 result.config.cmd = comm_append(result.config.cmd, "-l");
278 comm_append(optarg); 294 result.config.cmd = comm_append(result.config.cmd, optarg);
279 break; 295 break;
280 case 'l': /* login name */ 296 case 'l': /* login name */
281 comm_append("-l"); 297 result.config.cmd = comm_append(result.config.cmd, "-l");
282 comm_append(optarg); 298 result.config.cmd = comm_append(result.config.cmd, optarg);
283 break; 299 break;
284 case 'i': /* identity */ 300 case 'i': /* identity */
285 comm_append("-i"); 301 result.config.cmd = comm_append(result.config.cmd, "-i");
286 comm_append(optarg); 302 result.config.cmd = comm_append(result.config.cmd, optarg);
287 break; 303 break;
288 304
289 case '1': /* Pass these switches directly to ssh */ 305 case '1': /* Pass these switches directly to ssh */
290 comm_append("-1"); 306 result.config.cmd = comm_append(result.config.cmd, "-1");
291 break; 307 break;
292 case '2': /* 1 to force version 1, 2 to force version 2 */ 308 case '2': /* 1 to force version 1, 2 to force version 2 */
293 comm_append("-2"); 309 result.config.cmd = comm_append(result.config.cmd, "-2");
294 break; 310 break;
295 case '4': /* -4 for IPv4 */ 311 case '4': /* -4 for IPv4 */
296 comm_append("-4"); 312 result.config.cmd = comm_append(result.config.cmd, "-4");
297 break; 313 break;
298 case '6': /* -6 for IPv6 */ 314 case '6': /* -6 for IPv6 */
299 comm_append("-6"); 315 result.config.cmd = comm_append(result.config.cmd, "-6");
300 break; 316 break;
301 case 'f': /* fork to background */ 317 case 'f': /* fork to background */
302 comm_append("-f"); 318 result.config.cmd = comm_append(result.config.cmd, "-f");
303 break; 319 break;
304 case 'C': /* Command for remote machine */ 320 case 'C': /* Command for remote machine */
305 commands++; 321 result.config.commands++;
306 if (commands > 1) 322 if (result.config.commands > 1) {
307 xasprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd); 323 xasprintf(&result.config.remotecmd, "%s;echo STATUS CODE: $?;",
308 xasprintf (&remotecmd, "%s%s", remotecmd, optarg); 324 result.config.remotecmd);
325 }
326 xasprintf(&result.config.remotecmd, "%s%s", result.config.remotecmd, optarg);
309 break; 327 break;
310 case 'S': /* skip n (or all) lines on stdout */ 328 case 'S': /* skip n (or all) lines on stdout */
311 if (optarg == NULL) 329 if (optarg == NULL) {
312 skip_stdout = -1; /* skip all output on stdout */ 330 result.config.skip_stdout = -1; /* skip all output on stdout */
313 else if (!is_integer (optarg)) 331 } else if (!is_integer(optarg)) {
314 usage_va(_("skip-stdout argument must be an integer")); 332 usage_va(_("skip-stdout argument must be an integer"));
315 else 333 } else {
316 skip_stdout = atoi (optarg); 334 result.config.skip_stdout = atoi(optarg);
335 }
317 break; 336 break;
318 case 'E': /* skip n (or all) lines on stderr */ 337 case 'E': /* skip n (or all) lines on stderr */
319 if (optarg == NULL) 338 if (optarg == NULL) {
320 skip_stderr = -1; /* skip all output on stderr */ 339 result.config.skip_stderr = -1; /* skip all output on stderr */
321 else if (!is_integer (optarg)) 340 } else if (!is_integer(optarg)) {
322 usage_va(_("skip-stderr argument must be an integer")); 341 usage_va(_("skip-stderr argument must be an integer"));
323 else 342 } else {
324 skip_stderr = atoi (optarg); 343 result.config.skip_stderr = atoi(optarg);
344 }
325 break; 345 break;
326 case 'W': /* exit with warning if there is an output on stderr */ 346 case 'e': /* exit with unknown if there is an output on stderr */
327 warn_on_stderr = 1; 347 result.config.unknown_on_stderr = true;
328 break; 348 break;
329 case 'o': /* Extra options for the ssh command */ 349 case 'W': /* exit with warning if there is an output on stderr */
330 comm_append("-o"); 350 result.config.warn_on_stderr = true;
331 comm_append(optarg);
332 break; 351 break;
333 case 'q': /* Tell the ssh command to be quiet */ 352 case 'o': /* Extra options for the ssh command */
334 comm_append("-q"); 353 result.config.cmd = comm_append(result.config.cmd, "-o");
354 result.config.cmd = comm_append(result.config.cmd, optarg);
335 break; 355 break;
336 case 'F': /* ssh configfile */ 356 case 'q': /* Tell the ssh command to be quiet */
337 comm_append("-F"); 357 result.config.cmd = comm_append(result.config.cmd, "-q");
338 comm_append(optarg);
339 break; 358 break;
340 default: /* help */ 359 case 'F': /* ssh configfile */
360 result.config.cmd = comm_append(result.config.cmd, "-F");
361 result.config.cmd = comm_append(result.config.cmd, optarg);
362 break;
363 default: /* help */
341 usage5(); 364 usage5();
342 } 365 }
343 } 366 }
344 367
345 c = optind; 368 int c = optind;
346 if (hostname == NULL) { 369 if (result.config.hostname == NULL) {
347 if (c <= argc) { 370 if (c <= argc) {
348 die (STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname); 371 die(STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname);
349 } 372 }
350 hostname = argv[c++]; 373 result.config.hostname = argv[c++];
351 } 374 }
352 375
353 if (strlen(remotecmd) == 0) { 376 if (strlen(result.config.remotecmd) == 0) {
354 for (; c < argc; c++) 377 for (; c < argc; c++) {
355 if (strlen(remotecmd) > 0) 378 if (strlen(result.config.remotecmd) > 0) {
356 xasprintf (&remotecmd, "%s %s", remotecmd, argv[c]); 379 xasprintf(&result.config.remotecmd, "%s %s", result.config.remotecmd, argv[c]);
357 else 380 } else {
358 xasprintf (&remotecmd, "%s", argv[c]); 381 xasprintf(&result.config.remotecmd, "%s", argv[c]);
382 }
383 }
359 } 384 }
360 385
361 if (commands > 1 || passive) 386 if (result.config.commands > 1 || result.config.passive) {
362 xasprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd); 387 xasprintf(&result.config.remotecmd, "%s;echo STATUS CODE: $?;", result.config.remotecmd);
388 }
363 389
364 if (remotecmd == NULL || strlen (remotecmd) <= 1) 390 if (result.config.remotecmd == NULL || strlen(result.config.remotecmd) <= 1) {
365 usage_va(_("No remotecmd")); 391 usage_va(_("No remotecmd"));
392 }
366 393
367 comm_append(hostname); 394 result.config.cmd = comm_append(result.config.cmd, result.config.hostname);
368 comm_append(remotecmd); 395 result.config.cmd = comm_append(result.config.cmd, result.config.remotecmd);
369 396
370 return validate_arguments (); 397 return validate_arguments(result);
371} 398}
372 399
400command_construct comm_append(command_construct cmd, const char *str) {
373 401
374void 402 if (verbose) {
375comm_append (const char *str) 403 for (int i = 0; i < cmd.commargc; i++) {
376{ 404 printf("Current command: [%i] %s\n", i, cmd.commargv[i]);
405 }
406
407 printf("Appending: %s\n", str);
408 }
377 409
378 if (++commargc > NP_MAXARGS) 410 if (++cmd.commargc > NP_MAXARGS) {
379 die(STATE_UNKNOWN, _("%s: Argument limit of %d exceeded\n"), progname, NP_MAXARGS); 411 die(STATE_UNKNOWN, _("%s: Argument limit of %d exceeded\n"), progname, NP_MAXARGS);
412 }
380 413
381 if ((commargv = (char **)realloc(commargv, (commargc+1) * sizeof(char *))) == NULL) 414 if ((cmd.commargv = (char **)realloc(cmd.commargv, (cmd.commargc + 1) * sizeof(char *))) ==
415 NULL) {
382 die(STATE_UNKNOWN, _("Can not (re)allocate 'commargv' buffer\n")); 416 die(STATE_UNKNOWN, _("Can not (re)allocate 'commargv' buffer\n"));
417 }
383 418
384 commargv[commargc-1] = strdup(str); 419 cmd.commargv[cmd.commargc - 1] = strdup(str);
385 commargv[commargc] = NULL; 420 cmd.commargv[cmd.commargc] = NULL;
386 421
422 return cmd;
387} 423}
388 424
389int 425check_by_ssh_config_wrapper validate_arguments(check_by_ssh_config_wrapper config_wrapper) {
390validate_arguments (void) 426 if (config_wrapper.config.remotecmd == NULL || config_wrapper.config.hostname == NULL) {
391{ 427 config_wrapper.errorcode = ERROR;
392 if (remotecmd == NULL || hostname == NULL) 428 return config_wrapper;
393 return ERROR; 429 }
394 430
395 if (passive && commands != services) 431 if (config_wrapper.config.passive &&
396 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide a service name for each command.\n"), progname); 432 config_wrapper.config.commands != config_wrapper.config.number_of_services) {
433 die(STATE_UNKNOWN,
434 _("%s: In passive mode, you must provide a service name for each command.\n"),
435 progname);
436 }
397 437
398 if (passive && host_shortname == NULL) 438 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); 439 die(STATE_UNKNOWN,
440 _("%s: In passive mode, you must provide the host short name from the monitoring "
441 "configs.\n"),
442 progname);
443 }
400 444
401 return OK; 445 return config_wrapper;
402} 446}
403 447
404 448void print_help(void) {
405void 449 print_revision(progname, NP_VERSION);
406print_help (void) 450
407{ 451 printf("Copyright (c) 1999 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n");
408 print_revision (progname, NP_VERSION); 452 printf(COPYRIGHT, copyright, email);
409 453
410 printf ("Copyright (c) 1999 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n"); 454 printf(_("This plugin uses SSH to execute commands on a remote host"));
411 printf (COPYRIGHT, copyright, email); 455
412 456 printf("\n\n");
413 printf (_("This plugin uses SSH to execute commands on a remote host")); 457
414 458 print_usage();
415 printf ("\n\n"); 459
416 460 printf(UT_HELP_VRSN);
417 print_usage (); 461
418 462 printf(UT_EXTRA_OPTS);
419 printf (UT_HELP_VRSN); 463
420 464 printf(UT_HOST_PORT, 'p', "none");
421 printf (UT_EXTRA_OPTS); 465
422 466 printf(UT_IPv46);
423 printf (UT_HOST_PORT, 'p', "none"); 467
424 468 printf(" %s\n", "-1, --proto1");
425 printf (UT_IPv46); 469 printf(" %s\n", _("tell ssh to use Protocol 1 [optional]"));
426 470 printf(" %s\n", "-2, --proto2");
427 printf (" %s\n", "-1, --proto1"); 471 printf(" %s\n", _("tell ssh to use Protocol 2 [optional]"));
428 printf (" %s\n", _("tell ssh to use Protocol 1 [optional]")); 472 printf(" %s\n", "-S, --skip-stdout[=n]");
429 printf (" %s\n", "-2, --proto2"); 473 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]")); 474 printf(" %s\n", "-E, --skip-stderr[=n]");
431 printf (" %s\n", "-S, --skip-stdout[=n]"); 475 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]")); 476 printf(" %s\n", "-e, --unknown-on-stderr");
433 printf (" %s\n", "-E, --skip-stderr[=n]"); 477 printf(" %s\n", _("Exit with UNKNOWN, if there is output on STDERR"));
434 printf (" %s\n", _("Ignore all or (if specified) first n lines on STDERR [optional]")); 478 printf(" %s\n", "-W, --warn-on-stderr");
435 printf (" %s\n", "-W, --warn-on-stderr]"); 479 printf(" %s\n", _("Exit with WARNING, if there is output on STDERR"));
436 printf (" %s\n", _("Exit with an warning, if there is an output on STDERR")); 480 printf(" %s\n", "-f");
437 printf (" %s\n", "-f"); 481 printf(" %s\n", _("tells ssh to fork rather than create a tty [optional]. This will always "
438 printf (" %s\n", _("tells ssh to fork rather than create a tty [optional]. This will always return OK if ssh is executed")); 482 "return OK if ssh is executed"));
439 printf (" %s\n","-C, --command='COMMAND STRING'"); 483 printf(" %s\n", "-C, --command='COMMAND STRING'");
440 printf (" %s\n", _("command to execute on the remote machine")); 484 printf(" %s\n", _("command to execute on the remote machine"));
441 printf (" %s\n","-l, --logname=USERNAME"); 485 printf(" %s\n", "-l, --logname=USERNAME");
442 printf (" %s\n", _("SSH user name on remote host [optional]")); 486 printf(" %s\n", _("SSH user name on remote host [optional]"));
443 printf (" %s\n","-i, --identity=KEYFILE"); 487 printf(" %s\n", "-i, --identity=KEYFILE");
444 printf (" %s\n", _("identity of an authorized key [optional]")); 488 printf(" %s\n", _("identity of an authorized key [optional]"));
445 printf (" %s\n","-O, --output=FILE"); 489 printf(" %s\n", "-O, --output=FILE");
446 printf (" %s\n", _("external command file for monitoring [optional]")); 490 printf(" %s\n", _("external command file for monitoring [optional]"));
447 printf (" %s\n","-s, --services=LIST"); 491 printf(" %s\n", "-s, --services=LIST");
448 printf (" %s\n", _("list of monitoring service names, separated by ':' [optional]")); 492 printf(" %s\n", _("list of monitoring service names, separated by ':' [optional]"));
449 printf (" %s\n","-n, --name=NAME"); 493 printf(" %s\n", "-n, --name=NAME");
450 printf (" %s\n", _("short name of host in the monitoring configuration [optional]")); 494 printf(" %s\n", _("short name of host in the monitoring configuration [optional]"));
451 printf (" %s\n","-o, --ssh-option=OPTION"); 495 printf(" %s\n", "-o, --ssh-option=OPTION");
452 printf (" %s\n", _("Call ssh with '-o OPTION' (may be used multiple times) [optional]")); 496 printf(" %s\n", _("Call ssh with '-o OPTION' (may be used multiple times) [optional]"));
453 printf (" %s\n","-F, --configfile"); 497 printf(" %s\n", "-F, --configfile");
454 printf (" %s\n", _("Tell ssh to use this configfile [optional]")); 498 printf(" %s\n", _("Tell ssh to use this configfile [optional]"));
455 printf (" %s\n","-q, --quiet"); 499 printf(" %s\n", "-q, --quiet");
456 printf (" %s\n", _("Tell ssh to suppress warning and diagnostic messages [optional]")); 500 printf(" %s\n", _("Tell ssh to suppress warning and diagnostic messages [optional]"));
457 printf (UT_WARN_CRIT); 501 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
458 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 502 printf(" %s\n", "-U, --unknown-timeout");
459 printf (" %s\n","-U, --unknown-timeout"); 503 printf(" %s\n", _("Make connection problems return UNKNOWN instead of CRITICAL"));
460 printf (" %s\n", _("Make connection problems return UNKNOWN instead of CRITICAL")); 504 printf(UT_VERBOSE);
461 printf (UT_VERBOSE); 505 printf("\n");
506 printf(" %s\n", _("The most common mode of use is to refer to a local identity file with"));
507 printf(" %s\n", _("the '-i' option. In this mode, the identity pair should have a null"));
508 printf(" %s\n", _("passphrase and the public key should be listed in the authorized_keys"));
509 printf(" %s\n", _("file of the remote host. Usually the key will be restricted to running"));
510 printf(" %s\n", _("only one command on the remote server. If the remote SSH server tracks"));
511 printf(" %s\n", _("invocation arguments, the one remote program may be an agent that can"));
512 printf(" %s\n", _("execute additional commands as proxy"));
462 printf("\n"); 513 printf("\n");
463 printf (" %s\n", _("The most common mode of use is to refer to a local identity file with")); 514 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")); 515 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")); 516 printf("\n");
466 printf (" %s\n", _("file of the remote host. Usually the key will be restricted to running")); 517 printf("%s\n", _("Examples:"));
467 printf (" %s\n", _("only one command on the remote server. If the remote SSH server tracks")); 518 printf(
468 printf (" %s\n", _("invocation arguments, the one remote program may be an agent that can")); 519 " %s\n",
469 printf (" %s\n", _("execute additional commands as proxy")); 520 "$ check_by_ssh -H localhost -n lh -s c1:c2:c3 -C uptime -C uptime -C uptime -O /tmp/foo");
470 printf("\n"); 521 printf(" %s\n", "$ cat /tmp/foo");
471 printf (" %s\n", _("To use passive mode, provide multiple '-C' options, and provide")); 522 printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c1;0; up 2 days");
472 printf (" %s\n", _("all of -O, -s, and -n options (servicelist order must match '-C'options)")); 523 printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c2;0; up 2 days");
473 printf ("\n"); 524 printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c3;0; up 2 days");
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 525
481 printf(UT_SUPPORT); 526 printf(UT_SUPPORT);
482} 527}
483 528
484 529void print_usage(void) {
485 530 printf("%s\n", _("Usage:"));
486void 531 printf(" %s -H <host> -C <command> [-fqvU] [-1|-2] [-4|-6]\n"
487print_usage (void) 532 " [-S [lines]] [-E [lines]] [-e|-W] [-t timeout] [-i identity]\n"
488{ 533 " [-l user] [-n name] [-s servicelist] [-O outputfile]\n"
489 printf ("%s\n", _("Usage:")); 534 " [-p port] [-o ssh-option] [-F configfile]\n",
490 printf (" %s -H <host> -C <command> [-fqvU] [-1|-2] [-4|-6]\n" 535 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} 536}
diff --git a/plugins/check_by_ssh.d/config.h b/plugins/check_by_ssh.d/config.h
new file mode 100644
index 00000000..0e4b56d4
--- /dev/null
+++ b/plugins/check_by_ssh.d/config.h
@@ -0,0 +1,58 @@
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 unknown_on_stderr;
25 bool warn_on_stderr;
26 int skip_stdout;
27 int skip_stderr;
28 bool passive;
29 char *outputfile;
30} check_by_ssh_config;
31
32check_by_ssh_config check_by_ssh_config_init() {
33 check_by_ssh_config tmp = {
34 .hostname = NULL,
35 .host_shortname = NULL,
36
37 .service = NULL,
38 .number_of_services = 0,
39
40 .commands = 0,
41 .remotecmd = "",
42
43 .cmd =
44 {
45 .commargc = 0,
46 .commargv = NULL,
47 },
48
49 .unknown_timeout = false,
50 .unknown_on_stderr = false,
51 .warn_on_stderr = false,
52 .skip_stderr = 0,
53 .skip_stdout = 0,
54 .passive = false,
55 .outputfile = NULL,
56 };
57 return tmp;
58}
diff --git a/plugins/check_cluster.c b/plugins/check_cluster.c
index e1ede9f7..1cbdcd60 100644
--- a/plugins/check_cluster.c
+++ b/plugins/check_cluster.c
@@ -1,92 +1,87 @@
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 "output.h"
30#include "states.h"
29#include "common.h" 31#include "common.h"
30#include "utils.h" 32#include "utils.h"
31#include "utils_base.h" 33#include "utils_base.h"
34#include "check_cluster.d/config.h"
32 35
33#define CHECK_SERVICES 1 36static void print_help(void);
34#define CHECK_HOSTS 2 37void print_usage(void);
35 38
36void print_help (void); 39static int verbose = 0;
37void print_usage (void);
38 40
39int total_services_ok=0; 41typedef struct {
40int total_services_warning=0; 42 int errorcode;
41int total_services_unknown=0; 43 check_cluster_config config;
42int total_services_critical=0; 44} check_cluster_config_wrapper;
45static check_cluster_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
43 46
44int total_hosts_up=0; 47int main(int argc, char **argv) {
45int total_hosts_down=0; 48 setlocale(LC_ALL, "");
46int total_hosts_unreachable=0; 49 bindtextdomain(PACKAGE, LOCALEDIR);
47 50 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 51
72 /* Parse extra opts if any */ 52 /* Parse extra opts if any */
73 argv=np_extra_opts(&argc, argv, progname); 53 argv = np_extra_opts(&argc, argv, progname);
74 54
75 if(process_arguments(argc,argv)==ERROR) 55 check_cluster_config_wrapper tmp_config = process_arguments(argc, argv);
56 if (tmp_config.errorcode == ERROR) {
76 usage(_("Could not parse arguments")); 57 usage(_("Could not parse arguments"));
58 }
59
60 const check_cluster_config config = tmp_config.config;
61
62 if (config.output_format_is_set) {
63 mp_set_format(config.output_format);
64 }
77 65
78 /* Initialize the thresholds */ 66 /* Initialize the thresholds */
79 set_thresholds(&thresholds, warn_threshold, crit_threshold); 67 if (verbose) {
80 if(verbose) 68 print_thresholds("check_cluster", config.thresholds);
81 print_thresholds("check_cluster", thresholds); 69 }
82 70
71 int data_val;
72 int total_services_ok = 0;
73 int total_services_warning = 0;
74 int total_services_unknown = 0;
75 int total_services_critical = 0;
76 int total_hosts_up = 0;
77 int total_hosts_down = 0;
78 int total_hosts_unreachable = 0;
83 /* check the data values */ 79 /* check the data values */
84 for(ptr=strtok(data_vals,",");ptr!=NULL;ptr=strtok(NULL,",")){ 80 for (char *ptr = strtok(config.data_vals, ","); ptr != NULL; ptr = strtok(NULL, ",")) {
85 81 data_val = atoi(ptr);
86 data_val=atoi(ptr);
87 82
88 if(check_type==CHECK_SERVICES){ 83 if (config.check_type == CHECK_SERVICES) {
89 switch(data_val){ 84 switch (data_val) {
90 case 0: 85 case 0:
91 total_services_ok++; 86 total_services_ok++;
92 break; 87 break;
@@ -101,10 +96,9 @@ int main(int argc, char **argv){
101 break; 96 break;
102 default: 97 default:
103 break; 98 break;
104 } 99 }
105 } 100 } else {
106 else{ 101 switch (data_val) {
107 switch(data_val){
108 case 0: 102 case 0:
109 total_hosts_up++; 103 total_hosts_up++;
110 break; 104 break;
@@ -116,125 +110,150 @@ int main(int argc, char **argv){
116 break; 110 break;
117 default: 111 default:
118 break; 112 break;
119 } 113 }
120 } 114 }
121 } 115 }
122 116
117 mp_check overall = mp_check_init();
118 mp_subcheck sc_real_test = mp_subcheck_init();
119 sc_real_test = mp_set_subcheck_default_state(sc_real_test, STATE_OK);
123 120
124 /* return the status of the cluster */ 121 /* return the status of the cluster */
125 if(check_type==CHECK_SERVICES){ 122 if (config.check_type == CHECK_SERVICES) {
126 return_code=get_status(total_services_warning+total_services_unknown+total_services_critical, thresholds); 123 sc_real_test = mp_set_subcheck_state(
127 printf("CLUSTER %s: %s: %d ok, %d warning, %d unknown, %d critical\n", 124 sc_real_test,
128 state_text(return_code), (label==NULL)?"Service cluster":label, 125 get_status(total_services_warning + total_services_unknown + total_services_critical,
129 total_services_ok,total_services_warning, 126 config.thresholds));
130 total_services_unknown,total_services_critical); 127 xasprintf(&sc_real_test.output, "%s: %d ok, %d warning, %d unknown, %d critical",
131 } 128 (config.label == NULL) ? "Service cluster" : config.label, total_services_ok,
132 else{ 129 total_services_warning, total_services_unknown, total_services_critical);
133 return_code=get_status(total_hosts_down+total_hosts_unreachable, thresholds); 130 } else {
134 printf("CLUSTER %s: %s: %d up, %d down, %d unreachable\n", 131 sc_real_test = mp_set_subcheck_state(
135 state_text(return_code), (label==NULL)?"Host cluster":label, 132 sc_real_test,
136 total_hosts_up,total_hosts_down,total_hosts_unreachable); 133 get_status(total_hosts_down + total_hosts_unreachable, config.thresholds));
134 xasprintf(&sc_real_test.output, "%s: %d up, %d down, %d unreachable\n",
135 (config.label == NULL) ? "Host cluster" : config.label, total_hosts_up,
136 total_hosts_down, total_hosts_unreachable);
137 } 137 }
138 138
139 return return_code; 139 mp_add_subcheck_to_check(&overall, sc_real_test);
140}
141 140
141 mp_exit(overall);
142}
142 143
144check_cluster_config_wrapper process_arguments(int argc, char **argv) {
145 enum {
146 output_format_index = CHAR_MAX + 1,
147 };
143 148
144int process_arguments(int argc, char **argv){ 149 static struct option longopts[] = {{"data", required_argument, 0, 'd'},
145 int c; 150 {"warning", required_argument, 0, 'w'},
146 char *ptr; 151 {"critical", required_argument, 0, 'c'},
147 int option=0; 152 {"label", required_argument, 0, 'l'},
148 static struct option longopts[]={ 153 {"host", no_argument, 0, 'h'},
149 {"data", required_argument,0,'d'}, 154 {"service", no_argument, 0, 's'},
150 {"warning", required_argument,0,'w'}, 155 {"verbose", no_argument, 0, 'v'},
151 {"critical", required_argument,0,'c'}, 156 {"version", no_argument, 0, 'V'},
152 {"label", required_argument,0,'l'}, 157 {"help", no_argument, 0, 'H'},
153 {"host", no_argument, 0,'h'}, 158 {"output-format", required_argument, 0, output_format_index},
154 {"service", no_argument, 0,'s'}, 159 {0, 0, 0, 0}};
155 {"verbose", no_argument, 0,'v'}, 160
156 {"version", no_argument, 0,'V'}, 161 check_cluster_config_wrapper result = {
157 {"help", no_argument, 0,'H'}, 162 .errorcode = OK,
158 {0,0,0,0} 163 .config = check_cluster_config_init(),
159 }; 164 };
160 165
161 /* no options were supplied */ 166 /* no options were supplied */
162 if(argc<2) 167 if (argc < 2) {
163 return ERROR; 168 result.errorcode = ERROR;
164 169 return result;
165 while(1){ 170 }
166 171
167 c=getopt_long(argc,argv,"hHsvVw:c:d:l:",longopts,&option); 172 int option = 0;
173 char *warn_threshold = NULL;
174 char *crit_threshold = NULL;
175 while (true) {
176 int option_index = getopt_long(argc, argv, "hHsvVw:c:d:l:", longopts, &option);
168 177
169 if(c==-1 || c==EOF || c==1) 178 if (option_index == -1 || option_index == EOF || option_index == 1) {
170 break; 179 break;
180 }
171 181
172 switch(c){ 182 switch (option_index) {
173
174 case 'h': /* host cluster */ 183 case 'h': /* host cluster */
175 check_type=CHECK_HOSTS; 184 result.config.check_type = CHECK_HOSTS;
176 break; 185 break;
177
178 case 's': /* service cluster */ 186 case 's': /* service cluster */
179 check_type=CHECK_SERVICES; 187 result.config.check_type = CHECK_SERVICES;
180 break; 188 break;
181
182 case 'w': /* warning threshold */ 189 case 'w': /* warning threshold */
183 warn_threshold = strdup(optarg); 190 warn_threshold = strdup(optarg);
184 break; 191 break;
185
186 case 'c': /* warning threshold */ 192 case 'c': /* warning threshold */
187 crit_threshold = strdup(optarg); 193 crit_threshold = strdup(optarg);
188 break; 194 break;
189
190 case 'd': /* data values */ 195 case 'd': /* data values */
191 data_vals=(char *)strdup(optarg); 196 result.config.data_vals = strdup(optarg);
192 /* validate data */ 197 /* validate data */
193 for (ptr=data_vals;ptr!=NULL;ptr+=2){ 198 for (char *ptr = result.config.data_vals; ptr != NULL; ptr += 2) {
194 if (ptr[0]<'0' || ptr[0]>'3') 199 if (ptr[0] < '0' || ptr[0] > '3') {
195 return ERROR; 200 result.errorcode = ERROR;
196 if (ptr[1]=='\0') 201 return result;
202 }
203 if (ptr[1] == '\0') {
197 break; 204 break;
198 if (ptr[1]!=',') 205 }
199 return ERROR; 206 if (ptr[1] != ',') {
207 result.errorcode = ERROR;
208 return result;
209 }
200 } 210 }
201 break; 211 break;
202
203 case 'l': /* text label */ 212 case 'l': /* text label */
204 label=(char *)strdup(optarg); 213 result.config.label = strdup(optarg);
205 break; 214 break;
206
207 case 'v': /* verbose */ 215 case 'v': /* verbose */
208 verbose++; 216 verbose++;
209 break; 217 break;
210
211 case 'V': /* version */ 218 case 'V': /* version */
212 print_revision (progname, NP_VERSION); 219 print_revision(progname, NP_VERSION);
213 exit (STATE_UNKNOWN); 220 exit(STATE_UNKNOWN);
214 break; 221 break;
215
216 case 'H': /* help */ 222 case 'H': /* help */
217 print_help(); 223 print_help();
218 exit(STATE_UNKNOWN); 224 exit(STATE_UNKNOWN);
219 break; 225 break;
226 case output_format_index: {
227 parsed_output_format parser = mp_parse_output_format(optarg);
228 if (!parser.parsing_success) {
229 // TODO List all available formats here, maybe add anothoer usage function
230 printf("Invalid output format: %s\n", optarg);
231 exit(STATE_UNKNOWN);
232 }
220 233
234 result.config.output_format_is_set = true;
235 result.config.output_format = parser.output_format;
236 break;
237 }
221 default: 238 default:
222 return ERROR; 239 result.errorcode = ERROR;
240 return result;
223 break; 241 break;
224 } 242 }
225 } 243 }
226 244
227 if(data_vals==NULL) 245 if (result.config.data_vals == NULL) {
228 return ERROR; 246 result.errorcode = ERROR;
247 return result;
248 }
229 249
230 return OK; 250 set_thresholds(&result.config.thresholds, warn_threshold, crit_threshold);
251 return result;
231} 252}
232 253
233void 254void print_help(void) {
234print_help(void)
235{
236 print_revision(progname, NP_VERSION); 255 print_revision(progname, NP_VERSION);
237 printf ("Copyright (c) 2000-2004 Ethan Galstad (nagios@nagios.org)\n"); 256 printf("Copyright (c) 2000-2004 Ethan Galstad (nagios@nagios.org)\n");
238 printf(COPYRIGHT, copyright, email); 257 printf(COPYRIGHT, copyright, email);
239 258
240 printf(_("Host/Service Cluster Plugin for Monitoring")); 259 printf(_("Host/Service Cluster Plugin for Monitoring"));
@@ -245,45 +264,43 @@ print_help(void)
245 printf("\n"); 264 printf("\n");
246 printf("%s\n", _("Options:")); 265 printf("%s\n", _("Options:"));
247 printf(UT_EXTRA_OPTS); 266 printf(UT_EXTRA_OPTS);
248 printf (" %s\n", "-s, --service"); 267 printf(" %s\n", "-s, --service");
249 printf (" %s\n", _("Check service cluster status")); 268 printf(" %s\n", _("Check service cluster status"));
250 printf (" %s\n", "-h, --host"); 269 printf(" %s\n", "-h, --host");
251 printf (" %s\n", _("Check host cluster status")); 270 printf(" %s\n", _("Check host cluster status"));
252 printf (" %s\n", "-l, --label=STRING"); 271 printf(" %s\n", "-l, --label=STRING");
253 printf (" %s\n", _("Optional prepended text output (i.e. \"Host cluster\")")); 272 printf(" %s\n", _("Optional prepended text output (i.e. \"Host cluster\")"));
254 printf (" %s\n", "-w, --warning=THRESHOLD"); 273 printf(" %s\n", "-w, --warning=THRESHOLD");
255 printf (" %s\n", _("Specifies the range of hosts or services in cluster that must be in a")); 274 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")); 275 printf(" %s\n", _("non-OK state in order to return a WARNING status level"));
257 printf (" %s\n", "-c, --critical=THRESHOLD"); 276 printf(" %s\n", "-c, --critical=THRESHOLD");
258 printf (" %s\n", _("Specifies the range of hosts or services in cluster that must be in a")); 277 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")); 278 printf(" %s\n", _("non-OK state in order to return a CRITICAL status level"));
260 printf (" %s\n", "-d, --data=LIST"); 279 printf(" %s\n", "-d, --data=LIST");
261 printf (" %s\n", _("The status codes of the hosts or services in the cluster, separated by")); 280 printf(" %s\n", _("The status codes of the hosts or services in the cluster, separated by"));
262 printf (" %s\n", _("commas")); 281 printf(" %s\n", _("commas"));
263 282
264 printf(UT_VERBOSE); 283 printf(UT_VERBOSE);
265 284
285 printf(UT_OUTPUT_FORMAT);
286
266 printf("\n"); 287 printf("\n");
267 printf("%s\n", _("Notes:")); 288 printf("%s\n", _("Notes:"));
268 printf(UT_THRESHOLDS_NOTES); 289 printf(UT_THRESHOLDS_NOTES);
269 290
270 printf ("\n"); 291 printf("\n");
271 printf ("%s\n", _("Examples:")); 292 printf("%s\n", _("Examples:"));
272 printf (" %s\n", "check_cluster -s -d 2,0,2,0 -c @3:"); 293 printf(" %s\n", "check_cluster -s -d 2,0,2,0 -c @3:");
273 printf (" %s\n", _("Will alert critical if there are 3 or more service data points in a non-OK") ); 294 printf(" %s\n",
274 printf (" %s\n", _("state.") ); 295 _("Will alert critical if there are 3 or more service data points in a non-OK"));
296 printf(" %s\n", _("state."));
275 297
276 printf(UT_SUPPORT); 298 printf(UT_SUPPORT);
277} 299}
278 300
279 301void print_usage(void) {
280void
281print_usage(void)
282{
283 302
284 printf("%s\n", _("Usage:")); 303 printf("%s\n", _("Usage:"));
285 printf(" %s (-s | -h) -d val1[,val2,...,valn] [-l label]\n", progname); 304 printf(" %s (-s | -h) -d val1[,val2,...,valn] [-l label]\n", progname);
286 printf("[-w threshold] [-c threshold] [-v] [--help]\n"); 305 printf("[-w threshold] [-c threshold] [-v] [--help]\n");
287
288} 306}
289
diff --git a/plugins/check_cluster.d/config.h b/plugins/check_cluster.d/config.h
new file mode 100644
index 00000000..054657b0
--- /dev/null
+++ b/plugins/check_cluster.d/config.h
@@ -0,0 +1,33 @@
1#pragma once
2
3#include "../../config.h"
4#include "../../lib/thresholds.h"
5#include "output.h"
6#include <stddef.h>
7
8enum {
9 CHECK_SERVICES = 1,
10 CHECK_HOSTS = 2
11};
12
13typedef struct {
14 char *data_vals;
15 thresholds *thresholds;
16 int check_type;
17 char *label;
18
19 mp_output_format output_format;
20 bool output_format_is_set;
21} check_cluster_config;
22
23check_cluster_config check_cluster_config_init() {
24 check_cluster_config tmp = {
25 .data_vals = NULL,
26 .thresholds = NULL,
27 .check_type = CHECK_SERVICES,
28 .label = NULL,
29
30 .output_format_is_set = false,
31 };
32 return tmp;
33}
diff --git a/plugins/check_curl.c b/plugins/check_curl.c
index e25d7a79..fc704171 100644
--- a/plugins/check_curl.c
+++ b/plugins/check_curl.c
@@ -1,2736 +1,1889 @@
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";
36 35
37const char *copyright = "2006-2019"; 36const char *progname = "check_curl";
37const char *copyright = "2006-2024";
38const char *email = "devel@monitoring-plugins.org"; 38const char *email = "devel@monitoring-plugins.org";
39 39
40#include "check_curl.d/config.h"
41#include "states.h"
42#include "thresholds.h"
40#include <stdbool.h> 43#include <stdbool.h>
41#include <ctype.h> 44#include <ctype.h>
45#include "output.h"
46#include "perfdata.h"
42 47
48#include <assert.h>
43#include "common.h" 49#include "common.h"
44#include "utils.h" 50#include "utils.h"
51#include "./check_curl.d/check_curl_helpers.h"
45 52
46#ifndef LIBCURL_PROTOCOL_HTTP 53#ifndef LIBCURL_PROTOCOL_HTTP
47#error libcurl compiled without HTTP support, compiling check_curl plugin does not makes a lot of sense 54# error libcurl compiled without HTTP support, compiling check_curl plugin does not makes a lot of sense
48#endif 55#endif
49 56
50#include "curl/curl.h" 57#include "curl/curl.h"
51#include "curl/easy.h" 58#include "curl/easy.h"
52 59
53#include "picohttpparser.h"
54
55#include "uriparser/Uri.h" 60#include "uriparser/Uri.h"
56 61
57#include <arpa/inet.h> 62#include <arpa/inet.h>
58#include <netinet/in.h> 63#include <netinet/in.h>
59 64
60#if defined(HAVE_SSL) && defined(USE_OPENSSL) 65#if defined(HAVE_SSL) && defined(USE_OPENSSL)
61#include <openssl/opensslv.h> 66# include <openssl/opensslv.h>
62#endif 67#endif
63 68
64#include <netdb.h> 69#include <netdb.h>
65 70
66#define MAKE_LIBCURL_VERSION(major, minor, patch) ((major)*0x10000 + (minor)*0x100 + (patch))
67
68#define DEFAULT_BUFFER_SIZE 2048
69#define DEFAULT_SERVER_URL "/"
70#define HTTP_EXPECT "HTTP/"
71#define INET_ADDR_MAX_SIZE INET6_ADDRSTRLEN
72enum { 71enum {
73 MAX_IPV4_HOSTLENGTH = 255, 72 MAX_IPV4_HOSTLENGTH = 255,
74 HTTP_PORT = 80,
75 HTTPS_PORT = 443,
76 MAX_PORT = 65535,
77 DEFAULT_MAX_REDIRS = 15
78}; 73};
79 74
80enum { 75enum {
81 STICKY_NONE = 0, 76 REGS = 2,
82 STICKY_HOST = 1,
83 STICKY_PORT = 2
84}; 77};
85 78
86enum {
87 FOLLOW_HTTP_CURL = 0,
88 FOLLOW_LIBCURL = 1
89};
90
91/* for buffers for header and body */
92typedef struct {
93 char *buf;
94 size_t buflen;
95 size_t bufsize;
96} curlhelp_write_curlbuf;
97
98/* for buffering the data sent in PUT */
99typedef struct {
100 char *buf;
101 size_t buflen;
102 off_t pos;
103} curlhelp_read_curlbuf;
104
105/* for parsing the HTTP status line */
106typedef struct {
107 int http_major; /* major version of the protocol, always 1 (HTTP/0.9
108 * never reached the big internet most likely) */
109 int http_minor; /* minor version of the protocol, usually 0 or 1 */
110 int http_code; /* HTTP return code as in RFC 2145 */
111 int http_subcode; /* Microsoft IIS extension, HTTP subcodes, see
112 * http://support.microsoft.com/kb/318380/en-us */
113 const char *msg; /* the human readable message */
114 char *first_line; /* a copy of the first line */
115} curlhelp_statusline;
116
117/* to know the underlying SSL library used by libcurl */
118typedef enum curlhelp_ssl_library {
119 CURLHELP_SSL_LIBRARY_UNKNOWN,
120 CURLHELP_SSL_LIBRARY_OPENSSL,
121 CURLHELP_SSL_LIBRARY_LIBRESSL,
122 CURLHELP_SSL_LIBRARY_GNUTLS,
123 CURLHELP_SSL_LIBRARY_NSS
124} curlhelp_ssl_library;
125
126enum {
127 REGS = 2,
128 MAX_RE_SIZE = 1024
129};
130#include "regex.h" 79#include "regex.h"
131regex_t preg; 80
132regmatch_t pmatch[REGS]; 81// Globals
133char regexp[MAX_RE_SIZE];
134int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
135int errcode;
136bool invert_regex = false;
137int state_regex = STATE_CRITICAL;
138
139char *server_address = NULL;
140char *host_name = NULL;
141char *server_url = 0;
142char server_ip[DEFAULT_BUFFER_SIZE];
143struct curl_slist *server_ips = NULL;
144bool specify_port = false;
145unsigned short server_port = HTTP_PORT;
146unsigned short virtual_port = 0;
147int host_name_length;
148char output_header_search[30] = "";
149char output_string_search[30] = "";
150char *warning_thresholds = NULL;
151char *critical_thresholds = NULL;
152int days_till_exp_warn, days_till_exp_crit;
153thresholds *thlds;
154char user_agent[DEFAULT_BUFFER_SIZE];
155int verbose = 0; 82int verbose = 0;
156bool show_extended_perfdata = false; 83
157bool show_body = false; 84extern char errbuf[MAX_INPUT_BUFFER];
158int min_page_len = 0; 85extern bool is_openssl_callback;
159int max_page_len = 0; 86extern bool add_sslctx_verify_fun;
160int redir_depth = 0;
161int max_depth = DEFAULT_MAX_REDIRS;
162char *http_method = NULL;
163char *http_post_data = NULL;
164char *http_content_type = NULL;
165CURL *curl;
166bool curl_global_initialized = false;
167bool curl_easy_initialized = false;
168struct curl_slist *header_list = NULL;
169bool body_buf_initialized = false;
170curlhelp_write_curlbuf body_buf;
171bool header_buf_initialized = false;
172curlhelp_write_curlbuf header_buf;
173bool status_line_initialized = false;
174curlhelp_statusline status_line;
175bool put_buf_initialized = false;
176curlhelp_read_curlbuf put_buf;
177char http_header[DEFAULT_BUFFER_SIZE];
178long code;
179long socket_timeout = DEFAULT_SOCKET_TIMEOUT;
180double total_time;
181double time_connect;
182double time_appconnect;
183double time_headers;
184double time_firstbyte;
185char errbuf[MAX_INPUT_BUFFER];
186CURLcode res;
187char url[DEFAULT_BUFFER_SIZE];
188char msg[DEFAULT_BUFFER_SIZE];
189char perfstring[DEFAULT_BUFFER_SIZE];
190char header_expect[MAX_INPUT_BUFFER] = "";
191char string_expect[MAX_INPUT_BUFFER] = "";
192char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
193int server_expect_yn = 0;
194char user_auth[MAX_INPUT_BUFFER] = "";
195char proxy_auth[MAX_INPUT_BUFFER] = "";
196char **http_opt_headers;
197int http_opt_headers_count = 0;
198bool display_html = false;
199int onredirect = STATE_OK;
200int followmethod = FOLLOW_HTTP_CURL;
201int followsticky = STICKY_NONE;
202bool use_ssl = false;
203bool use_sni = true;
204bool check_cert = false;
205bool continue_after_check_cert = false;
206typedef union {
207 struct curl_slist* to_info;
208 struct curl_certinfo* to_certinfo;
209} cert_ptr_union;
210cert_ptr_union cert_ptr;
211int ssl_version = CURL_SSLVERSION_DEFAULT;
212char *client_cert = NULL;
213char *client_privkey = NULL;
214char *ca_cert = NULL;
215bool verify_peer_and_host = false;
216bool is_openssl_callback = false;
217#if defined(HAVE_SSL) && defined(USE_OPENSSL)
218X509 *cert = NULL;
219#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
220bool no_body = false;
221int maximum_age = -1;
222int address_family = AF_UNSPEC;
223curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
224int curl_http_version = CURL_HTTP_VERSION_NONE;
225bool automatic_decompression = false;
226char *cookie_jar_file = NULL;
227bool haproxy_protocol = false;
228
229bool process_arguments (int, char**);
230void handle_curl_option_return_code (CURLcode res, const char* option);
231int check_http (void);
232void redir (curlhelp_write_curlbuf*);
233char *perfd_time (double microsec);
234char *perfd_time_connect (double microsec);
235char *perfd_time_ssl (double microsec);
236char *perfd_time_firstbyte (double microsec);
237char *perfd_time_headers (double microsec);
238char *perfd_time_transfer (double microsec);
239char *perfd_size (int page_len);
240void print_help (void);
241void print_usage (void);
242void print_curl_version (void);
243int curlhelp_initwritebuffer (curlhelp_write_curlbuf*);
244size_t curlhelp_buffer_write_callback(void*, size_t , size_t , void*);
245void curlhelp_freewritebuffer (curlhelp_write_curlbuf*);
246int curlhelp_initreadbuffer (curlhelp_read_curlbuf *, const char *, size_t);
247size_t curlhelp_buffer_read_callback(void *, size_t , size_t , void *);
248void curlhelp_freereadbuffer (curlhelp_read_curlbuf *);
249curlhelp_ssl_library curlhelp_get_ssl_library ();
250const char* curlhelp_get_ssl_library_string (curlhelp_ssl_library);
251int net_noopenssl_check_certificate (cert_ptr_union*, int, int);
252
253int curlhelp_parse_statusline (const char*, curlhelp_statusline *);
254void curlhelp_free_statusline (curlhelp_statusline *);
255char *get_header_value (const struct phr_header* headers, const size_t nof_headers, const char* header);
256int check_document_dates (const curlhelp_write_curlbuf *, char (*msg)[DEFAULT_BUFFER_SIZE]);
257int get_content_length (const curlhelp_write_curlbuf* header_buf, const curlhelp_write_curlbuf* body_buf);
258 87
259#if defined(HAVE_SSL) && defined(USE_OPENSSL) 88#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); 89static X509 *cert = NULL;
261#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */ 90#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
262 91
263void remove_newlines (char *); 92typedef struct {
264void test_file (char *); 93 int errorcode;
94 check_curl_config config;
95} check_curl_config_wrapper;
96static check_curl_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
265 97
266int 98static mp_subcheck check_http(check_curl_config /*config*/, check_curl_working_state workingState,
267main (int argc, char **argv) 99 int redir_depth);
268{
269 int result = STATE_UNKNOWN;
270 100
271 setlocale (LC_ALL, ""); 101typedef struct {
272 bindtextdomain (PACKAGE, LOCALEDIR); 102 int redir_depth;
273 textdomain (PACKAGE); 103 check_curl_working_state working_state;
104 int error_code;
105 check_curl_global_state curl_state;
106} redir_wrapper;
107static redir_wrapper redir(curlhelp_write_curlbuf * /*header_buf*/, check_curl_config /*config*/,
108 int redir_depth, check_curl_working_state working_state);
274 109
275 /* Parse extra opts if any */ 110static void print_help(void);
276 argv = np_extra_opts (&argc, argv, progname); 111void print_usage(void);
277 112
278 /* set defaults */ 113static void print_curl_version(void);
279 snprintf( user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s, %s)",
280 progname, NP_VERSION, VERSION, curl_version());
281 114
282 /* parse arguments */ 115// typedef struct {
283 if (process_arguments (argc, argv) == false) 116// int errorcode;
284 usage4 (_("Could not parse arguments")); 117// } check_curl_evaluation_wrapper;
118// check_curl_evaluation_wrapper check_curl_evaluate(check_curl_config config,
119// mp_check overall[static 1]) {}
285 120
286 if (display_html) 121#if defined(HAVE_SSL) && defined(USE_OPENSSL)
287 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", 122mp_state_enum np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn,
288 use_ssl ? "https" : "http", 123 int days_till_exp_crit);
289 host_name ? host_name : server_address, 124#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
290 virtual_port ? virtual_port : server_port,
291 server_url);
292 125
293 result = check_http (); 126int main(int argc, char **argv) {
294 return result; 127 setlocale(LC_ALL, "");
295} 128 bindtextdomain(PACKAGE, LOCALEDIR);
129 textdomain(PACKAGE);
296 130
297#ifdef HAVE_SSL 131 /* Parse extra opts if any */
298#ifdef USE_OPENSSL 132 argv = np_extra_opts(&argc, argv, progname);
299
300int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
301{
302 (void) preverify_ok;
303 /* TODO: we get all certificates of the chain, so which ones
304 * should we test?
305 * TODO: is the last certificate always the server certificate?
306 */
307 cert = X509_STORE_CTX_get_current_cert(x509_ctx);
308#if OPENSSL_VERSION_NUMBER >= 0x10100000L
309 X509_up_ref(cert);
310#endif
311 if (verbose>=2) {
312 puts("* SSL verify callback with certificate:");
313 X509_NAME *subject, *issuer;
314 printf("* issuer:\n");
315 issuer = X509_get_issuer_name( cert );
316 X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE);
317 printf("* curl verify_callback:\n* subject:\n");
318 subject = X509_get_subject_name( cert );
319 X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE);
320 puts("");
321 }
322 return 1;
323}
324 133
325CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) 134 /* parse arguments */
326{ 135 check_curl_config_wrapper tmp_config = process_arguments(argc, argv);
327 (void) curl; // ignore unused parameter 136 if (tmp_config.errorcode == ERROR) {
328 (void) parm; // ignore unused parameter 137 usage4(_("Could not parse arguments"));
329 SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, verify_callback); 138 }
330 139
331 return CURLE_OK; 140 const check_curl_config config = tmp_config.config;
332}
333 141
334#endif /* USE_OPENSSL */ 142 if (config.output_format_is_set) {
335#endif /* HAVE_SSL */ 143 mp_set_format(config.output_format);
336 144 }
337/* returns a string "HTTP/1.x" or "HTTP/2" */
338static char *string_statuscode (int major, int minor)
339{
340 static char buf[10];
341
342 switch (major) {
343 case 1:
344 snprintf (buf, sizeof (buf), "HTTP/%d.%d", major, minor);
345 break;
346 case 2:
347 case 3:
348 snprintf (buf, sizeof (buf), "HTTP/%d", major);
349 break;
350 default:
351 /* assuming here HTTP/N with N>=4 */
352 snprintf (buf, sizeof (buf), "HTTP/%d", major);
353 break;
354 }
355
356 return buf;
357}
358 145
359/* Checks if the server 'reply' is one of the expected 'statuscodes' */ 146 check_curl_working_state working_state = config.initial_config;
360static int
361expected_statuscode (const char *reply, const char *statuscodes)
362{
363 char *expected, *code;
364 int result = 0;
365 147
366 if ((expected = strdup (statuscodes)) == NULL) 148 mp_check overall = mp_check_init();
367 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n")); 149 mp_subcheck sc_test = check_http(config, working_state, 0);
368 150
369 for (code = strtok (expected, ","); code != NULL; code = strtok (NULL, ",")) 151 mp_add_subcheck_to_check(&overall, sc_test);
370 if (strstr (reply, code) != NULL) {
371 result = 1;
372 break;
373 }
374 152
375 free (expected); 153 mp_exit(overall);
376 return result;
377} 154}
378 155
379void 156#ifdef HAVE_SSL
380handle_curl_option_return_code (CURLcode res, const char* option) 157# ifdef USE_OPENSSL
381{ 158int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) {
382 if (res != CURLE_OK) { 159 (void)preverify_ok;
383 snprintf (msg, 160 /* TODO: we get all certificates of the chain, so which ones
384 DEFAULT_BUFFER_SIZE, 161 * should we test?
385 _("Error while setting cURL option '%s': cURL returned %d - %s"), 162 * TODO: is the last certificate always the server certificate?
386 option, 163 */
387 res, 164 cert = X509_STORE_CTX_get_current_cert(x509_ctx);
388 curl_easy_strerror(res)); 165# if OPENSSL_VERSION_NUMBER >= 0x10100000L
389 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 166 X509_up_ref(cert);
390 } 167# endif
168 if (verbose >= 2) {
169 puts("* SSL verify callback with certificate:");
170 printf("* issuer:\n");
171 X509_NAME *issuer = X509_get_issuer_name(cert);
172 X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE);
173 printf("* curl verify_callback:\n* subject:\n");
174 X509_NAME *subject = X509_get_subject_name(cert);
175 X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE);
176 puts("");
177 }
178 return 1;
391} 179}
180# endif /* USE_OPENSSL */
181#endif /* HAVE_SSL */
392 182
393int 183#ifdef HAVE_SSL
394lookup_host (const char *host, char *buf, size_t buflen) 184# ifdef USE_OPENSSL
395{ 185CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) {
396 struct addrinfo hints, *res, *result; 186 (void)curl; // ignore unused parameter
397 char addrstr[100]; 187 (void)parm; // ignore unused parameter
398 size_t addrstr_len; 188 if (add_sslctx_verify_fun) {
399 int errcode; 189 SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, verify_callback);
400 void *ptr = { 0 }; 190 }
401 size_t buflen_remaining = buflen - 1;
402
403 memset (&hints, 0, sizeof (hints));
404 hints.ai_family = address_family;
405 hints.ai_socktype = SOCK_STREAM;
406 hints.ai_flags |= AI_CANONNAME;
407
408 errcode = getaddrinfo (host, NULL, &hints, &result);
409 if (errcode != 0)
410 return errcode;
411
412 strcpy(buf, "");
413 res = result;
414
415 while (res) {
416 switch (res->ai_family) {
417 case AF_INET:
418 ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
419 break;
420 case AF_INET6:
421 ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
422 break;
423 }
424
425 inet_ntop (res->ai_family, ptr, addrstr, 100);
426 if (verbose >= 1) {
427 printf ("* getaddrinfo IPv%d address: %s\n",
428 res->ai_family == PF_INET6 ? 6 : 4, addrstr);
429 }
430
431 // Append all IPs to buf as a comma-separated string
432 addrstr_len = strlen(addrstr);
433 if (buflen_remaining > addrstr_len + 1) {
434 if (buf[0] != '\0') {
435 strncat(buf, ",", buflen_remaining);
436 buflen_remaining -= 1;
437 }
438 strncat(buf, addrstr, buflen_remaining);
439 buflen_remaining -= addrstr_len;
440 }
441
442 res = res->ai_next;
443 }
444
445 freeaddrinfo(result);
446
447 return 0;
448}
449 191
450static void 192 // workaround for issue:
451cleanup (void) 193 // OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0
452{ 194 // see discussion https://github.com/openssl/openssl/discussions/22690
453 if (status_line_initialized) curlhelp_free_statusline(&status_line); 195# ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
454 status_line_initialized = false; 196 SSL_CTX_set_options(sslctx, SSL_OP_IGNORE_UNEXPECTED_EOF);
455 if (curl_easy_initialized) curl_easy_cleanup (curl); 197# endif
456 curl_easy_initialized = false; 198
457 if (curl_global_initialized) curl_global_cleanup (); 199 return CURLE_OK;
458 curl_global_initialized = false;
459 if (body_buf_initialized) curlhelp_freewritebuffer (&body_buf);
460 body_buf_initialized = false;
461 if (header_buf_initialized) curlhelp_freewritebuffer (&header_buf);
462 header_buf_initialized = false;
463 if (put_buf_initialized) curlhelp_freereadbuffer (&put_buf);
464 put_buf_initialized = false;
465} 200}
201# endif /* USE_OPENSSL */
202#endif /* HAVE_SSL */
466 203
467int 204mp_subcheck check_http(const check_curl_config config, check_curl_working_state workingState,
468check_http (void) 205 int redir_depth) {
469{
470 int result = STATE_OK;
471 int result_ssl = STATE_OK;
472 int page_len = 0;
473 int i;
474 char *force_host_header = NULL;
475 struct curl_slist *host = NULL;
476 char addrstr[DEFAULT_BUFFER_SIZE/2];
477 char dnscache[DEFAULT_BUFFER_SIZE];
478
479 /* initialize curl */
480 if (curl_global_init (CURL_GLOBAL_DEFAULT) != CURLE_OK)
481 die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n");
482 curl_global_initialized = true;
483
484 if ((curl = curl_easy_init()) == NULL) {
485 die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n");
486 }
487 curl_easy_initialized = true;
488
489 /* register cleanup function to shut down libcurl properly */
490 atexit (cleanup);
491
492 if (verbose >= 1)
493 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_VERBOSE, 1), "CURLOPT_VERBOSE");
494
495 /* print everything on stdout like check_http would do */
496 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_STDERR, stdout), "CURLOPT_STDERR");
497
498 if (automatic_decompression)
499#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");
501#else
502 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_ENCODING, ""), "CURLOPT_ENCODING");
503#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */
504
505 /* initialize buffer for body of the answer */
506 if (curlhelp_initwritebuffer(&body_buf) < 0)
507 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n");
508 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");
510 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void *)&body_buf), "CURLOPT_WRITEDATA");
511
512 /* initialize buffer for header of the answer */
513 if (curlhelp_initwritebuffer( &header_buf ) < 0)
514 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n" );
515 header_buf_initialized = true;
516 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback), "CURLOPT_HEADERFUNCTION");
517 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEHEADER, (void *)&header_buf), "CURLOPT_WRITEHEADER");
518
519 /* set the error buffer */
520 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, errbuf), "CURLOPT_ERRORBUFFER");
521
522 /* set timeouts */
523 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, socket_timeout), "CURLOPT_CONNECTTIMEOUT");
524 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_TIMEOUT, socket_timeout), "CURLOPT_TIMEOUT");
525
526 /* enable haproxy protocol */
527 if (haproxy_protocol) {
528 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L), "CURLOPT_HAPROXYPROTOCOL");
529 }
530
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
532 if(use_ssl && host_name != NULL) {
533 if ( (res=lookup_host (server_address, addrstr, DEFAULT_BUFFER_SIZE/2)) != 0) {
534 snprintf (msg,
535 DEFAULT_BUFFER_SIZE,
536 _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"),
537 server_address,
538 res,
539 gai_strerror (res));
540 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
541 }
542 snprintf (dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", host_name, server_port, addrstr);
543 host = curl_slist_append(NULL, dnscache);
544 curl_easy_setopt(curl, CURLOPT_RESOLVE, host);
545 if (verbose>=1)
546 printf ("* curl CURLOPT_RESOLVE: %s\n", dnscache);
547 }
548
549 // If server_address is an IPv6 address it must be surround by square brackets
550 struct in6_addr tmp_in_addr;
551 if (inet_pton(AF_INET6, server_address, &tmp_in_addr) == 1) {
552 char *new_server_address = malloc(strlen(server_address) + 3);
553 if (new_server_address == NULL) {
554 die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n");
555 }
556 snprintf(new_server_address, strlen(server_address)+3, "[%s]", server_address);
557 free(server_address);
558 server_address = new_server_address;
559 }
560
561 /* compose URL: use the address we want to connect to, set Host: header later */
562 snprintf (url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s",
563 use_ssl ? "https" : "http",
564 ( use_ssl & ( host_name != NULL ) ) ? host_name : server_address,
565 server_port,
566 server_url
567 );
568
569 if (verbose>=1)
570 printf ("* curl CURLOPT_URL: %s\n", url);
571 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_URL, url), "CURLOPT_URL");
572
573 /* extract proxy information for legacy proxy https requests */
574 if (!strcmp(http_method, "CONNECT") || strstr(server_url, "http") == server_url) {
575 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_PROXY, server_address), "CURLOPT_PROXY");
576 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_PROXYPORT, (long)server_port), "CURLOPT_PROXYPORT");
577 if (verbose>=2)
578 printf ("* curl CURLOPT_PROXY: %s:%d\n", server_address, server_port);
579 http_method = "GET";
580 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_URL, server_url), "CURLOPT_URL");
581 }
582
583 /* disable body for HEAD request */
584 if (http_method && !strcmp (http_method, "HEAD" )) {
585 no_body = true;
586 }
587
588 /* set HTTP protocol version */
589 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_HTTP_VERSION, curl_http_version), "CURLOPT_HTTP_VERSION");
590
591 /* set HTTP method */
592 if (http_method) {
593 if (!strcmp(http_method, "POST"))
594 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_POST, 1), "CURLOPT_POST");
595 else if (!strcmp(http_method, "PUT"))
596 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_UPLOAD, 1), "CURLOPT_UPLOAD");
597 else
598 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CUSTOMREQUEST, http_method), "CURLOPT_CUSTOMREQUEST");
599 }
600
601 /* check if Host header is explicitly set in options */
602 if (http_opt_headers_count) {
603 for (i = 0; i < http_opt_headers_count ; i++) {
604 if (strncmp(http_opt_headers[i], "Host:", 5) == 0) {
605 force_host_header = http_opt_headers[i];
606 }
607 }
608 }
609
610 /* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in anyway */
611 if(host_name != NULL && force_host_header == NULL) {
612 if((virtual_port != HTTP_PORT && !use_ssl) || (virtual_port != HTTPS_PORT && use_ssl)) {
613 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", host_name, virtual_port);
614 } else {
615 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", host_name);
616 }
617 header_list = curl_slist_append (header_list, http_header);
618 }
619
620 /* always close connection, be nice to servers */
621 snprintf (http_header, DEFAULT_BUFFER_SIZE, "Connection: close");
622 header_list = curl_slist_append (header_list, http_header);
623
624 /* attach additional headers supplied by the user */
625 /* optionally send any other header tag */
626 if (http_opt_headers_count) {
627 for (i = 0; i < http_opt_headers_count ; i++) {
628 header_list = curl_slist_append (header_list, http_opt_headers[i]);
629 }
630 /* This cannot be free'd here because a redirection will then try to access this and segfault */
631 /* Covered in a testcase in tests/check_http.t */
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 206
638#ifdef LIBCURL_FEATURE_SSL 207 // =======================
208 // Initialisation for curl
209 // =======================
210 check_curl_configure_curl_wrapper conf_curl_struct = check_curl_configure_curl(
211 config.curl_config, workingState, config.check_cert, config.on_redirect_dependent,
212 config.followmethod, config.max_depth);
639 213
640 /* set SSL version, warn about insecure or unsupported versions */ 214 check_curl_global_state curl_state = conf_curl_struct.curl_state;
641 if (use_ssl) { 215 workingState = conf_curl_struct.working_state;
642 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLVERSION, ssl_version), "CURLOPT_SSLVERSION");
643 }
644
645 /* client certificate and key to present to server (SSL) */
646 if (client_cert)
647 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLCERT, client_cert), "CURLOPT_SSLCERT");
648 if (client_privkey)
649 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLKEY, client_privkey), "CURLOPT_SSLKEY");
650 if (ca_cert) {
651 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CAINFO, ca_cert), "CURLOPT_CAINFO");
652 }
653 if (ca_cert || verify_peer_and_host) {
654 /* per default if we have a CA verify both the peer and the
655 * 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");
657 handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_SSL_VERIFYHOST, 2), "CURLOPT_SSL_VERIFYHOST");
658 } else {
659 /* backward-compatible behaviour, be tolerant in checks
660 * TODO: depending on more options have aspects we want
661 * to be less tolerant about ssl verfications
662 */
663 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");
665 }
666
667 /* detect SSL library used by libcurl */
668 ssl_library = curlhelp_get_ssl_library ();
669
670 /* try hard to get a stack of certificates to verify against */
671 if (check_cert) {
672#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1)
673 /* inform curl to report back certificates */
674 switch (ssl_library) {
675 case CURLHELP_SSL_LIBRARY_OPENSSL:
676 case CURLHELP_SSL_LIBRARY_LIBRESSL:
677 /* set callback to extract certificate with OpenSSL context function (works with
678 * OpenSSL-style libraries only!) */
679#ifdef USE_OPENSSL
680 /* 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");
682 is_openssl_callback = true;
683#else /* USE_OPENSSL */
684#endif /* USE_OPENSSL */
685 /* libcurl is built with OpenSSL, monitoring plugins, so falling
686 * back to manually extracting certificate information */
687 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
688 break;
689
690 case CURLHELP_SSL_LIBRARY_NSS:
691#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
692 /* NSS: support for CERTINFO is implemented since 7.34.0 */
693 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
694#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
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));
696#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
697 break;
698
699 case CURLHELP_SSL_LIBRARY_GNUTLS:
700#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0)
701 /* 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");
703#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));
705#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
706 break;
707
708 case CURLHELP_SSL_LIBRARY_UNKNOWN:
709 default:
710 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (unknown SSL library '%s', must implement first)\n", curlhelp_get_ssl_library_string (ssl_library));
711 break;
712 }
713#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
714 /* old libcurl, our only hope is OpenSSL, otherwise we are out of luck */
715 if (ssl_library == CURLHELP_SSL_LIBRARY_OPENSSL || ssl_library == CURLHELP_SSL_LIBRARY_LIBRESSL)
716 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION");
717 else
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");
719#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
720 }
721 216
722#endif /* LIBCURL_FEATURE_SSL */ 217 mp_subcheck sc_result = mp_subcheck_init();
723 218
724 /* set default or user-given user agent identification */ 219 char *url = fmt_url(workingState);
725 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_USERAGENT, user_agent), "CURLOPT_USERAGENT"); 220 xasprintf(&sc_result.output, "Testing %s", url);
726 221 // TODO add some output here URL or something
727 /* proxy-authentication */ 222 free(url);
728 if (strcmp(proxy_auth, ""))
729 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_PROXYUSERPWD, proxy_auth), "CURLOPT_PROXYUSERPWD");
730
731 /* authentication */
732 if (strcmp(user_auth, ""))
733 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_USERPWD, user_auth), "CURLOPT_USERPWD");
734
735 /* TODO: parameter auth method, bitfield of following methods:
736 * CURLAUTH_BASIC (default)
737 * CURLAUTH_DIGEST
738 * CURLAUTH_DIGEST_IE
739 * CURLAUTH_NEGOTIATE
740 * CURLAUTH_NTLM
741 * CURLAUTH_NTLM_WB
742 *
743 * convenience tokens for typical sets of methods:
744 * CURLAUTH_ANYSAFE: most secure, without BASIC
745 * or CURLAUTH_ANY: most secure, even BASIC if necessary
746 *
747 * handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_DIGEST ), "CURLOPT_HTTPAUTH");
748 */
749
750 /* handle redirections */
751 if (onredirect == STATE_DEPENDENT) {
752 if( followmethod == FOLLOW_LIBCURL ) {
753 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1), "CURLOPT_FOLLOWLOCATION");
754
755 /* 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
757 */
758 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_MAXREDIRS, max_depth+1), "CURLOPT_MAXREDIRS");
759
760 /* 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)
762 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"), "CURLOPT_REDIR_PROTOCOLS_STR");
763#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");
765#endif
766 223
767 /* TODO: handle the following aspects of redirection, make them 224 // ==============
768 * command line options too later: 225 // do the request
769 CURLOPT_POSTREDIR: method switch 226 // ==============
770 CURLINFO_REDIRECT_URL: custom redirect option 227 CURLcode res = curl_easy_perform(curl_state.curl);
771 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?
773 */
774 } else {
775 /* old style redirection is handled below */
776 }
777 }
778
779 /* no-body */
780 if (no_body)
781 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_NOBODY, 1), "CURLOPT_NOBODY");
782
783 /* IPv4 or IPv6 forced DNS resolution */
784 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)");
786 else if (address_family == AF_INET)
787 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)");
788#if defined (USE_IPV6) && defined (LIBCURL_FEATURE_IPV6)
789 else if (address_family == AF_INET6)
790 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)");
791#endif
792
793 /* either send http POST data (any data, not only POST)*/
794 if (!strcmp(http_method, "POST") ||!strcmp(http_method, "PUT")) {
795 /* set content of payload for POST and PUT */
796 if (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);
799 }
800 /* NULL indicates "HTTP Continue" in libcurl, provide an empty string
801 * in case of no POST/PUT data */
802 if (!http_post_data)
803 http_post_data = "";
804 if (!strcmp(http_method, "POST")) {
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");
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");
809 if (curlhelp_initreadbuffer (&put_buf, http_post_data, strlen (http_post_data)) < 0)
810 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating read buffer for PUT\n");
811 put_buf_initialized = true;
812 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_READDATA, (void *)&put_buf), "CURLOPT_READDATA");
813 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_INFILESIZE, (curl_off_t)strlen (http_post_data)), "CURLOPT_INFILESIZE");
814 }
815 }
816
817 /* cookie handling */
818 if (cookie_jar_file != NULL) {
819 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_COOKIEJAR, cookie_jar_file), "CURLOPT_COOKIEJAR");
820 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_COOKIEFILE, cookie_jar_file), "CURLOPT_COOKIEFILE");
821 }
822
823 /* do the request */
824 res = curl_easy_perform(curl);
825
826 if (verbose>=2 && http_post_data)
827 printf ("**** REQUEST CONTENT ****\n%s\n", http_post_data);
828
829 /* free header and server IP resolve lists, we don't need it anymore */
830 curl_slist_free_all (header_list); header_list = NULL;
831 curl_slist_free_all (server_ips); server_ips = NULL;
832 if (host) {
833 curl_slist_free_all (host); host = NULL;
834 }
835
836 /* Curl errors, result in critical Nagios state */
837 if (res != CURLE_OK) {
838 snprintf (msg,
839 DEFAULT_BUFFER_SIZE,
840 _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"),
841 server_port,
842 res,
843 errbuf[0] ? errbuf : curl_easy_strerror(res));
844 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
845 }
846
847 /* certificate checks */
848#ifdef LIBCURL_FEATURE_SSL
849 if (use_ssl) {
850 if (check_cert) {
851 if (is_openssl_callback) {
852#ifdef USE_OPENSSL
853 /* check certificate with OpenSSL functions, curl has been built against OpenSSL
854 * and we actually have OpenSSL in the monitoring tools
855 */
856 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
857 if (!continue_after_check_cert) {
858 return result_ssl;
859 }
860#else /* USE_OPENSSL */
861 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL callback used and not linked against OpenSSL\n");
862#endif /* USE_OPENSSL */
863 } else {
864 int i;
865 struct curl_slist *slist;
866
867 cert_ptr.to_info = NULL;
868 res = curl_easy_getinfo (curl, CURLINFO_CERTINFO, &cert_ptr.to_info);
869 if (!res && cert_ptr.to_info) {
870#ifdef USE_OPENSSL
871 /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert parsing
872 * We only check the first certificate and assume it's the one of the server
873 */
874 const char* raw_cert = NULL;
875 for (i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) {
876 for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) {
877 if (verbose >= 2)
878 printf ("%d ** %s\n", i, slist->data);
879 if (strncmp (slist->data, "Cert:", 5) == 0) {
880 raw_cert = &slist->data[5];
881 goto GOT_FIRST_CERT;
882 }
883 }
884 }
885GOT_FIRST_CERT:
886 if (!raw_cert) {
887 snprintf (msg,
888 DEFAULT_BUFFER_SIZE,
889 _("Cannot retrieve certificates from CERTINFO information - certificate data was empty"));
890 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
891 }
892 BIO* cert_BIO = BIO_new (BIO_s_mem());
893 BIO_write (cert_BIO, raw_cert, strlen(raw_cert));
894 cert = PEM_read_bio_X509 (cert_BIO, NULL, NULL, NULL);
895 if (!cert) {
896 snprintf (msg,
897 DEFAULT_BUFFER_SIZE,
898 _("Cannot read certificate from CERTINFO information - BIO error"));
899 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
900 }
901 BIO_free (cert_BIO);
902 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
903 if (!continue_after_check_cert) {
904 return result_ssl;
905 }
906#else /* USE_OPENSSL */
907 /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our disposal,
908 * so we use the libcurl CURLINFO data
909 */
910 result_ssl = net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn, days_till_exp_crit);
911 if (!continue_after_check_cert) {
912 return result_ssl;
913 }
914#endif /* USE_OPENSSL */
915 } else {
916 snprintf (msg,
917 DEFAULT_BUFFER_SIZE,
918 _("Cannot retrieve certificates - cURL returned %d - %s"),
919 res,
920 curl_easy_strerror(res));
921 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
922 }
923 }
924 }
925 }
926#endif /* LIBCURL_FEATURE_SSL */
927 228
928 /* we got the data and we executed the request in a given time, so we can append 229 if (verbose >= 2 && workingState.http_post_data) {
929 * performance data to the answer always 230 printf("**** REQUEST CONTENT ****\n%s\n", workingState.http_post_data);
930 */ 231 }
931 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);
933 if(show_extended_perfdata) {
934 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");
936 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");
938 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s",
939 perfd_time(total_time),
940 perfd_size(page_len),
941 perfd_time_connect(time_connect),
942 use_ssl ? perfd_time_ssl (time_appconnect-time_connect) : "",
943 perfd_time_headers(time_headers - time_appconnect),
944 perfd_time_firstbyte(time_firstbyte - time_headers),
945 perfd_time_transfer(total_time-time_firstbyte)
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
1073 char tmp[DEFAULT_BUFFER_SIZE];
1074
1075 snprintf (tmp,
1076 DEFAULT_BUFFER_SIZE,
1077 _("%sheader '%s' not found on '%s://%s:%d%s', "),
1078 msg,
1079 output_header_search,
1080 use_ssl ? "https" : "http",
1081 host_name ? host_name : server_address,
1082 server_port,
1083 server_url);
1084
1085 strcpy(msg, tmp);
1086
1087 result = STATE_CRITICAL;
1088 }
1089 }
1090
1091 if (strlen (string_expect)) {
1092 if (!strstr (body_buf.buf, string_expect)) {
1093
1094 strncpy(&output_string_search[0],string_expect,sizeof(output_string_search));
1095
1096 if(output_string_search[sizeof(output_string_search)-1]!='\0') {
1097 bcopy("...",&output_string_search[sizeof(output_string_search)-4],4);
1098 }
1099
1100 char tmp[DEFAULT_BUFFER_SIZE];
1101
1102 snprintf (tmp,
1103 DEFAULT_BUFFER_SIZE,
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
1112 strcpy(msg, tmp);
1113
1114 result = STATE_CRITICAL;
1115 }
1116 }
1117
1118 if (strlen (regexp)) {
1119 errcode = regexec (&preg, body_buf.buf, REGS, pmatch, 0);
1120 if ((errcode == 0 && !invert_regex) || (errcode == REG_NOMATCH && invert_regex)) {
1121 /* OK - No-op to avoid changing the logic around it */
1122 result = max_state_alt(STATE_OK, result);
1123 }
1124 else if ((errcode == REG_NOMATCH && !invert_regex) || (errcode == 0 && invert_regex)) {
1125 if (!invert_regex) {
1126 char tmp[DEFAULT_BUFFER_SIZE];
1127
1128 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg);
1129 strcpy(msg, tmp);
1130 232
1131 } else { 233 mp_subcheck sc_curl = mp_subcheck_init();
1132 char tmp[DEFAULT_BUFFER_SIZE];
1133 234
1134 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg); 235 /* Curl errors, result in critical Nagios state */
1135 strcpy(msg, tmp); 236 if (res != CURLE_OK) {
237 xasprintf(&sc_curl.output, _("Error while performing connection: cURL returned %d - %s"),
238 res, errbuf[0] ? errbuf : curl_easy_strerror(res));
239 sc_curl = mp_set_subcheck_state(sc_curl, STATE_CRITICAL);
240 mp_add_subcheck_to_subcheck(&sc_result, sc_curl);
241 return sc_result;
242 }
1136 243
1137 } 244 /* get status line of answer, check sanity of HTTP code */
1138 result = state_regex; 245 if (curlhelp_parse_statusline(curl_state.header_buf->buf, curl_state.status_line) < 0) {
1139 } else { 246 sc_result = mp_set_subcheck_state(sc_result, STATE_CRITICAL);
1140 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 247 /* we cannot know the major/minor version here for sure as we cannot parse the first
248 * line */
249 xasprintf(&sc_result.output, "HTTP/x.x unknown - Unparsable status line");
250 return sc_result;
251 }
1141 252
1142 char tmp[DEFAULT_BUFFER_SIZE]; 253 curl_state.status_line_initialized = true;
1143 254
1144 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sExecute Error: %s, "), msg, errbuf); 255 size_t page_len = get_content_length(curl_state.header_buf, curl_state.body_buf);
1145 strcpy(msg, tmp);
1146 result = STATE_UNKNOWN;
1147 }
1148 }
1149 256
1150 /* make sure the page is of an appropriate size */ 257 double total_time;
1151 if ((max_page_len > 0) && (page_len > max_page_len)) { 258 handle_curl_option_return_code(
1152 char tmp[DEFAULT_BUFFER_SIZE]; 259 curl_easy_getinfo(curl_state.curl, CURLINFO_TOTAL_TIME, &total_time),
260 "CURLINFO_TOTAL_TIME");
1153 261
1154 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too large, "), msg, page_len); 262 xasprintf(
263 &sc_curl.output, "%s %d %s - %ld bytes in %.3f second response time",
264 string_statuscode(curl_state.status_line->http_major, curl_state.status_line->http_minor),
265 curl_state.status_line->http_code, curl_state.status_line->msg, page_len, total_time);
266 sc_curl = mp_set_subcheck_state(sc_curl, STATE_OK);
267 mp_add_subcheck_to_subcheck(&sc_result, sc_curl);
1155 268
1156 strcpy(msg, tmp); 269 // ==========
270 // Evaluation
271 // ==========
1157 272
1158 result = max_state_alt(STATE_WARNING, result); 273#ifdef LIBCURL_FEATURE_SSL
1159 274 if (workingState.use_ssl && config.check_cert) {
1160 } else if ((min_page_len > 0) && (page_len < min_page_len)) { 275 mp_subcheck sc_certificate = check_curl_certificate_checks(
1161 char tmp[DEFAULT_BUFFER_SIZE]; 276 curl_state.curl, cert, config.days_till_exp_warn, config.days_till_exp_crit);
1162 277
1163 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too small, "), msg, page_len); 278 mp_add_subcheck_to_subcheck(&sc_result, sc_certificate);
1164 strcpy(msg, tmp); 279 if (!config.continue_after_check_cert) {
1165 result = max_state_alt(STATE_WARNING, result); 280 return sc_result;
281 }
1166 } 282 }
283#endif
1167 284
1168 /* -w, -c: check warning and critical level */ 285 /* we got the data and we executed the request in a given time, so we can append
1169 result = max_state_alt(get_status(total_time, thlds), result); 286 * performance data to the answer always
1170 287 */
1171 /* Cut-off trailing characters */ 288
1172 if (strlen(msg) >= 2) { 289 // total time the query took
1173 if(msg[strlen(msg)-2] == ',') 290 mp_perfdata pd_total_time = perfdata_init();
1174 msg[strlen(msg)-2] = '\0'; 291 mp_perfdata_value pd_val_total_time = mp_create_pd_value(total_time);
1175 else 292 pd_total_time.value = pd_val_total_time;
1176 msg[strlen(msg)-3] = '\0'; 293 pd_total_time = mp_pd_set_thresholds(pd_total_time, config.thlds);
1177 } 294 pd_total_time.label = "time";
1178 295 pd_total_time.uom = "s";
1179 /* TODO: separate _() msg and status code: die (result, "HTTP %s: %s\n", state_text(result), msg); */ 296
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", 297 mp_subcheck sc_total_time = mp_subcheck_init();
1181 state_text(result), string_statuscode (status_line.http_major, status_line.http_minor), 298 sc_total_time = mp_set_subcheck_state(sc_total_time, mp_get_pd_status(pd_total_time));
1182 status_line.http_code, status_line.msg, 299 xasprintf(&sc_total_time.output, "Total connection time: %fs", total_time);
1183 strlen(msg) > 0 ? " - " : "", 300 mp_add_perfdata_to_subcheck(&sc_total_time, pd_total_time);
1184 msg, page_len, total_time, 301
1185 (display_html ? "</A>" : ""), 302 mp_add_subcheck_to_subcheck(&sc_result, sc_total_time);
1186 perfstring, 303
1187 (show_body ? body_buf.buf : ""), 304 if (config.show_extended_perfdata) {
1188 (show_body ? "\n" : "") ); 305 // overall connection time
1189 306 mp_perfdata pd_time_connect = perfdata_init();
1190 return max_state_alt(result, result_ssl); 307 double time_connect;
1191} 308 handle_curl_option_return_code(
1192 309 curl_easy_getinfo(curl_state.curl, CURLINFO_CONNECT_TIME, &time_connect),
1193int 310 "CURLINFO_CONNECT_TIME");
1194uri_strcmp (const UriTextRangeA range, const char* s) 311
1195{ 312 mp_perfdata_value pd_val_time_connect = mp_create_pd_value(time_connect);
1196 if (!range.first) return -1; 313 pd_time_connect.value = pd_val_time_connect;
1197 if ( (size_t)(range.afterLast - range.first) < strlen (s) ) return -1; 314 pd_time_connect.label = "time_connect";
1198 return strncmp (s, range.first, min( (size_t)(range.afterLast - range.first), strlen (s))); 315 pd_time_connect.uom = "s";
1199} 316 pd_time_connect = mp_set_pd_max_value(
317 pd_time_connect, mp_create_pd_value(config.curl_config.socket_timeout));
318
319 pd_time_connect = mp_pd_set_thresholds(pd_time_connect, config.thlds);
320 mp_add_perfdata_to_subcheck(&sc_result, pd_time_connect);
321
322 // application connection time, used to compute other timings
323 double time_appconnect;
324 handle_curl_option_return_code(
325 curl_easy_getinfo(curl_state.curl, CURLINFO_APPCONNECT_TIME, &time_appconnect),
326 "CURLINFO_APPCONNECT_TIME");
327
328 if (workingState.use_ssl) {
329 mp_perfdata pd_time_tls = perfdata_init();
330 {
331 mp_perfdata_value pd_val_time_tls =
332 mp_create_pd_value(time_appconnect - time_connect);
333
334 pd_time_tls.value = pd_val_time_tls;
335 }
336 pd_time_tls.label = "time_tls";
337 pd_time_tls.uom = "s";
338 mp_add_perfdata_to_subcheck(&sc_result, pd_time_tls);
339 }
1200 340
1201char* 341 mp_perfdata pd_time_headers = perfdata_init();
1202uri_string (const UriTextRangeA range, char* buf, size_t buflen) 342 {
1203{ 343 double time_headers;
1204 if (!range.first) return "(null)"; 344 handle_curl_option_return_code(
1205 strncpy (buf, range.first, max (buflen-1, (size_t)(range.afterLast - range.first))); 345 curl_easy_getinfo(curl_state.curl, CURLINFO_PRETRANSFER_TIME, &time_headers),
1206 buf[max (buflen-1, (size_t)(range.afterLast - range.first))] = '\0'; 346 "CURLINFO_PRETRANSFER_TIME");
1207 buf[range.afterLast - range.first] = '\0';
1208 return buf;
1209}
1210 347
1211void 348 mp_perfdata_value pd_val_time_headers =
1212redir (curlhelp_write_curlbuf* header_buf) 349 mp_create_pd_value(time_headers - time_appconnect);
1213{
1214 char *location = NULL;
1215 curlhelp_statusline status_line;
1216 struct phr_header headers[255];
1217 size_t nof_headers = 255;
1218 size_t msglen;
1219 char buf[DEFAULT_BUFFER_SIZE];
1220 char ipstr[INET_ADDR_MAX_SIZE];
1221 int new_port;
1222 char *new_host;
1223 char *new_url;
1224
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 350
1229 if (res == -1) { 351 pd_time_headers.value = pd_val_time_headers;
1230 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 352 }
353 pd_time_headers.label = "time_headers";
354 pd_time_headers.uom = "s";
355 mp_add_perfdata_to_subcheck(&sc_result, pd_time_headers);
356
357 mp_perfdata pd_time_firstbyte = perfdata_init();
358 double time_firstbyte;
359 handle_curl_option_return_code(
360 curl_easy_getinfo(curl_state.curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte),
361 "CURLINFO_STARTTRANSFER_TIME");
362
363 mp_perfdata_value pd_val_time_firstbyte = mp_create_pd_value(time_firstbyte);
364 pd_time_firstbyte.value = pd_val_time_firstbyte;
365 pd_time_firstbyte.label = "time_firstbyte";
366 pd_time_firstbyte.uom = "s";
367 mp_add_perfdata_to_subcheck(&sc_result, pd_time_firstbyte);
368
369 mp_perfdata pd_time_transfer = perfdata_init();
370 pd_time_transfer.value = mp_create_pd_value(total_time - time_firstbyte);
371 pd_time_transfer.label = "time_transfer";
372 pd_time_transfer.uom = "s";
373 mp_add_perfdata_to_subcheck(&sc_result, pd_time_transfer);
1231 } 374 }
1232 375
1233 location = get_header_value (headers, nof_headers, "location"); 376 /* return a CRITICAL status if we couldn't read any data */
1234 377 if (strlen(curl_state.header_buf->buf) == 0 && strlen(curl_state.body_buf->buf) == 0) {
1235 if (verbose >= 2) 378 sc_result = mp_set_subcheck_state(sc_result, STATE_CRITICAL);
1236 printf(_("* Seen redirect location %s\n"), location); 379 xasprintf(&sc_result.output, "No header received from host");
1237 380 return sc_result;
1238 if (++redir_depth > max_depth)
1239 die (STATE_WARNING,
1240 _("HTTP WARNING - maximum redirection depth %d exceeded - %s%s\n"),
1241 max_depth, location, (display_html ? "</A>" : ""));
1242
1243 UriParserStateA state;
1244 UriUriA uri;
1245 state.uri = &uri;
1246 if (uriParseUriA (&state, location) != URI_SUCCESS) {
1247 if (state.errorCode == URI_ERROR_SYNTAX) {
1248 die (STATE_UNKNOWN,
1249 _("HTTP UNKNOWN - Could not parse redirect location '%s'%s\n"),
1250 location, (display_html ? "</A>" : ""));
1251 } else if (state.errorCode == URI_ERROR_MALLOC) {
1252 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1253 }
1254 }
1255
1256 if (verbose >= 2) {
1257 printf (_("** scheme: %s\n"),
1258 uri_string (uri.scheme, buf, DEFAULT_BUFFER_SIZE));
1259 printf (_("** host: %s\n"),
1260 uri_string (uri.hostText, buf, DEFAULT_BUFFER_SIZE));
1261 printf (_("** port: %s\n"),
1262 uri_string (uri.portText, buf, DEFAULT_BUFFER_SIZE));
1263 if (uri.hostData.ip4) {
1264 inet_ntop (AF_INET, uri.hostData.ip4->data, ipstr, sizeof (ipstr));
1265 printf (_("** IPv4: %s\n"), ipstr);
1266 }
1267 if (uri.hostData.ip6) {
1268 inet_ntop (AF_INET, uri.hostData.ip6->data, ipstr, sizeof (ipstr));
1269 printf (_("** IPv6: %s\n"), ipstr);
1270 }
1271 if (uri.pathHead) {
1272 printf (_("** path: "));
1273 const UriPathSegmentA* p = uri.pathHead;
1274 for (; p; p = p->next) {
1275 printf ("/%s", uri_string (p->text, buf, DEFAULT_BUFFER_SIZE));
1276 }
1277 puts ("");
1278 }
1279 if (uri.query.first) {
1280 printf (_("** query: %s\n"),
1281 uri_string (uri.query, buf, DEFAULT_BUFFER_SIZE));
1282 }
1283 if (uri.fragment.first) {
1284 printf (_("** fragment: %s\n"),
1285 uri_string (uri.fragment, buf, DEFAULT_BUFFER_SIZE));
1286 }
1287 }
1288
1289 if (uri.scheme.first) {
1290 if (!uri_strcmp (uri.scheme, "https"))
1291 use_ssl = true;
1292 else
1293 use_ssl = false;
1294 }
1295
1296 /* we do a sloppy test here only, because uriparser would have failed
1297 * above, if the port would be invalid, we just check for MAX_PORT
1298 */
1299 if (uri.portText.first) {
1300 new_port = atoi (uri_string (uri.portText, buf, DEFAULT_BUFFER_SIZE));
1301 } else {
1302 new_port = HTTP_PORT;
1303 if (use_ssl)
1304 new_port = HTTPS_PORT;
1305 }
1306 if (new_port > MAX_PORT)
1307 die (STATE_UNKNOWN,
1308 _("HTTP UNKNOWN - Redirection to port above %d - %s%s\n"),
1309 MAX_PORT, location, display_html ? "</A>" : "");
1310
1311 /* by RFC 7231 relative URLs in Location should be taken relative to
1312 * the original URL, so we try to form a new absolute URL here
1313 */
1314 if (!uri.scheme.first && !uri.hostText.first) {
1315 new_host = strdup (host_name ? host_name : server_address);
1316 new_port = server_port;
1317 if(use_ssl)
1318 uri_string (uri.scheme, "https", DEFAULT_BUFFER_SIZE);
1319 } else {
1320 new_host = strdup (uri_string (uri.hostText, buf, DEFAULT_BUFFER_SIZE));
1321 }
1322
1323 /* compose new path */
1324 /* TODO: handle fragments and query part of URL */
1325 new_url = (char *)calloc( 1, DEFAULT_BUFFER_SIZE);
1326 if (uri.pathHead) {
1327 const UriPathSegmentA* p = uri.pathHead;
1328 for (; p; p = p->next) {
1329 strncat (new_url, "/", DEFAULT_BUFFER_SIZE);
1330 strncat (new_url, uri_string (p->text, buf, DEFAULT_BUFFER_SIZE), DEFAULT_BUFFER_SIZE-1);
1331 }
1332 }
1333
1334 if (server_port==new_port &&
1335 !strncmp(server_address, new_host, MAX_IPV4_HOSTLENGTH) &&
1336 (host_name && !strncmp(host_name, new_host, MAX_IPV4_HOSTLENGTH)) &&
1337 !strcmp(server_url, new_url))
1338 die (STATE_CRITICAL,
1339 _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1340 use_ssl ? "https" : "http", new_host, new_port, new_url, (display_html ? "</A>" : ""));
1341
1342 /* set new values for redirected request */
1343
1344 if (!(followsticky & STICKY_HOST)) {
1345 free (server_address);
1346 server_address = strndup (new_host, MAX_IPV4_HOSTLENGTH);
1347 }
1348 if (!(followsticky & STICKY_PORT)) {
1349 server_port = (unsigned short)new_port;
1350 }
1351
1352 free (host_name);
1353 host_name = strndup (new_host, MAX_IPV4_HOSTLENGTH);
1354
1355 /* reset virtual port */
1356 virtual_port = server_port;
1357
1358 free(new_host);
1359 free (server_url);
1360 server_url = new_url;
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}
1375
1376/* check whether a file exists */
1377void
1378test_file (char *path)
1379{
1380 if (access(path, R_OK) == 0)
1381 return;
1382 usage2 (_("file does not exist or is not readable"), path);
1383}
1384
1385bool
1386process_arguments (int argc, char **argv)
1387{
1388 char *p;
1389 int c = 1;
1390 char *temp;
1391
1392 enum {
1393 INVERT_REGEX = CHAR_MAX + 1,
1394 SNI_OPTION,
1395 MAX_REDIRS_OPTION,
1396 CONTINUE_AFTER_CHECK_CERT,
1397 CA_CERT_OPTION,
1398 HTTP_VERSION_OPTION,
1399 AUTOMATIC_DECOMPRESSION,
1400 COOKIE_JAR,
1401 HAPROXY_PROTOCOL,
1402 STATE_REGEX
1403 };
1404
1405 int option = 0;
1406 int got_plus = 0;
1407 static struct option longopts[] = {
1408 STD_LONG_OPTS,
1409 {"link", no_argument, 0, 'L'},
1410 {"nohtml", no_argument, 0, 'n'},
1411 {"ssl", optional_argument, 0, 'S'},
1412 {"sni", no_argument, 0, SNI_OPTION},
1413 {"post", required_argument, 0, 'P'},
1414 {"method", required_argument, 0, 'j'},
1415 {"IP-address", required_argument, 0, 'I'},
1416 {"url", required_argument, 0, 'u'},
1417 {"port", required_argument, 0, 'p'},
1418 {"authorization", required_argument, 0, 'a'},
1419 {"proxy-authorization", required_argument, 0, 'b'},
1420 {"header-string", required_argument, 0, 'd'},
1421 {"string", required_argument, 0, 's'},
1422 {"expect", required_argument, 0, 'e'},
1423 {"regex", required_argument, 0, 'r'},
1424 {"ereg", required_argument, 0, 'r'},
1425 {"eregi", required_argument, 0, 'R'},
1426 {"linespan", no_argument, 0, 'l'},
1427 {"onredirect", required_argument, 0, 'f'},
1428 {"certificate", required_argument, 0, 'C'},
1429 {"client-cert", required_argument, 0, 'J'},
1430 {"private-key", required_argument, 0, 'K'},
1431 {"ca-cert", required_argument, 0, CA_CERT_OPTION},
1432 {"verify-cert", no_argument, 0, 'D'},
1433 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT},
1434 {"useragent", required_argument, 0, 'A'},
1435 {"header", required_argument, 0, 'k'},
1436 {"no-body", no_argument, 0, 'N'},
1437 {"max-age", required_argument, 0, 'M'},
1438 {"content-type", required_argument, 0, 'T'},
1439 {"pagesize", required_argument, 0, 'm'},
1440 {"invert-regex", no_argument, NULL, INVERT_REGEX},
1441 {"state-regex", required_argument, 0, STATE_REGEX},
1442 {"use-ipv4", no_argument, 0, '4'},
1443 {"use-ipv6", no_argument, 0, '6'},
1444 {"extended-perfdata", no_argument, 0, 'E'},
1445 {"show-body", no_argument, 0, 'B'},
1446 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION},
1447 {"http-version", required_argument, 0, HTTP_VERSION_OPTION},
1448 {"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION},
1449 {"cookie-jar", required_argument, 0, COOKIE_JAR},
1450 {"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL},
1451 {0, 0, 0, 0}
1452 };
1453
1454 if (argc < 2)
1455 return false;
1456
1457 /* support check_http compatible arguments */
1458 for (c = 1; c < argc; c++) {
1459 if (strcmp ("-to", argv[c]) == 0)
1460 strcpy (argv[c], "-t");
1461 if (strcmp ("-hn", argv[c]) == 0)
1462 strcpy (argv[c], "-H");
1463 if (strcmp ("-wt", argv[c]) == 0)
1464 strcpy (argv[c], "-w");
1465 if (strcmp ("-ct", argv[c]) == 0)
1466 strcpy (argv[c], "-c");
1467 if (strcmp ("-nohtml", argv[c]) == 0)
1468 strcpy (argv[c], "-n");
1469 }
1470
1471 server_url = strdup(DEFAULT_SERVER_URL);
1472
1473 while (1) {
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);
1475 if (c == -1 || c == EOF || c == 1)
1476 break;
1477
1478 switch (c) {
1479 case 'h':
1480 print_help();
1481 exit(STATE_UNKNOWN);
1482 break;
1483 case 'V':
1484 print_revision(progname, NP_VERSION);
1485 print_curl_version();
1486 exit(STATE_UNKNOWN);
1487 break;
1488 case 'v':
1489 verbose++;
1490 break;
1491 case 't': /* timeout period */
1492 if (!is_intnonneg (optarg))
1493 usage2 (_("Timeout interval must be a positive integer"), optarg);
1494 else
1495 socket_timeout = (int)strtol (optarg, NULL, 10);
1496 break;
1497 case 'c': /* critical time threshold */
1498 critical_thresholds = optarg;
1499 break;
1500 case 'w': /* warning time threshold */
1501 warning_thresholds = optarg;
1502 break;
1503 case 'H': /* virtual host */
1504 host_name = strdup (optarg);
1505 if (host_name[0] == '[') {
1506 if ((p = strstr (host_name, "]:")) != NULL) { /* [IPv6]:port */
1507 virtual_port = atoi (p + 2);
1508 /* cut off the port */
1509 host_name_length = strlen (host_name) - strlen (p) - 1;
1510 free (host_name);
1511 host_name = strndup (optarg, host_name_length);
1512 } 381 }
1513 } else if ((p = strchr (host_name, ':')) != NULL
1514 && strchr (++p, ':') == NULL) { /* IPv4:port or host:port */
1515 virtual_port = atoi (p);
1516 /* cut off the port */
1517 host_name_length = strlen (host_name) - strlen (p) - 1;
1518 free (host_name);
1519 host_name = strndup (optarg, host_name_length);
1520 }
1521 break;
1522 case 'I': /* internet address */
1523 server_address = strdup (optarg);
1524 break;
1525 case 'u': /* URL path */
1526 server_url = strdup (optarg);
1527 break;
1528 case 'p': /* Server port */
1529 if (!is_intnonneg (optarg))
1530 usage2 (_("Invalid port number, expecting a non-negative number"), optarg);
1531 else {
1532 if( strtol(optarg, NULL, 10) > MAX_PORT)
1533 usage2 (_("Invalid port number, supplied port number is too big"), optarg);
1534 server_port = (unsigned short)strtol(optarg, NULL, 10);
1535 specify_port = true;
1536 }
1537 break;
1538 case 'a': /* authorization info */
1539 strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
1540 user_auth[MAX_INPUT_BUFFER - 1] = 0;
1541 break;
1542 case 'b': /* proxy-authorization info */
1543 strncpy (proxy_auth, optarg, MAX_INPUT_BUFFER - 1);
1544 proxy_auth[MAX_INPUT_BUFFER - 1] = 0;
1545 break;
1546 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
1547 if (! http_post_data)
1548 http_post_data = strdup (optarg);
1549 if (! http_method)
1550 http_method = strdup("POST");
1551 break;
1552 case 'j': /* Set HTTP method */
1553 if (http_method)
1554 free(http_method);
1555 http_method = strdup (optarg);
1556 break;
1557 case 'A': /* useragent */
1558 strncpy (user_agent, optarg, DEFAULT_BUFFER_SIZE);
1559 user_agent[DEFAULT_BUFFER_SIZE-1] = '\0';
1560 break;
1561 case 'k': /* Additional headers */
1562 if (http_opt_headers_count == 0)
1563 http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count));
1564 else
1565 http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count));
1566 http_opt_headers[http_opt_headers_count - 1] = optarg;
1567 break;
1568 case 'L': /* show html link */
1569 display_html = true;
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
1576 if ((temp=strchr(optarg,','))!=NULL) {
1577 *temp='\0';
1578 if (!is_intnonneg (optarg))
1579 usage2 (_("Invalid certificate expiration period"), optarg);
1580 days_till_exp_warn = atoi(optarg);
1581 *temp=',';
1582 temp++;
1583 if (!is_intnonneg (temp))
1584 usage2 (_("Invalid certificate expiration period"), temp);
1585 days_till_exp_crit = atoi (temp);
1586 }
1587 else {
1588 days_till_exp_crit=0;
1589 if (!is_intnonneg (optarg))
1590 usage2 (_("Invalid certificate expiration period"), optarg);
1591 days_till_exp_warn = atoi (optarg);
1592 }
1593 check_cert = true;
1594 goto enable_ssl;
1595#endif
1596 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
1597#ifdef HAVE_SSL
1598 continue_after_check_cert = true;
1599 break;
1600#endif
1601 case 'J': /* use client certificate */
1602#ifdef LIBCURL_FEATURE_SSL
1603 test_file(optarg);
1604 client_cert = optarg;
1605 goto enable_ssl;
1606#endif
1607 case 'K': /* use client private key */
1608#ifdef LIBCURL_FEATURE_SSL
1609 test_file(optarg);
1610 client_privkey = optarg;
1611 goto enable_ssl;
1612#endif
1613#ifdef LIBCURL_FEATURE_SSL
1614 case CA_CERT_OPTION: /* use CA chain file */
1615 test_file(optarg);
1616 ca_cert = optarg;
1617 goto enable_ssl;
1618#endif
1619#ifdef LIBCURL_FEATURE_SSL
1620 case 'D': /* verify peer certificate & host */
1621 verify_peer_and_host = true;
1622 break;
1623#endif
1624 case 'S': /* use SSL */
1625#ifdef LIBCURL_FEATURE_SSL
1626 enable_ssl:
1627 use_ssl = true;
1628 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default.
1629 * Only set if it's non-zero. This helps when we include multiple
1630 * parameters, like -S and -C combinations */
1631 ssl_version = CURL_SSLVERSION_DEFAULT;
1632 if (c=='S' && optarg != NULL) {
1633 char *plus_ptr = strchr(optarg, '+');
1634 if (plus_ptr) {
1635 got_plus = 1;
1636 *plus_ptr = '\0';
1637 }
1638
1639 if (optarg[0] == '2')
1640 ssl_version = CURL_SSLVERSION_SSLv2;
1641 else if (optarg[0] == '3')
1642 ssl_version = CURL_SSLVERSION_SSLv3;
1643 else if (!strcmp (optarg, "1") || !strcmp (optarg, "1.0"))
1644#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1645 ssl_version = CURL_SSLVERSION_TLSv1_0;
1646#else
1647 ssl_version = CURL_SSLVERSION_DEFAULT;
1648#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1649 else if (!strcmp (optarg, "1.1"))
1650#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1651 ssl_version = CURL_SSLVERSION_TLSv1_1;
1652#else
1653 ssl_version = CURL_SSLVERSION_DEFAULT;
1654#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1655 else if (!strcmp (optarg, "1.2"))
1656#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1657 ssl_version = CURL_SSLVERSION_TLSv1_2;
1658#else
1659 ssl_version = CURL_SSLVERSION_DEFAULT;
1660#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1661 else if (!strcmp (optarg, "1.3"))
1662#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0)
1663 ssl_version = CURL_SSLVERSION_TLSv1_3;
1664#else
1665 ssl_version = CURL_SSLVERSION_DEFAULT;
1666#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */
1667 else
1668 usage4 (_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2, 1.3 (with optional '+' suffix)"));
1669 }
1670#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0)
1671 if (got_plus) {
1672 switch (ssl_version) {
1673 case CURL_SSLVERSION_TLSv1_3:
1674 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1675 break;
1676 case CURL_SSLVERSION_TLSv1_2:
1677 case CURL_SSLVERSION_TLSv1_1:
1678 case CURL_SSLVERSION_TLSv1_0:
1679 ssl_version |= CURL_SSLVERSION_MAX_DEFAULT;
1680 break;
1681 }
1682 } else {
1683 switch (ssl_version) {
1684 case CURL_SSLVERSION_TLSv1_3:
1685 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1686 break;
1687 case CURL_SSLVERSION_TLSv1_2:
1688 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2;
1689 break;
1690 case CURL_SSLVERSION_TLSv1_1:
1691 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1;
1692 break;
1693 case CURL_SSLVERSION_TLSv1_0:
1694 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0;
1695 break;
1696 }
1697 }
1698#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */
1699 if (verbose >= 2)
1700 printf(_("* Set SSL/TLS version to %d\n"), ssl_version);
1701 if (!specify_port)
1702 server_port = HTTPS_PORT;
1703 break;
1704#else /* LIBCURL_FEATURE_SSL */
1705 /* -C -J and -K fall through to here without SSL */
1706 usage4 (_("Invalid option - SSL is not available"));
1707 break;
1708 case SNI_OPTION: /* --sni is parsed, but ignored, the default is true with libcurl */
1709 use_sni = true;
1710 break;
1711#endif /* LIBCURL_FEATURE_SSL */
1712 case MAX_REDIRS_OPTION:
1713 if (!is_intnonneg (optarg))
1714 usage2 (_("Invalid max_redirs count"), optarg);
1715 else {
1716 max_depth = atoi (optarg);
1717 }
1718 break;
1719 case 'f': /* onredirect */
1720 if (!strcmp (optarg, "ok"))
1721 onredirect = STATE_OK;
1722 else if (!strcmp (optarg, "warning"))
1723 onredirect = STATE_WARNING;
1724 else if (!strcmp (optarg, "critical"))
1725 onredirect = STATE_CRITICAL;
1726 else if (!strcmp (optarg, "unknown"))
1727 onredirect = STATE_UNKNOWN;
1728 else if (!strcmp (optarg, "follow"))
1729 onredirect = STATE_DEPENDENT;
1730 else if (!strcmp (optarg, "stickyport"))
1731 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST|STICKY_PORT;
1732 else if (!strcmp (optarg, "sticky"))
1733 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST;
1734 else if (!strcmp (optarg, "follow"))
1735 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_NONE;
1736 else if (!strcmp (optarg, "curl"))
1737 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_LIBCURL;
1738 else usage2 (_("Invalid onredirect option"), optarg);
1739 if (verbose >= 2)
1740 printf(_("* Following redirects set to %s\n"), state_text(onredirect));
1741 break;
1742 case 'd': /* string or substring */
1743 strncpy (header_expect, optarg, MAX_INPUT_BUFFER - 1);
1744 header_expect[MAX_INPUT_BUFFER - 1] = 0;
1745 break;
1746 case 's': /* string or substring */
1747 strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
1748 string_expect[MAX_INPUT_BUFFER - 1] = 0;
1749 break;
1750 case 'e': /* string or substring */
1751 strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
1752 server_expect[MAX_INPUT_BUFFER - 1] = 0;
1753 server_expect_yn = 1;
1754 break;
1755 case 'T': /* Content-type */
1756 http_content_type = strdup (optarg);
1757 break;
1758 case 'l': /* linespan */
1759 cflags &= ~REG_NEWLINE;
1760 break;
1761 case 'R': /* regex */
1762 cflags |= REG_ICASE;
1763 // fall through
1764 case 'r': /* regex */
1765 strncpy (regexp, optarg, MAX_RE_SIZE - 1);
1766 regexp[MAX_RE_SIZE - 1] = 0;
1767 errcode = regcomp (&preg, regexp, cflags);
1768 if (errcode != 0) {
1769 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1770 printf (_("Could Not Compile Regular Expression: %s"), errbuf);
1771 return false;
1772 }
1773 break;
1774 case INVERT_REGEX:
1775 invert_regex = true;
1776 break;
1777 case STATE_REGEX:
1778 if (!strcmp (optarg, "critical"))
1779 state_regex = STATE_CRITICAL;
1780 else if (!strcmp (optarg, "warning"))
1781 state_regex = STATE_WARNING;
1782 else usage2 (_("Invalid state-regex option"), optarg);
1783 break;
1784 case '4':
1785 address_family = AF_INET;
1786 break;
1787 case '6':
1788#if defined (USE_IPV6) && defined (LIBCURL_FEATURE_IPV6)
1789 address_family = AF_INET6;
1790#else
1791 usage4 (_("IPv6 support not available"));
1792#endif
1793 break;
1794 case 'm': /* min_page_length */
1795 {
1796 char *tmp;
1797 if (strchr(optarg, ':') != (char *)NULL) {
1798 /* range, so get two values, min:max */
1799 tmp = strtok(optarg, ":");
1800 if (tmp == NULL) {
1801 printf("Bad format: try \"-m min:max\"\n");
1802 exit (STATE_WARNING);
1803 } else
1804 min_page_len = atoi(tmp);
1805
1806 tmp = strtok(NULL, ":");
1807 if (tmp == NULL) {
1808 printf("Bad format: try \"-m min:max\"\n");
1809 exit (STATE_WARNING);
1810 } else
1811 max_page_len = atoi(tmp);
1812 } else
1813 min_page_len = atoi (optarg);
1814 break;
1815 }
1816 case 'N': /* no-body */
1817 no_body = true;
1818 break;
1819 case 'M': /* max-age */
1820 {
1821 int L = strlen(optarg);
1822 if (L && optarg[L-1] == 'm')
1823 maximum_age = atoi (optarg) * 60;
1824 else if (L && optarg[L-1] == 'h')
1825 maximum_age = atoi (optarg) * 60 * 60;
1826 else if (L && optarg[L-1] == 'd')
1827 maximum_age = atoi (optarg) * 60 * 60 * 24;
1828 else if (L && (optarg[L-1] == 's' ||
1829 isdigit (optarg[L-1])))
1830 maximum_age = atoi (optarg);
1831 else {
1832 fprintf (stderr, "unparsable max-age: %s\n", optarg);
1833 exit (STATE_WARNING);
1834 }
1835 if (verbose >= 2)
1836 printf ("* Maximal age of document set to %d seconds\n", maximum_age);
1837 }
1838 break;
1839 case 'E': /* show extended perfdata */
1840 show_extended_perfdata = true;
1841 break;
1842 case 'B': /* print body content after status line */
1843 show_body = true;
1844 break;
1845 case HTTP_VERSION_OPTION:
1846 curl_http_version = CURL_HTTP_VERSION_NONE;
1847 if (strcmp (optarg, "1.0") == 0) {
1848 curl_http_version = CURL_HTTP_VERSION_1_0;
1849 } else if (strcmp (optarg, "1.1") == 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)
1853 curl_http_version = CURL_HTTP_VERSION_2_0;
1854#else
1855 curl_http_version = CURL_HTTP_VERSION_NONE;
1856#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */
1857 } else {
1858 fprintf (stderr, "unknown http-version parameter: %s\n", optarg);
1859 exit (STATE_WARNING);
1860 }
1861 break;
1862 case AUTOMATIC_DECOMPRESSION:
1863 automatic_decompression = true;
1864 break;
1865 case COOKIE_JAR:
1866 cookie_jar_file = optarg;
1867 break;
1868 case HAPROXY_PROTOCOL:
1869 haproxy_protocol = true;
1870 break;
1871 case '?':
1872 /* print short usage statement if args not parsable */
1873 usage5 ();
1874 break;
1875 }
1876 }
1877
1878 c = optind;
1879
1880 if (server_address == NULL && c < argc)
1881 server_address = strdup (argv[c++]);
1882
1883 if (host_name == NULL && c < argc)
1884 host_name = strdup (argv[c++]);
1885
1886 if (server_address == NULL) {
1887 if (host_name == NULL)
1888 usage4 (_("You must specify a server address or host name"));
1889 else
1890 server_address = strdup (host_name);
1891 }
1892
1893 set_thresholds(&thlds, warning_thresholds, critical_thresholds);
1894
1895 if (critical_thresholds && thlds->critical->end>(double)socket_timeout)
1896 socket_timeout = (int)thlds->critical->end + 1;
1897 if (verbose >= 2)
1898 printf ("* Socket timeout set to %ld seconds\n", socket_timeout);
1899
1900 if (http_method == NULL)
1901 http_method = strdup ("GET");
1902
1903 if (client_cert && !client_privkey)
1904 usage4 (_("If you use a client certificate you must also specify a private key file"));
1905
1906 if (virtual_port == 0)
1907 virtual_port = server_port;
1908 else {
1909 if ((use_ssl && server_port == HTTPS_PORT) || (!use_ssl && server_port == HTTP_PORT))
1910 if(!specify_port)
1911 server_port = virtual_port;
1912 }
1913
1914 return true;
1915}
1916
1917char *perfd_time (double elapsed_time)
1918{
1919 return fperfdata ("time", elapsed_time, "s",
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}
1924 382
1925char *perfd_time_connect (double elapsed_time_connect) 383 /* get result code from cURL */
1926{ 384 long httpReturnCode;
1927 return fperfdata ("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout); 385 handle_curl_option_return_code(
1928} 386 curl_easy_getinfo(curl_state.curl, CURLINFO_RESPONSE_CODE, &httpReturnCode),
387 "CURLINFO_RESPONSE_CODE");
388 if (verbose >= 2) {
389 printf("* curl CURLINFO_RESPONSE_CODE is %ld\n", httpReturnCode);
390 }
1929 391
1930char *perfd_time_ssl (double elapsed_time_ssl) 392 /* print status line, header, body if verbose */
1931{ 393 if (verbose >= 2) {
1932 return fperfdata ("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout); 394 printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", curl_state.header_buf->buf,
1933} 395 (workingState.no_body ? " [[ skipped ]]" : curl_state.body_buf->buf));
396 }
1934 397
1935char *perfd_time_headers (double elapsed_time_headers) 398 /* make sure the status line matches the response we are looking for */
1936{ 399 mp_subcheck sc_expect = mp_subcheck_init();
1937 return fperfdata ("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout); 400 sc_expect = mp_set_subcheck_default_state(sc_expect, STATE_OK);
1938} 401 if (!expected_statuscode(curl_state.status_line->first_line, config.server_expect.string)) {
402 if (workingState.serverPort == HTTP_PORT) {
403 xasprintf(&sc_expect.output, _("Invalid HTTP response received from host: %s\n"),
404 curl_state.status_line->first_line);
405 } else {
406 xasprintf(&sc_expect.output,
407 _("Invalid HTTP response received from host on port %d: %s\n"),
408 workingState.serverPort, curl_state.status_line->first_line);
409 }
410 sc_expect = mp_set_subcheck_default_state(sc_expect, STATE_CRITICAL);
411 } else {
412 xasprintf(&sc_expect.output, _("Status line output matched \"%s\""),
413 config.server_expect.string);
414 }
415 mp_add_subcheck_to_subcheck(&sc_result, sc_expect);
416
417 if (!config.server_expect.is_present) {
418 /* illegal return codes result in a critical state */
419 mp_subcheck sc_return_code = mp_subcheck_init();
420 sc_return_code = mp_set_subcheck_default_state(sc_return_code, STATE_OK);
421 xasprintf(&sc_return_code.output, "HTTP return code: %d",
422 curl_state.status_line->http_code);
423
424 if (httpReturnCode >= 600 || httpReturnCode < 100) {
425 sc_return_code = mp_set_subcheck_state(sc_return_code, STATE_CRITICAL);
426 xasprintf(&sc_return_code.output, _("Invalid Status (%d, %.40s)"),
427 curl_state.status_line->http_code, curl_state.status_line->msg);
428 mp_add_subcheck_to_subcheck(&sc_result, sc_return_code);
429 return sc_result;
430 }
1939 431
1940char *perfd_time_firstbyte (double elapsed_time_firstbyte) 432 // server errors result in a critical state
1941{ 433 if (httpReturnCode >= 500) {
1942 return fperfdata ("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout); 434 sc_return_code = mp_set_subcheck_state(sc_return_code, STATE_CRITICAL);
1943} 435 /* client errors result in a warning state */
436 } else if (httpReturnCode >= 400) {
437 sc_return_code = mp_set_subcheck_state(sc_return_code, STATE_WARNING);
438 /* check redirected page if specified */
439 } else if (httpReturnCode >= 300) {
440 if (config.on_redirect_dependent) {
441 if (config.followmethod == FOLLOW_LIBCURL) {
442 httpReturnCode = curl_state.status_line->http_code;
443 handle_curl_option_return_code(
444 curl_easy_getinfo(curl_state.curl, CURLINFO_REDIRECT_COUNT, &redir_depth),
445 "CURLINFO_REDIRECT_COUNT");
446
447 if (verbose >= 2) {
448 printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth);
449 }
450
451 mp_subcheck sc_redir_depth = mp_subcheck_init();
452 if (redir_depth > config.max_depth) {
453 xasprintf(&sc_redir_depth.output,
454 "maximum redirection depth %d exceeded in libcurl",
455 config.max_depth);
456 sc_redir_depth = mp_set_subcheck_state(sc_redir_depth, STATE_CRITICAL);
457 mp_add_subcheck_to_subcheck(&sc_result, sc_redir_depth);
458 return sc_result;
459 }
460 xasprintf(&sc_redir_depth.output, "redirection depth %d (of a maximum %d)",
461 redir_depth, config.max_depth);
462 mp_add_subcheck_to_subcheck(&sc_result, sc_redir_depth);
463
464 } else {
465 /* old check_http style redirection, if we come
466 * back here, we are in the same status as with
467 * the libcurl method
468 */
469 redir_wrapper redir_result =
470 redir(curl_state.header_buf, config, redir_depth, workingState);
471 cleanup(curl_state);
472 mp_subcheck sc_redir =
473 check_http(config, redir_result.working_state, redir_result.redir_depth);
474 mp_add_subcheck_to_subcheck(&sc_result, sc_redir);
475
476 return sc_result;
477 }
478 } else {
479 /* this is a specific code in the command line to
480 * be returned when a redirection is encountered
481 */
482 sc_return_code =
483 mp_set_subcheck_state(sc_return_code, config.on_redirect_result_state);
484 }
485 } else {
486 sc_return_code = mp_set_subcheck_state(sc_return_code, STATE_OK);
487 }
1944 488
1945char *perfd_time_transfer (double elapsed_time_transfer) 489 mp_add_subcheck_to_subcheck(&sc_result, sc_return_code);
1946{ 490 }
1947 return fperfdata ("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1948}
1949 491
1950char *perfd_size (int page_len) 492 /* check status codes, set exit status accordingly */
1951{ 493 if (curl_state.status_line->http_code != httpReturnCode) {
1952 return perfdata ("size", page_len, "B", 494 mp_subcheck sc_http_return_code_sanity = mp_subcheck_init();
1953 (min_page_len>0?true:false), min_page_len, 495 sc_http_return_code_sanity =
1954 (min_page_len>0?true:false), 0, 496 mp_set_subcheck_state(sc_http_return_code_sanity, STATE_CRITICAL);
1955 true, 0, false, 0); 497 xasprintf(&sc_http_return_code_sanity.output,
1956} 498 _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"),
499 string_statuscode(curl_state.status_line->http_major,
500 curl_state.status_line->http_minor),
501 curl_state.status_line->http_code, curl_state.status_line->msg, httpReturnCode);
502
503 mp_add_subcheck_to_subcheck(&sc_result, sc_http_return_code_sanity);
504 return sc_result;
505 }
1957 506
1958void 507 if (config.maximum_age >= 0) {
1959print_help (void) 508 mp_subcheck sc_max_age = check_document_dates(curl_state.header_buf, config.maximum_age);
1960{ 509 mp_add_subcheck_to_subcheck(&sc_result, sc_max_age);
1961 print_revision (progname, NP_VERSION); 510 }
1962 511
1963 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 512 /* Page and Header content checks go here */
1964 printf (COPYRIGHT, copyright, email); 513 if (strlen(config.header_expect)) {
514 mp_subcheck sc_header_expect = mp_subcheck_init();
515 sc_header_expect = mp_set_subcheck_default_state(sc_header_expect, STATE_OK);
516 xasprintf(&sc_header_expect.output, "Expect %s in header", config.header_expect);
1965 517
1966 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test")); 518 if (!strstr(curl_state.header_buf->buf, config.header_expect)) {
1967 printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for")); 519 char output_header_search[30] = "";
1968 printf ("%s\n", _("strings and regular expressions, check connection times, and report on")); 520 strncpy(&output_header_search[0], config.header_expect, sizeof(output_header_search));
1969 printf ("%s\n", _("certificate expiration times."));
1970 printf ("\n");
1971 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."));
1973 521
1974 printf ("\n\n"); 522 if (output_header_search[sizeof(output_header_search) - 1] != '\0') {
523 bcopy("...", &output_header_search[sizeof(output_header_search) - 4], 4);
524 }
1975 525
1976 print_usage (); 526 xasprintf(&sc_header_expect.output, _("header '%s' not found on '%s://%s:%d%s', "),
527 output_header_search, workingState.use_ssl ? "https" : "http",
528 workingState.host_name ? workingState.host_name : workingState.server_address,
529 workingState.serverPort, workingState.server_url);
1977 530
1978 printf (_("NOTE: One or both of -H and -I must be specified")); 531 sc_header_expect = mp_set_subcheck_state(sc_header_expect, STATE_CRITICAL);
532 }
1979 533
1980 printf ("\n"); 534 mp_add_subcheck_to_subcheck(&sc_result, sc_header_expect);
535 }
1981 536
1982 printf (UT_HELP_VRSN); 537 if (strlen(config.string_expect)) {
1983 printf (UT_EXTRA_OPTS); 538 mp_subcheck sc_string_expect = mp_subcheck_init();
539 sc_string_expect = mp_set_subcheck_default_state(sc_string_expect, STATE_OK);
540 xasprintf(&sc_string_expect.output, "Expect string \"%s\" in body", config.string_expect);
1984 541
1985 printf (" %s\n", "-H, --hostname=ADDRESS"); 542 if (!strstr(curl_state.body_buf->buf, config.string_expect)) {
1986 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)")); 543 char output_string_search[30] = "";
1987 printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)")); 544 strncpy(&output_string_search[0], config.string_expect, sizeof(output_string_search));
1988 printf (" %s\n", "-I, --IP-address=ADDRESS");
1989 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1990 printf (" %s\n", "-p, --port=INTEGER");
1991 printf (" %s", _("Port number (default: "));
1992 printf ("%d)\n", HTTP_PORT);
1993 545
1994 printf (UT_IPv46); 546 if (output_string_search[sizeof(output_string_search) - 1] != '\0') {
547 bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 4);
548 }
1995 549
1996#ifdef LIBCURL_FEATURE_SSL 550 xasprintf(&sc_string_expect.output, _("string '%s' not found on '%s://%s:%d%s', "),
1997 printf (" %s\n", "-S, --ssl=VERSION[+]"); 551 output_string_search, workingState.use_ssl ? "https" : "http",
1998 printf (" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents")); 552 workingState.host_name ? workingState.host_name : workingState.server_address,
1999 printf (" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,")); 553 workingState.serverPort, workingState.server_url);
2000 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"));
2002 printf (" %s\n", "--sni");
2003 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
2004#if LIBCURL_VERSION_NUM >= 0x071801
2005 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"));
2007#else
2008 printf (" %s\n", _("Note: SNI is not supported in libcurl before 7.18.1"));
2009#endif
2010 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."));
2012 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"));
2014 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"));
2016 printf (" %s\n", _(" --continue-after-certificate to override this behavior)"));
2017 printf (" %s\n", "--continue-after-certificate");
2018 printf (" %s\n", _("Allows the HTTP check to continue after performing the certificate check."));
2019 printf (" %s\n", _("Does nothing unless -C is used."));
2020 printf (" %s\n", "-J, --client-cert=FILE");
2021 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"));
2023 printf (" %s\n", "-K, --private-key=FILE");
2024 printf (" %s\n", _("Name of file containing the private key (PEM format)"));
2025 printf (" %s\n", _("matching the client certificate"));
2026 printf (" %s\n", "--ca-cert=FILE");
2027 printf (" %s\n", _("CA certificate file to verify peer against"));
2028 printf (" %s\n", "-D, --verify-cert");
2029 printf (" %s\n", _("Verify the peer's SSL certificate and hostname"));
2030#endif
2031 554
2032 printf (" %s\n", "-e, --expect=STRING"); 555 sc_string_expect = mp_set_subcheck_state(sc_string_expect, STATE_CRITICAL);
2033 printf (" %s\n", _("Comma-delimited list of strings, at least one of them is expected in")); 556 }
2034 printf (" %s", _("the first (status) line of the server response (default: "));
2035 printf ("%s)\n", HTTP_EXPECT);
2036 printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
2037 printf (" %s\n", "-d, --header-string=STRING");
2038 printf (" %s\n", _("String to expect in the response headers"));
2039 printf (" %s\n", "-s, --string=STRING");
2040 printf (" %s\n", _("String to expect in the content"));
2041 printf (" %s\n", "-u, --url=PATH");
2042 printf (" %s\n", _("URL to GET or POST (default: /)"));
2043 printf (" %s\n", "-P, --post=STRING");
2044 printf (" %s\n", _("URL decoded http POST data"));
2045 printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT)");
2046 printf (" %s\n", _("Set HTTP method."));
2047 printf (" %s\n", "-N, --no-body");
2048 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.)"));
2050 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"));
2052 printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
2053 printf (" %s\n", "-T, --content-type=STRING");
2054 printf (" %s\n", _("specify Content-Type header media type when POSTing\n"));
2055 printf (" %s\n", "-l, --linespan");
2056 printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
2057 printf (" %s\n", "-r, --regex, --ereg=STRING");
2058 printf (" %s\n", _("Search page for regex STRING"));
2059 printf (" %s\n", "-R, --eregi=STRING");
2060 printf (" %s\n", _("Search page for case-insensitive regex STRING"));
2061 printf (" %s\n", "--invert-regex");
2062 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)"));
2064 printf (" %s\n", "--regex-state=STATE");
2065 printf (" %s\n", _("Return STATE if regex is found, OK if not\n"));
2066 printf (" %s\n", "-a, --authorization=AUTH_PAIR");
2067 printf (" %s\n", _("Username:password on sites with basic authentication"));
2068 printf (" %s\n", "-b, --proxy-authorization=AUTH_PAIR");
2069 printf (" %s\n", _("Username:password on proxy-servers with basic authentication"));
2070 printf (" %s\n", "-A, --useragent=STRING");
2071 printf (" %s\n", _("String to be sent in http header as \"User Agent\""));
2072 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"));
2074 printf (" %s\n", "-E, --extended-perfdata");
2075 printf (" %s\n", _("Print additional performance data"));
2076 printf (" %s\n", "-B, --show-body");
2077 printf (" %s\n", _("Print body content below status line"));
2078 printf (" %s\n", "-L, --link");
2079 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
2080 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"));
2082 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."));
2084 printf (" %s\n", _("curl uses CURL_FOLLOWLOCATION built into libcurl."));
2085 printf (" %s\n", "--max-redirs=INTEGER");
2086 printf (" %s", _("Maximal number of redirects (default: "));
2087 printf ("%d)\n", DEFAULT_MAX_REDIRS);
2088 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
2089 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
2090 printf ("\n");
2091 printf (" %s\n", "--http-version=VERSION");
2092 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)"));
2094 printf (" %s\n", "--enable-automatic-decompression");
2095 printf (" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING)."));
2096 printf(" %s\n", "--haproxy-protocol");
2097 printf(" %s\n", _("Send HAProxy proxy protocol v1 header (CURLOPT_HAPROXYPROTOCOL)."));
2098 printf (" %s\n", "--cookie-jar=FILE");
2099 printf (" %s\n", _("Store cookies in the cookie jar and send them out when requested."));
2100 printf ("\n");
2101
2102 printf (UT_WARN_CRIT);
2103
2104 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
2105
2106 printf (UT_VERBOSE);
2107
2108 printf ("\n");
2109 printf ("%s\n", _("Notes:"));
2110 printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
2111 printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
2112 printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response"));
2113 printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
2114 printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
2115 printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
2116 557
2117#ifdef LIBCURL_FEATURE_SSL 558 mp_add_subcheck_to_subcheck(&sc_result, sc_string_expect);
2118 printf ("\n"); 559 }
2119 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 "));
2121 printf (" %s\n", _("certificate is still valid for the specified number of days."));
2122 printf ("\n");
2123 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"));
2125 printf (" %s\n", _("has a valid chain of trust to one of the locally installed CAs."));
2126 printf ("\n");
2127 printf ("%s\n", _("Examples:"));
2128 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,"));
2130 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,"));
2132 printf (" %s\n", _("a STATE_CRITICAL will be returned."));
2133 printf ("\n");
2134 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,"));
2136 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"));
2138 printf (" %s\n\n", _("the certificate is expired."));
2139 printf ("\n");
2140 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,"));
2142 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."));
2144 printf (" %s\n", _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days"));
2145#endif
2146 560
2147 printf ("\n %s\n", "CHECK WEBSERVER CONTENT VIA PROXY:"); 561 if (strlen(config.regexp)) {
2148 printf (" %s\n", _("It is recommended to use an environment proxy like:")); 562 mp_subcheck sc_body_regex = mp_subcheck_init();
2149 printf (" %s\n", _("http_proxy=http://192.168.100.35:3128 ./check_curl -H www.monitoring-plugins.org")); 563 xasprintf(&sc_body_regex.output, "Regex \"%s\" in body matched", config.regexp);
2150 printf (" %s\n", _("legacy proxy requests in check_http style still work:")); 564 regmatch_t pmatch[REGS];
2151 printf (" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u http://www.monitoring-plugins.org/ -H www.monitoring-plugins.org"));
2152 565
2153#ifdef LIBCURL_FEATURE_SSL 566 int errcode = regexec(&config.compiled_regex, curl_state.body_buf->buf, REGS, pmatch, 0);
2154 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:"));
2156 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:"));
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 "));
2159 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"));
2161 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."));
2163 567
2164#endif 568 if (errcode == 0) {
569 // got a match
570 if (config.invert_regex) {
571 sc_body_regex = mp_set_subcheck_state(sc_body_regex, config.state_regex);
572 } else {
573 sc_body_regex = mp_set_subcheck_state(sc_body_regex, STATE_OK);
574 }
575 } else if (errcode == REG_NOMATCH) {
576 // got no match
577 xasprintf(&sc_body_regex.output, "%s not", sc_body_regex.output);
2165 578
2166 printf (UT_SUPPORT); 579 if (config.invert_regex) {
580 sc_body_regex = mp_set_subcheck_state(sc_body_regex, STATE_OK);
581 } else {
582 sc_body_regex = mp_set_subcheck_state(sc_body_regex, config.state_regex);
583 }
584 } else {
585 // error in regexec
586 char error_buffer[DEFAULT_BUFFER_SIZE];
587 regerror(errcode, &config.compiled_regex, &error_buffer[0], DEFAULT_BUFFER_SIZE);
588 xasprintf(&sc_body_regex.output, "regexec error: %s", error_buffer);
589 sc_body_regex = mp_set_subcheck_state(sc_body_regex, STATE_UNKNOWN);
590 }
2167 591
2168} 592 mp_add_subcheck_to_subcheck(&sc_result, sc_body_regex);
593 }
2169 594
595 // size a.k.a. page length
596 mp_perfdata pd_page_length = perfdata_init();
597 mp_perfdata_value pd_val_page_length = mp_create_pd_value(page_len);
598 pd_page_length.value = pd_val_page_length;
599 pd_page_length.label = "size";
600 pd_page_length.uom = "B";
601 pd_page_length.min = mp_create_pd_value(0);
602 pd_page_length.warn = config.page_length_limits;
603 pd_page_length.warn_present = true;
604
605 /* make sure the page is of an appropriate size */
606 if (config.page_length_limits_is_set) {
607 mp_thresholds page_length_threshold = mp_thresholds_init();
608 page_length_threshold.warning = config.page_length_limits;
609 page_length_threshold.warning_is_set = true;
610
611 pd_page_length = mp_pd_set_thresholds(pd_page_length, page_length_threshold);
612
613 mp_subcheck sc_page_length = mp_subcheck_init();
614
615 mp_add_perfdata_to_subcheck(&sc_page_length, pd_page_length);
616
617 mp_state_enum tmp_state = mp_get_pd_status(pd_page_length);
618 sc_page_length = mp_set_subcheck_state(sc_page_length, tmp_state);
619
620 switch (tmp_state) {
621 case STATE_CRITICAL:
622 case STATE_WARNING:
623 xasprintf(&sc_page_length.output, _("page size %zu violates threshold"), page_len);
624 break;
625 case STATE_OK:
626 xasprintf(&sc_page_length.output, _("page size %zu is OK"), page_len);
627 break;
628 default:
629 assert(false);
630 }
2170 631
632 mp_add_subcheck_to_subcheck(&sc_result, sc_page_length);
633 }
2171 634
2172void 635 return sc_result;
2173print_usage (void)
2174{
2175 printf ("%s\n", _("Usage:"));
2176 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
2177 printf (" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate file>] [-D]\n");
2178 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n");
2179 printf (" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport|curl>]\n");
2180 printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n");
2181 printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
2182 printf (" [-A string] [-k string] [-S <version>] [--sni] [--haproxy-protocol]\n");
2183 printf (" [-T <content-type>] [-j method]\n");
2184 printf (" [--http-version=<version>] [--enable-automatic-decompression]\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
2190 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."));
2192#endif
2193} 636}
2194 637
2195void 638int uri_strcmp(const UriTextRangeA range, const char *stringToCompare) {
2196print_curl_version (void) 639 if (!range.first) {
2197{ 640 return -1;
2198 printf( "%s\n", curl_version()); 641 }
642 if ((size_t)(range.afterLast - range.first) < strlen(stringToCompare)) {
643 return -1;
644 }
645 return strncmp(stringToCompare, range.first,
646 min((size_t)(range.afterLast - range.first), strlen(stringToCompare)));
2199} 647}
2200 648
2201int 649char *uri_string(const UriTextRangeA range, char *buf, size_t buflen) {
2202curlhelp_initwritebuffer (curlhelp_write_curlbuf *buf) 650 if (!range.first) {
2203{ 651 return "(null)";
2204 buf->bufsize = DEFAULT_BUFFER_SIZE; 652 }
2205 buf->buflen = 0; 653 strncpy(buf, range.first, max(buflen - 1, (size_t)(range.afterLast - range.first)));
2206 buf->buf = (char *)malloc ((size_t)buf->bufsize); 654 buf[max(buflen - 1, (size_t)(range.afterLast - range.first))] = '\0';
2207 if (buf->buf == NULL) return -1; 655 buf[range.afterLast - range.first] = '\0';
2208 return 0; 656 return buf;
2209} 657}
2210 658
2211size_t curlhelp_buffer_write_callback (void *buffer, size_t size, size_t nmemb, void *stream) 659redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config config,
2212{ 660 int redir_depth, check_curl_working_state working_state) {
2213 curlhelp_write_curlbuf *buf = (curlhelp_write_curlbuf *)stream; 661 curlhelp_statusline status_line;
662 struct phr_header headers[255];
663 size_t msglen;
664 size_t nof_headers = 255;
665 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major,
666 &status_line.http_minor, &status_line.http_code, &status_line.msg,
667 &msglen, headers, &nof_headers, 0);
2214 668
2215 while (buf->bufsize < buf->buflen + size * nmemb + 1) { 669 if (res == -1) {
2216 buf->bufsize = buf->bufsize * 2; 670 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
2217 buf->buf = (char *)realloc (buf->buf, buf->bufsize); 671 }
2218 if (buf->buf == NULL) {
2219 fprintf(stderr, "malloc failed (%d) %s\n", errno, strerror(errno));
2220 return -1;
2221 }
2222 }
2223 672
2224 memcpy (buf->buf + buf->buflen, buffer, size * nmemb); 673 char *location = get_header_value(headers, nof_headers, "location");
2225 buf->buflen += size * nmemb;
2226 buf->buf[buf->buflen] = '\0';
2227 674
2228 return (int)(size * nmemb); 675 if (verbose >= 2) {
2229} 676 printf(_("* Seen redirect location %s\n"), location);
677 }
2230 678
2231size_t curlhelp_buffer_read_callback(void *buffer, size_t size, size_t nmemb, void *stream) 679 if (++redir_depth > config.max_depth) {
2232{ 680 die(STATE_WARNING, _("HTTP WARNING - maximum redirection depth %d exceeded - %s\n"),
2233 curlhelp_read_curlbuf *buf = (curlhelp_read_curlbuf *)stream; 681 config.max_depth, location);
682 }
2234 683
2235 size_t n = min (nmemb * size, buf->buflen - buf->pos); 684 UriParserStateA state;
685 UriUriA uri;
686 state.uri = &uri;
687 if (uriParseUriA(&state, location) != URI_SUCCESS) {
688 if (state.errorCode == URI_ERROR_SYNTAX) {
689 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not parse redirect location '%s'\n"),
690 location);
691 } else if (state.errorCode == URI_ERROR_MALLOC) {
692 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
693 }
694 }
2236 695
2237 memcpy (buffer, buf->buf + buf->pos, n); 696 char ipstr[INET_ADDR_MAX_SIZE];
2238 buf->pos += n; 697 char buf[DEFAULT_BUFFER_SIZE];
698 if (verbose >= 2) {
699 printf(_("** scheme: %s\n"), uri_string(uri.scheme, buf, DEFAULT_BUFFER_SIZE));
700 printf(_("** host: %s\n"), uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE));
701 printf(_("** port: %s\n"), uri_string(uri.portText, buf, DEFAULT_BUFFER_SIZE));
702 if (uri.hostData.ip4) {
703 inet_ntop(AF_INET, uri.hostData.ip4->data, ipstr, sizeof(ipstr));
704 printf(_("** IPv4: %s\n"), ipstr);
705 }
706 if (uri.hostData.ip6) {
707 inet_ntop(AF_INET, uri.hostData.ip6->data, ipstr, sizeof(ipstr));
708 printf(_("** IPv6: %s\n"), ipstr);
709 }
710 if (uri.pathHead) {
711 printf(_("** path: "));
712 for (UriPathSegmentA *path_segment = uri.pathHead; path_segment;
713 path_segment = path_segment->next) {
714 printf("/%s", uri_string(path_segment->text, buf, DEFAULT_BUFFER_SIZE));
715 }
716 puts("");
717 }
718 if (uri.query.first) {
719 printf(_("** query: %s\n"), uri_string(uri.query, buf, DEFAULT_BUFFER_SIZE));
720 }
721 if (uri.fragment.first) {
722 printf(_("** fragment: %s\n"), uri_string(uri.fragment, buf, DEFAULT_BUFFER_SIZE));
723 }
724 }
2239 725
2240 return (int)n; 726 if (uri.scheme.first) {
2241} 727 working_state.use_ssl = (bool)(!uri_strcmp(uri.scheme, "https"));
728 }
2242 729
2243void 730 /* we do a sloppy test here only, because uriparser would have failed
2244curlhelp_freewritebuffer (curlhelp_write_curlbuf *buf) 731 * above, if the port would be invalid, we just check for MAX_PORT
2245{ 732 */
2246 free (buf->buf); 733 int new_port;
2247 buf->buf = NULL; 734 if (uri.portText.first) {
2248} 735 new_port = atoi(uri_string(uri.portText, buf, DEFAULT_BUFFER_SIZE));
736 } else {
737 new_port = HTTP_PORT;
738 if (working_state.use_ssl) {
739 new_port = HTTPS_PORT;
740 }
741 }
742 if (new_port > MAX_PORT) {
743 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Redirection to port above %d - %s\n"), MAX_PORT,
744 location);
745 }
2249 746
2250int 747 /* by RFC 7231 relative URLs in Location should be taken relative to
2251curlhelp_initreadbuffer (curlhelp_read_curlbuf *buf, const char *data, size_t datalen) 748 * the original URL, so we try to form a new absolute URL here
2252{ 749 */
2253 buf->buflen = datalen; 750 char *new_host;
2254 buf->buf = (char *)malloc ((size_t)buf->buflen); 751 if (!uri.scheme.first && !uri.hostText.first) {
2255 if (buf->buf == NULL) return -1; 752 new_host = strdup(working_state.host_name ? working_state.host_name
2256 memcpy (buf->buf, data, datalen); 753 : working_state.server_address);
2257 buf->pos = 0; 754 new_port = working_state.serverPort;
2258 return 0; 755 if (working_state.use_ssl) {
2259} 756 uri_string(uri.scheme, "https", DEFAULT_BUFFER_SIZE);
757 }
758 } else {
759 new_host = strdup(uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE));
760 }
2260 761
2261void 762 /* compose new path */
2262curlhelp_freereadbuffer (curlhelp_read_curlbuf *buf) 763 /* TODO: handle fragments and query part of URL */
2263{ 764 char *new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE);
2264 free (buf->buf); 765 if (uri.pathHead) {
2265 buf->buf = NULL; 766 for (UriPathSegmentA *pathSegment = uri.pathHead; pathSegment;
2266} 767 pathSegment = pathSegment->next) {
768 strncat(new_url, "/", DEFAULT_BUFFER_SIZE);
769 strncat(new_url, uri_string(pathSegment->text, buf, DEFAULT_BUFFER_SIZE),
770 DEFAULT_BUFFER_SIZE - 1);
771 }
772 }
2267 773
2268/* TODO: where to put this, it's actually part of sstrings2 (logically)? 774 if (working_state.serverPort == new_port &&
2269 */ 775 !strncmp(working_state.server_address, new_host, MAX_IPV4_HOSTLENGTH) &&
2270const char* 776 (working_state.host_name &&
2271strrstr2(const char *haystack, const char *needle) 777 !strncmp(working_state.host_name, new_host, MAX_IPV4_HOSTLENGTH)) &&
2272{ 778 !strcmp(working_state.server_url, new_url)) {
2273 int counter; 779 die(STATE_CRITICAL,
2274 size_t len; 780 _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s\n"),
2275 const char *prev_pos; 781 working_state.use_ssl ? "https" : "http", new_host, new_port, new_url);
2276 const char *pos; 782 }
2277
2278 if (haystack == NULL || needle == NULL)
2279 return NULL;
2280
2281 if (haystack[0] == '\0' || needle[0] == '\0')
2282 return NULL;
2283
2284 counter = 0;
2285 prev_pos = NULL;
2286 pos = haystack;
2287 len = strlen (needle);
2288 for (;;) {
2289 pos = strstr (pos, needle);
2290 if (pos == NULL) {
2291 if (counter == 0)
2292 return NULL;
2293 else
2294 return prev_pos;
2295 }
2296 counter++;
2297 prev_pos = pos;
2298 pos += len;
2299 if (*pos == '\0') return prev_pos;
2300 }
2301}
2302 783
2303int 784 /* set new values for redirected request */
2304curlhelp_parse_statusline (const char *buf, curlhelp_statusline *status_line)
2305{
2306 char *first_line_end;
2307 char *p;
2308 size_t first_line_len;
2309 char *pp;
2310 const char *start;
2311 char *first_line_buf;
2312
2313 /* find last start of a new header */
2314 start = strrstr2 (buf, "\r\nHTTP/");
2315 if (start != NULL) {
2316 start += 2;
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 785
2385void 786 if (!(config.followsticky & STICKY_HOST)) {
2386curlhelp_free_statusline (curlhelp_statusline *status_line) 787 free(working_state.server_address);
2387{ 788 working_state.server_address = strndup(new_host, MAX_IPV4_HOSTLENGTH);
2388 free (status_line->first_line); 789 }
2389} 790 if (!(config.followsticky & STICKY_PORT)) {
791 working_state.serverPort = (unsigned short)new_port;
792 }
2390 793
2391void 794 free(working_state.host_name);
2392remove_newlines (char *s) 795 working_state.host_name = strndup(new_host, MAX_IPV4_HOSTLENGTH);
2393{
2394 char *p;
2395 796
2396 for (p = s; *p != '\0'; p++) 797 /* reset virtual port */
2397 if (*p == '\r' || *p == '\n') 798 working_state.virtualPort = working_state.serverPort;
2398 *p = ' ';
2399}
2400 799
2401char * 800 free(new_host);
2402get_header_value (const struct phr_header* headers, const size_t nof_headers, const char* header) 801 free(working_state.server_url);
2403{ 802 working_state.server_url = new_url;
2404 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 ) {
2406 return strndup( headers[i].value, headers[i].value_len );
2407 }
2408 }
2409 return NULL;
2410}
2411 803
2412int 804 uriFreeUriMembersA(&uri);
2413check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFAULT_BUFFER_SIZE])
2414{
2415 char *server_date = NULL;
2416 char *document_date = NULL;
2417 int date_result = STATE_OK;
2418 curlhelp_statusline status_line;
2419 struct phr_header headers[255];
2420 size_t nof_headers = 255;
2421 size_t msglen;
2422
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 805
2427 if (res == -1) { 806 if (verbose) {
2428 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 807 printf(_("Redirection to %s://%s:%d%s\n"), working_state.use_ssl ? "https" : "http",
808 working_state.host_name ? working_state.host_name : working_state.server_address,
809 working_state.serverPort, working_state.server_url);
2429 } 810 }
2430 811
2431 server_date = get_header_value (headers, nof_headers, "date"); 812 /* TODO: the hash component MUST be taken from the original URL and
2432 document_date = get_header_value (headers, nof_headers, "last-modified"); 813 * attached to the URL in Location
814 */
2433 815
2434 if (!server_date || !*server_date) { 816 redir_wrapper result = {
2435 char tmp[DEFAULT_BUFFER_SIZE]; 817 .redir_depth = redir_depth,
818 .working_state = working_state,
819 .error_code = OK,
820 };
821 return result;
822}
2436 823
2437 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sServer date unknown, "), *msg); 824check_curl_config_wrapper process_arguments(int argc, char **argv) {
2438 strcpy(*msg, tmp); 825 enum {
826 INVERT_REGEX = CHAR_MAX + 1,
827 SNI_OPTION,
828 MAX_REDIRS_OPTION,
829 CONTINUE_AFTER_CHECK_CERT,
830 CA_CERT_OPTION,
831 HTTP_VERSION_OPTION,
832 AUTOMATIC_DECOMPRESSION,
833 COOKIE_JAR,
834 HAPROXY_PROTOCOL,
835 STATE_REGEX,
836 OUTPUT_FORMAT
837 };
838
839 static struct option longopts[] = {
840 STD_LONG_OPTS,
841 {"link", no_argument, 0, 'L'},
842 {"nohtml", no_argument, 0, 'n'},
843 {"ssl", optional_argument, 0, 'S'},
844 {"sni", no_argument, 0, SNI_OPTION},
845 {"post", required_argument, 0, 'P'},
846 {"method", required_argument, 0, 'j'},
847 {"IP-address", required_argument, 0, 'I'},
848 {"url", required_argument, 0, 'u'},
849 {"port", required_argument, 0, 'p'},
850 {"authorization", required_argument, 0, 'a'},
851 {"proxy-authorization", required_argument, 0, 'b'},
852 {"header-string", required_argument, 0, 'd'},
853 {"string", required_argument, 0, 's'},
854 {"expect", required_argument, 0, 'e'},
855 {"regex", required_argument, 0, 'r'},
856 {"ereg", required_argument, 0, 'r'},
857 {"eregi", required_argument, 0, 'R'},
858 {"linespan", no_argument, 0, 'l'},
859 {"onredirect", required_argument, 0, 'f'},
860 {"certificate", required_argument, 0, 'C'},
861 {"client-cert", required_argument, 0, 'J'},
862 {"private-key", required_argument, 0, 'K'},
863 {"ca-cert", required_argument, 0, CA_CERT_OPTION},
864 {"verify-cert", no_argument, 0, 'D'},
865 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT},
866 {"useragent", required_argument, 0, 'A'},
867 {"header", required_argument, 0, 'k'},
868 {"no-body", no_argument, 0, 'N'},
869 {"max-age", required_argument, 0, 'M'},
870 {"content-type", required_argument, 0, 'T'},
871 {"pagesize", required_argument, 0, 'm'},
872 {"invert-regex", no_argument, NULL, INVERT_REGEX},
873 {"state-regex", required_argument, 0, STATE_REGEX},
874 {"use-ipv4", no_argument, 0, '4'},
875 {"use-ipv6", no_argument, 0, '6'},
876 {"extended-perfdata", no_argument, 0, 'E'},
877 {"show-body", no_argument, 0, 'B'},
878 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION},
879 {"http-version", required_argument, 0, HTTP_VERSION_OPTION},
880 {"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION},
881 {"cookie-jar", required_argument, 0, COOKIE_JAR},
882 {"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL},
883 {"output-format", required_argument, 0, OUTPUT_FORMAT},
884 {0, 0, 0, 0}};
885
886 check_curl_config_wrapper result = {
887 .errorcode = OK,
888 .config = check_curl_config_init(),
889 };
890
891 if (argc < 2) {
892 result.errorcode = ERROR;
893 return result;
894 }
2439 895
2440 date_result = max_state_alt(STATE_UNKNOWN, date_result); 896 /* support check_http compatible arguments */
897 for (int index = 1; index < argc; index++) {
898 if (strcmp("-to", argv[index]) == 0) {
899 strcpy(argv[index], "-t");
900 }
901 if (strcmp("-hn", argv[index]) == 0) {
902 strcpy(argv[index], "-H");
903 }
904 if (strcmp("-wt", argv[index]) == 0) {
905 strcpy(argv[index], "-w");
906 }
907 if (strcmp("-ct", argv[index]) == 0) {
908 strcpy(argv[index], "-c");
909 }
910 if (strcmp("-nohtml", argv[index]) == 0) {
911 strcpy(argv[index], "-n");
912 }
913 }
2441 914
2442 } else if (!document_date || !*document_date) { 915 int option = 0;
2443 char tmp[DEFAULT_BUFFER_SIZE]; 916 int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
917 bool specify_port = false;
918 bool enable_tls = false;
919 char *tls_option_optarg = NULL;
920
921 while (true) {
922 int option_index = getopt_long(
923 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",
924 longopts, &option);
925 if (option_index == -1 || option_index == EOF || option_index == 1) {
926 break;
927 }
2444 928
2445 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument modification date unknown, "), *msg); 929 switch (option_index) {
2446 strcpy(*msg, tmp); 930 case 'h':
931 print_help();
932 exit(STATE_UNKNOWN);
933 break;
934 case 'V':
935 print_revision(progname, NP_VERSION);
936 print_curl_version();
937 exit(STATE_UNKNOWN);
938 break;
939 case 'v':
940 verbose++;
941 break;
942 case 't': /* timeout period */
943 if (!is_intnonneg(optarg)) {
944 usage2(_("Timeout interval must be a positive integer"), optarg);
945 } else {
946 result.config.curl_config.socket_timeout = (int)strtol(optarg, NULL, 10);
947 }
948 break;
949 case 'c': /* critical time threshold */
950 {
951 mp_range_parsed critical_range = mp_parse_range_string(optarg);
952 if (critical_range.error != MP_PARSING_SUCCES) {
953 die(STATE_UNKNOWN, "failed to parse critical threshold: %s", optarg);
954 }
955 result.config.thlds = mp_thresholds_set_crit(result.config.thlds, critical_range.range);
956 } break;
957 case 'w': /* warning time threshold */
958 {
959 mp_range_parsed warning_range = mp_parse_range_string(optarg);
960
961 if (warning_range.error != MP_PARSING_SUCCES) {
962 die(STATE_UNKNOWN, "failed to parse warning threshold: %s", optarg);
963 }
964 result.config.thlds = mp_thresholds_set_warn(result.config.thlds, warning_range.range);
965 } break;
966 case 'H': /* virtual host */
967 result.config.initial_config.host_name = strdup(optarg);
968 char *tmp_string;
969 size_t host_name_length;
970 if (result.config.initial_config.host_name[0] == '[') {
971 if ((tmp_string = strstr(result.config.initial_config.host_name, "]:")) !=
972 NULL) { /* [IPv6]:port */
973 result.config.initial_config.virtualPort = atoi(tmp_string + 2);
974 /* cut off the port */
975 host_name_length =
976 strlen(result.config.initial_config.host_name) - strlen(tmp_string) - 1;
977 free(result.config.initial_config.host_name);
978 result.config.initial_config.host_name = strndup(optarg, host_name_length);
979 }
980 } else if ((tmp_string = strchr(result.config.initial_config.host_name, ':')) != NULL &&
981 strchr(++tmp_string, ':') == NULL) { /* IPv4:port or host:port */
982 result.config.initial_config.virtualPort = atoi(tmp_string);
983 /* cut off the port */
984 host_name_length =
985 strlen(result.config.initial_config.host_name) - strlen(tmp_string) - 1;
986 free(result.config.initial_config.host_name);
987 result.config.initial_config.host_name = strndup(optarg, host_name_length);
988 }
989 break;
990 case 'I': /* internet address */
991 result.config.initial_config.server_address = strdup(optarg);
992 break;
993 case 'u': /* URL path */
994 result.config.initial_config.server_url = strdup(optarg);
995 break;
996 case 'p': /* Server port */
997 if (!is_intnonneg(optarg)) {
998 usage2(_("Invalid port number, expecting a non-negative number"), optarg);
999 } else {
1000 if (strtol(optarg, NULL, 10) > MAX_PORT) {
1001 usage2(_("Invalid port number, supplied port number is too big"), optarg);
1002 }
1003 result.config.initial_config.serverPort = (unsigned short)strtol(optarg, NULL, 10);
1004 specify_port = true;
1005 }
1006 break;
1007 case 'a': /* authorization info */
1008 strncpy(result.config.curl_config.user_auth, optarg, MAX_INPUT_BUFFER - 1);
1009 result.config.curl_config.user_auth[MAX_INPUT_BUFFER - 1] = 0;
1010 break;
1011 case 'b': /* proxy-authorization info */
1012 strncpy(result.config.curl_config.proxy_auth, optarg, MAX_INPUT_BUFFER - 1);
1013 result.config.curl_config.proxy_auth[MAX_INPUT_BUFFER - 1] = 0;
1014 break;
1015 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
1016 if (!result.config.initial_config.http_post_data) {
1017 result.config.initial_config.http_post_data = strdup(optarg);
1018 }
1019 if (!result.config.initial_config.http_method) {
1020 result.config.initial_config.http_method = strdup("POST");
1021 }
1022 break;
1023 case 'j': /* Set HTTP method */
1024 if (result.config.initial_config.http_method) {
1025 free(result.config.initial_config.http_method);
1026 }
1027 result.config.initial_config.http_method = strdup(optarg);
1028 break;
1029 case 'A': /* useragent */
1030 strncpy(result.config.curl_config.user_agent, optarg, DEFAULT_BUFFER_SIZE);
1031 result.config.curl_config.user_agent[DEFAULT_BUFFER_SIZE - 1] = '\0';
1032 break;
1033 case 'k': /* Additional headers */
1034 if (result.config.curl_config.http_opt_headers_count == 0) {
1035 result.config.curl_config.http_opt_headers =
1036 malloc(sizeof(char *) * (++result.config.curl_config.http_opt_headers_count));
1037 } else {
1038 result.config.curl_config.http_opt_headers =
1039 realloc(result.config.curl_config.http_opt_headers,
1040 sizeof(char *) * (++result.config.curl_config.http_opt_headers_count));
1041 }
1042 result.config.curl_config
1043 .http_opt_headers[result.config.curl_config.http_opt_headers_count - 1] = optarg;
1044 break;
1045 case 'L': /* show html link */
1046 case 'n': /* do not show html link */
1047 // HTML link related options are deprecated
1048 break;
1049 case 'C': /* Check SSL cert validity */
1050#ifndef LIBCURL_FEATURE_SSL
1051 usage4(_("Invalid option - SSL is not available"));
1052#endif
1053 {
1054 char *temp;
1055 if ((temp = strchr(optarg, ',')) != NULL) {
1056 *temp = '\0';
1057 if (!is_intnonneg(optarg)) {
1058 usage2(_("Invalid certificate expiration period"), optarg);
1059 }
1060 result.config.days_till_exp_warn = atoi(optarg);
1061 *temp = ',';
1062 temp++;
1063 if (!is_intnonneg(temp)) {
1064 usage2(_("Invalid certificate expiration period"), temp);
1065 }
1066 result.config.days_till_exp_crit = atoi(temp);
1067 } else {
1068 result.config.days_till_exp_crit = 0;
1069 if (!is_intnonneg(optarg)) {
1070 usage2(_("Invalid certificate expiration period"), optarg);
1071 }
1072 result.config.days_till_exp_warn = atoi(optarg);
1073 }
1074 result.config.check_cert = true;
1075 enable_tls = true;
1076 }
1077 break;
1078 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
1079#ifdef HAVE_SSL
1080 result.config.continue_after_check_cert = true;
1081 break;
1082#endif
1083 case 'J': /* use client certificate */
1084#ifndef LIBCURL_FEATURE_SSL
1085 usage4(_("Invalid option - SSL is not available"));
1086#endif
1087 test_file(optarg);
1088 result.config.curl_config.client_cert = optarg;
1089 enable_tls = true;
1090 break;
1091 case 'K': /* use client private key */
1092#ifndef LIBCURL_FEATURE_SSL
1093 usage4(_("Invalid option - SSL is not available"));
1094#endif
1095 test_file(optarg);
1096 result.config.curl_config.client_privkey = optarg;
1097 enable_tls = true;
1098 break;
1099 case CA_CERT_OPTION: /* use CA chain file */
1100#ifndef LIBCURL_FEATURE_SSL
1101 usage4(_("Invalid option - SSL is not available"));
1102#endif
1103 test_file(optarg);
1104 result.config.curl_config.ca_cert = optarg;
1105 enable_tls = true;
1106 break;
1107 case 'D': /* verify peer certificate & host */
1108#ifndef LIBCURL_FEATURE_SSL
1109 usage4(_("Invalid option - SSL is not available"));
1110#endif
1111 result.config.curl_config.verify_peer_and_host = true;
1112 enable_tls = true;
1113 break;
1114 case 'S': /* use SSL */
1115 tls_option_optarg = optarg;
1116 enable_tls = true;
1117#ifndef LIBCURL_FEATURE_SSL
1118 usage4(_("Invalid option - SSL is not available"));
1119#endif
1120 break;
1121 case SNI_OPTION: /* --sni is parsed, but ignored, the default is true with libcurl */
1122#ifndef LIBCURL_FEATURE_SSL
1123 usage4(_("Invalid option - SSL is not available"));
1124#endif /* LIBCURL_FEATURE_SSL */
1125 break;
1126 case MAX_REDIRS_OPTION:
1127 if (!is_intnonneg(optarg)) {
1128 usage2(_("Invalid max_redirs count"), optarg);
1129 } else {
1130 result.config.max_depth = atoi(optarg);
1131 }
1132 break;
1133 case 'f': /* onredirect */
1134 if (!strcmp(optarg, "ok")) {
1135 result.config.on_redirect_result_state = STATE_OK;
1136 result.config.on_redirect_dependent = false;
1137 } else if (!strcmp(optarg, "warning")) {
1138 result.config.on_redirect_result_state = STATE_WARNING;
1139 result.config.on_redirect_dependent = false;
1140 } else if (!strcmp(optarg, "critical")) {
1141 result.config.on_redirect_result_state = STATE_CRITICAL;
1142 result.config.on_redirect_dependent = false;
1143 } else if (!strcmp(optarg, "unknown")) {
1144 result.config.on_redirect_result_state = STATE_UNKNOWN;
1145 result.config.on_redirect_dependent = false;
1146 } else if (!strcmp(optarg, "follow")) {
1147 result.config.on_redirect_dependent = true;
1148 } else if (!strcmp(optarg, "stickyport")) {
1149 result.config.on_redirect_dependent = true;
1150 result.config.followmethod = FOLLOW_HTTP_CURL,
1151 result.config.followsticky = STICKY_HOST | STICKY_PORT;
1152 } else if (!strcmp(optarg, "sticky")) {
1153 result.config.on_redirect_dependent = true;
1154 result.config.followmethod = FOLLOW_HTTP_CURL,
1155 result.config.followsticky = STICKY_HOST;
1156 } else if (!strcmp(optarg, "follow")) {
1157 result.config.on_redirect_dependent = true;
1158 result.config.followmethod = FOLLOW_HTTP_CURL,
1159 result.config.followsticky = STICKY_NONE;
1160 } else if (!strcmp(optarg, "curl")) {
1161 result.config.on_redirect_dependent = true;
1162 result.config.followmethod = FOLLOW_LIBCURL;
1163 } else {
1164 usage2(_("Invalid onredirect option"), optarg);
1165 }
1166 if (verbose >= 2) {
1167 if (result.config.on_redirect_dependent) {
1168 printf(_("* Following redirects\n"));
1169 } else {
1170 printf(_("* Following redirects set to state %s\n"),
1171 state_text(result.config.on_redirect_result_state));
1172 }
1173 }
1174 break;
1175 case 'd': /* string or substring */
1176 strncpy(result.config.header_expect, optarg, MAX_INPUT_BUFFER - 1);
1177 result.config.header_expect[MAX_INPUT_BUFFER - 1] = 0;
1178 break;
1179 case 's': /* string or substring */
1180 strncpy(result.config.string_expect, optarg, MAX_INPUT_BUFFER - 1);
1181 result.config.string_expect[MAX_INPUT_BUFFER - 1] = 0;
1182 break;
1183 case 'e': /* string or substring */
1184 strncpy(result.config.server_expect.string, optarg, MAX_INPUT_BUFFER - 1);
1185 result.config.server_expect.string[MAX_INPUT_BUFFER - 1] = 0;
1186 result.config.server_expect.is_present = true;
1187 break;
1188 case 'T': /* Content-type */
1189 result.config.curl_config.http_content_type = strdup(optarg);
1190 break;
1191 case 'l': /* linespan */
1192 cflags &= ~REG_NEWLINE;
1193 break;
1194 case 'R': /* regex */
1195 cflags |= REG_ICASE;
1196 // fall through
1197 case 'r': /* regex */
1198 strncpy(result.config.regexp, optarg, MAX_RE_SIZE - 1);
1199 result.config.regexp[MAX_RE_SIZE - 1] = 0;
1200 regex_t preg;
1201 int errcode = regcomp(&preg, result.config.regexp, cflags);
1202 if (errcode != 0) {
1203 (void)regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1204 printf(_("Could Not Compile Regular Expression: %s"), errbuf);
1205 result.errorcode = ERROR;
1206 return result;
1207 }
1208
1209 result.config.compiled_regex = preg;
1210 break;
1211 case INVERT_REGEX:
1212 result.config.invert_regex = true;
1213 break;
1214 case STATE_REGEX:
1215 if (!strcasecmp(optarg, "critical")) {
1216 result.config.state_regex = STATE_CRITICAL;
1217 } else if (!strcasecmp(optarg, "warning")) {
1218 result.config.state_regex = STATE_WARNING;
1219 } else {
1220 usage2(_("Invalid state-regex option"), optarg);
1221 }
1222 break;
1223 case '4':
1224 result.config.curl_config.sin_family = AF_INET;
1225 break;
1226 case '6':
1227#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6)
1228 result.config.curl_config.sin_family = AF_INET6;
1229#else
1230 usage4(_("IPv6 support not available"));
1231#endif
1232 break;
1233 case 'm': /* min_page_length */
1234 {
1235 mp_range_parsed foo = mp_parse_range_string(optarg);
2447 1236
2448 date_result = max_state_alt(STATE_CRITICAL, date_result); 1237 if (foo.error != MP_PARSING_SUCCES) {
1238 die(STATE_CRITICAL, "failed to parse page size limits: %s", optarg);
1239 }
2449 1240
2450 } else { 1241 result.config.page_length_limits = foo.range;
2451 time_t srv_data = curl_getdate (server_date, NULL); 1242 result.config.page_length_limits_is_set = true;
2452 time_t doc_data = curl_getdate (document_date, NULL); 1243 break;
2453 if (verbose >= 2) 1244 }
2454 printf ("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data, document_date, (int)doc_data); 1245 case 'N': /* no-body */
2455 if (srv_data <= 0) { 1246 result.config.initial_config.no_body = true;
2456 char tmp[DEFAULT_BUFFER_SIZE]; 1247 break;
1248 case 'M': /* max-age */
1249 {
1250 size_t option_length = strlen(optarg);
1251 if (option_length && optarg[option_length - 1] == 'm') {
1252 result.config.maximum_age = atoi(optarg) * 60;
1253 } else if (option_length && optarg[option_length - 1] == 'h') {
1254 result.config.maximum_age = atoi(optarg) * 60 * 60;
1255 } else if (option_length && optarg[option_length - 1] == 'd') {
1256 result.config.maximum_age = atoi(optarg) * 60 * 60 * 24;
1257 } else if (option_length &&
1258 (optarg[option_length - 1] == 's' || isdigit(optarg[option_length - 1]))) {
1259 result.config.maximum_age = atoi(optarg);
1260 } else {
1261 fprintf(stderr, "unparsable max-age: %s\n", optarg);
1262 exit(STATE_WARNING);
1263 }
1264 if (verbose >= 2) {
1265 printf("* Maximal age of document set to %d seconds\n", result.config.maximum_age);
1266 }
1267 } break;
1268 case 'E': /* show extended perfdata */
1269 result.config.show_extended_perfdata = true;
1270 break;
1271 case 'B': /* print body content after status line */
1272 result.config.show_body = true;
1273 break;
1274 case HTTP_VERSION_OPTION:
1275 result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_NONE;
1276 if (strcmp(optarg, "1.0") == 0) {
1277 result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_1_0;
1278 } else if (strcmp(optarg, "1.1") == 0) {
1279 result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_1_1;
1280 } else if ((strcmp(optarg, "2.0") == 0) || (strcmp(optarg, "2") == 0)) {
1281#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0)
1282 result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_2_0;
1283#else
1284 result.config.curl_http_version = CURL_HTTP_VERSION_NONE;
1285#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */
1286 } else if ((strcmp(optarg, "3") == 0)) {
1287#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 66, 0)
1288 result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_3;
1289#else
1290 result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_NONE;
1291#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 66, 0) */
1292 } else {
1293 fprintf(stderr, "unknown http-version parameter: %s\n", optarg);
1294 exit(STATE_WARNING);
1295 }
1296 break;
1297 case AUTOMATIC_DECOMPRESSION:
1298 result.config.curl_config.automatic_decompression = true;
1299 break;
1300 case COOKIE_JAR:
1301 result.config.curl_config.cookie_jar_file = optarg;
1302 break;
1303 case HAPROXY_PROTOCOL:
1304 result.config.curl_config.haproxy_protocol = true;
1305 break;
1306 case '?':
1307 /* print short usage statement if args not parsable */
1308 usage5();
1309 break;
1310 case OUTPUT_FORMAT: {
1311 parsed_output_format parser = mp_parse_output_format(optarg);
1312 if (!parser.parsing_success) {
1313 // TODO List all available formats here, maybe add anothoer usage function
1314 printf("Invalid output format: %s\n", optarg);
1315 exit(STATE_UNKNOWN);
1316 }
2457 1317
2458 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sServer date \"%100s\" unparsable, "), *msg, server_date); 1318 result.config.output_format_is_set = true;
2459 strcpy(*msg, tmp); 1319 result.config.output_format = parser.output_format;
1320 break;
1321 }
1322 }
1323 }
2460 1324
2461 date_result = max_state_alt(STATE_CRITICAL, date_result); 1325 if (enable_tls) {
2462 } else if (doc_data <= 0) { 1326 bool got_plus = false;
2463 char tmp[DEFAULT_BUFFER_SIZE]; 1327 result.config.initial_config.use_ssl = true;
1328 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default.
1329 * Only set if it's non-zero. This helps when we include multiple
1330 * parameters, like -S and -C combinations */
1331 result.config.curl_config.ssl_version = CURL_SSLVERSION_DEFAULT;
1332 if (tls_option_optarg != NULL) {
1333 char *plus_ptr = strchr(optarg, '+');
1334 if (plus_ptr) {
1335 got_plus = true;
1336 *plus_ptr = '\0';
1337 }
2464 1338
2465 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date); 1339 if (optarg[0] == '2') {
2466 strcpy(*msg, tmp); 1340 result.config.curl_config.ssl_version = CURL_SSLVERSION_SSLv2;
1341 } else if (optarg[0] == '3') {
1342 result.config.curl_config.ssl_version = CURL_SSLVERSION_SSLv3;
1343 } else if (!strcmp(optarg, "1") || !strcmp(optarg, "1.0")) {
1344#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1345 result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_0;
1346#else
1347 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1348#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1349 } else if (!strcmp(optarg, "1.1")) {
1350#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1351 result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_1;
1352#else
1353 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1354#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1355 } else if (!strcmp(optarg, "1.2")) {
1356#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1357 result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_2;
1358#else
1359 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1360#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1361 } else if (!strcmp(optarg, "1.3")) {
1362#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0)
1363 result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_3;
1364#else
1365 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1366#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */
1367 } else {
1368 usage4(_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2, 1.3 "
1369 "(with optional '+' suffix)"));
1370 }
1371 }
1372#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0)
1373 if (got_plus) {
1374 switch (result.config.curl_config.ssl_version) {
1375 case CURL_SSLVERSION_TLSv1_3:
1376 result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1377 break;
1378 case CURL_SSLVERSION_TLSv1_2:
1379 case CURL_SSLVERSION_TLSv1_1:
1380 case CURL_SSLVERSION_TLSv1_0:
1381 result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_DEFAULT;
1382 break;
1383 }
1384 } else {
1385 switch (result.config.curl_config.ssl_version) {
1386 case CURL_SSLVERSION_TLSv1_3:
1387 result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1388 break;
1389 case CURL_SSLVERSION_TLSv1_2:
1390 result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2;
1391 break;
1392 case CURL_SSLVERSION_TLSv1_1:
1393 result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1;
1394 break;
1395 case CURL_SSLVERSION_TLSv1_0:
1396 result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0;
1397 break;
1398 }
1399 }
1400#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */
1401 if (verbose >= 2) {
1402 printf(_("* Set SSL/TLS version to %d\n"), result.config.curl_config.ssl_version);
1403 }
1404 if (!specify_port) {
1405 result.config.initial_config.serverPort = HTTPS_PORT;
1406 }
1407 }
2467 1408
2468 date_result = max_state_alt(STATE_CRITICAL, date_result); 1409 int option_counter = optind;
2469 } else if (doc_data > srv_data + 30) {
2470 char tmp[DEFAULT_BUFFER_SIZE];
2471 1410
2472 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data); 1411 if (result.config.initial_config.server_address == NULL && option_counter < argc) {
2473 strcpy(*msg, tmp); 1412 result.config.initial_config.server_address = strdup(argv[option_counter++]);
1413 }
2474 1414
2475 date_result = max_state_alt(STATE_CRITICAL, date_result); 1415 if (result.config.initial_config.host_name == NULL && option_counter < argc) {
2476 } else if (doc_data < srv_data - maximum_age) { 1416 result.config.initial_config.host_name = strdup(argv[option_counter++]);
2477 int n = (srv_data - doc_data); 1417 }
2478 if (n > (60 * 60 * 24 * 2)) {
2479 char tmp[DEFAULT_BUFFER_SIZE];
2480 1418
2481 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %.1f days ago, "), *msg, ((float) n) / (60 * 60 * 24)); 1419 if (result.config.initial_config.server_address == NULL) {
2482 strcpy(*msg, tmp); 1420 if (result.config.initial_config.host_name == NULL) {
1421 usage4(_("You must specify a server address or host name"));
1422 } else {
1423 result.config.initial_config.server_address =
1424 strdup(result.config.initial_config.host_name);
1425 }
1426 }
2483 1427
2484 date_result = max_state_alt(STATE_CRITICAL, date_result); 1428 if (result.config.initial_config.http_method == NULL) {
2485 } else { 1429 result.config.initial_config.http_method = strdup("GET");
2486 char tmp[DEFAULT_BUFFER_SIZE]; 1430 }
2487 1431
2488 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60); 1432 if (result.config.curl_config.client_cert && !result.config.curl_config.client_privkey) {
2489 strcpy(*msg, tmp); 1433 usage4(_("If you use a client certificate you must also specify a private key file"));
1434 }
2490 1435
2491 date_result = max_state_alt(STATE_CRITICAL, date_result); 1436 if (result.config.initial_config.virtualPort == 0) {
1437 result.config.initial_config.virtualPort = result.config.initial_config.serverPort;
1438 } else {
1439 if ((result.config.initial_config.use_ssl &&
1440 result.config.initial_config.serverPort == HTTPS_PORT) ||
1441 (!result.config.initial_config.use_ssl &&
1442 result.config.initial_config.serverPort == HTTP_PORT)) {
1443 if (!specify_port) {
1444 result.config.initial_config.serverPort = result.config.initial_config.virtualPort;
2492 } 1445 }
2493 } 1446 }
2494 } 1447 }
2495 1448
2496 if (server_date) free (server_date); 1449 return result;
2497 if (document_date) free (document_date);
2498
2499 return date_result;
2500} 1450}
2501 1451
1452void print_help(void) {
1453 print_revision(progname, NP_VERSION);
2502 1454
2503int 1455 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
2504get_content_length (const curlhelp_write_curlbuf* header_buf, const curlhelp_write_curlbuf* body_buf) 1456 printf(COPYRIGHT, copyright, email);
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 1457
2513 int res = phr_parse_response (header_buf->buf, header_buf->buflen, 1458 printf("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
2514 &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen, 1459 printf("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
2515 headers, &nof_headers, 0); 1460 printf("%s\n", _("strings and regular expressions, check connection times, and report on"));
1461 printf("%s\n", _("certificate expiration times."));
1462 printf("\n");
1463 printf("%s\n",
1464 _("It makes use of libcurl to do so. It tries to be as compatible to check_http"));
1465 printf("%s\n", _("as possible."));
2516 1466
2517 if (res == -1) { 1467 printf("\n\n");
2518 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
2519 }
2520 1468
2521 content_length_s = get_header_value (headers, nof_headers, "content-length"); 1469 print_usage();
2522 if (!content_length_s) {
2523 return header_buf->buflen + body_buf->buflen;
2524 }
2525 content_length_s += strspn (content_length_s, " \t");
2526 content_length = atoi (content_length_s);
2527 if (content_length != body_buf->buflen) {
2528 /* TODO: should we warn if the actual and the reported body length don't match? */
2529 }
2530 1470
2531 if (content_length_s) free (content_length_s); 1471 printf(_("NOTE: One or both of -H and -I must be specified"));
2532 1472
2533 return header_buf->buflen + body_buf->buflen; 1473 printf("\n");
2534} 1474
1475 printf(UT_HELP_VRSN);
1476 printf(UT_EXTRA_OPTS);
2535 1477
2536/* TODO: is there a better way in libcurl to check for the SSL library? */ 1478 printf(" %s\n", "-H, --hostname=ADDRESS");
2537curlhelp_ssl_library 1479 printf(" %s\n", _("Host name argument for servers using host headers (virtual host)"));
2538curlhelp_get_ssl_library () 1480 printf(" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
2539{ 1481 printf(" %s\n", "-I, --IP-address=ADDRESS");
2540 curl_version_info_data* version_data; 1482 printf(" %s\n",
2541 char *ssl_version; 1483 _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
2542 char *library; 1484 printf(" %s\n", "-p, --port=INTEGER");
2543 curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN; 1485 printf(" %s", _("Port number (default: "));
1486 printf("%d)\n", HTTP_PORT);
2544 1487
2545 version_data = curl_version_info (CURLVERSION_NOW); 1488 printf(UT_IPv46);
2546 if (version_data == NULL) return CURLHELP_SSL_LIBRARY_UNKNOWN; 1489
1490#ifdef LIBCURL_FEATURE_SSL
1491 printf(" %s\n", "-S, --ssl=VERSION[+]");
1492 printf(" %s\n",
1493 _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents"));
1494 printf(" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,"));
1495 printf(" %s\n", _("1.2 = TLSv1.2, 1.3 = TLSv1.3). With a '+' suffix, newer versions are "
1496 "also accepted."));
1497 printf(" %s\n", _("Note: SSLv2, SSLv3, TLSv1.0 and TLSv1.1 are deprecated and are usually "
1498 "disabled in libcurl"));
1499 printf(" %s\n", "--sni");
1500 printf(" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
1501# if LIBCURL_VERSION_NUM >= 0x071801
1502 printf(" %s\n",
1503 _("Note: --sni is the default in libcurl as SSLv2 and SSLV3 are deprecated and"));
1504 printf(" %s\n", _(" SNI only really works since TLSv1.0"));
1505# else
1506 printf(" %s\n", _("Note: SNI is not supported in libcurl before 7.18.1"));
1507# endif
1508 printf(" %s\n", "-C, --certificate=INTEGER[,INTEGER]");
1509 printf(" %s\n",
1510 _("Minimum number of days a certificate has to be valid. Port defaults to 443."));
1511 printf(" %s\n",
1512 _("A STATE_WARNING is returned if the certificate has a validity less than the"));
1513 printf(" %s\n",
1514 _("first agument's value. If there is a second argument and the certificate's"));
1515 printf(" %s\n", _("validity is less than its value, a STATE_CRITICAL is returned."));
1516 printf(" %s\n",
1517 _("(When this option is used the URL is not checked by default. You can use"));
1518 printf(" %s\n", _(" --continue-after-certificate to override this behavior)"));
1519 printf(" %s\n", "--continue-after-certificate");
1520 printf(" %s\n",
1521 _("Allows the HTTP check to continue after performing the certificate check."));
1522 printf(" %s\n", _("Does nothing unless -C is used."));
1523 printf(" %s\n", "-J, --client-cert=FILE");
1524 printf(" %s\n", _("Name of file that contains the client certificate (PEM format)"));
1525 printf(" %s\n", _("to be used in establishing the SSL session"));
1526 printf(" %s\n", "-K, --private-key=FILE");
1527 printf(" %s\n", _("Name of file containing the private key (PEM format)"));
1528 printf(" %s\n", _("matching the client certificate"));
1529 printf(" %s\n", "--ca-cert=FILE");
1530 printf(" %s\n", _("CA certificate file to verify peer against"));
1531 printf(" %s\n", "-D, --verify-cert");
1532 printf(" %s\n", _("Verify the peer's SSL certificate and hostname"));
1533#endif
2547 1534
2548 ssl_version = strdup (version_data->ssl_version); 1535 printf(" %s\n", "-e, --expect=STRING");
2549 if (ssl_version == NULL ) return CURLHELP_SSL_LIBRARY_UNKNOWN; 1536 printf(" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
1537 printf(" %s", _("the first (status) line of the server response (default: "));
1538 printf("%s)\n", HTTP_EXPECT);
1539 printf(" %s\n",
1540 _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1541 printf(" %s\n", "-d, --header-string=STRING");
1542 printf(" %s\n", _("String to expect in the response headers"));
1543 printf(" %s\n", "-s, --string=STRING");
1544 printf(" %s\n", _("String to expect in the content"));
1545 printf(" %s\n", "-u, --url=PATH");
1546 printf(" %s\n", _("URL to GET or POST (default: /)"));
1547 printf(" %s\n", "-P, --post=STRING");
1548 printf(" %s\n", _("URL decoded http POST data"));
1549 printf(" %s\n",
1550 "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT)");
1551 printf(" %s\n", _("Set HTTP method."));
1552 printf(" %s\n", "-N, --no-body");
1553 printf(" %s\n", _("Don't wait for document body: stop reading after headers."));
1554 printf(" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
1555 printf(" %s\n", "-M, --max-age=SECONDS");
1556 printf(" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
1557 printf(" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
1558 printf(" %s\n", "-T, --content-type=STRING");
1559 printf(" %s\n", _("specify Content-Type header media type when POSTing\n"));
1560 printf(" %s\n", "-l, --linespan");
1561 printf(" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
1562 printf(" %s\n", "-r, --regex, --ereg=STRING");
1563 printf(" %s\n", _("Search page for regex STRING"));
1564 printf(" %s\n", "-R, --eregi=STRING");
1565 printf(" %s\n", _("Search page for case-insensitive regex STRING"));
1566 printf(" %s\n", "--invert-regex");
1567 printf(" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)"));
1568 printf(" %s\n", _("can be changed with --state--regex)"));
1569 printf(" %s\n", "--state-regex=STATE");
1570 printf(" %s\n", _("Return STATE if regex is found, OK if not. STATE can be one of "
1571 "\"critical\",\"warning\""));
1572 printf(" %s\n", "-a, --authorization=AUTH_PAIR");
1573 printf(" %s\n", _("Username:password on sites with basic authentication"));
1574 printf(" %s\n", "-b, --proxy-authorization=AUTH_PAIR");
1575 printf(" %s\n", _("Username:password on proxy-servers with basic authentication"));
1576 printf(" %s\n", "-A, --useragent=STRING");
1577 printf(" %s\n", _("String to be sent in http header as \"User Agent\""));
1578 printf(" %s\n", "-k, --header=STRING");
1579 printf(" %s\n", _("Any other tags to be sent in http header. Use multiple times for "
1580 "additional headers"));
1581 printf(" %s\n", "-E, --extended-perfdata");
1582 printf(" %s\n", _("Print additional performance data"));
1583 printf(" %s\n", "-B, --show-body");
1584 printf(" %s\n", _("Print body content below status line"));
1585 // printf(" %s\n", "-L, --link");
1586 // printf(" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1587 printf(" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport|curl>");
1588 printf(" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
1589 printf(" %s\n", _("specified IP address. stickyport also ensures port stays the same."));
1590 printf(" %s\n", _("follow uses the old redirection algorithm of check_http."));
1591 printf(" %s\n", _("curl uses CURL_FOLLOWLOCATION built into libcurl."));
1592 printf(" %s\n", "--max-redirs=INTEGER");
1593 printf(" %s", _("Maximal number of redirects (default: "));
1594 printf("%d)\n", DEFAULT_MAX_REDIRS);
1595 printf(" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1596 printf(" %s\n",
1597 _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1598 printf("\n");
1599 printf(" %s\n", "--http-version=VERSION");
1600 printf(" %s\n", _("Connect via specific HTTP protocol."));
1601 printf(" %s\n",
1602 _("1.0 = HTTP/1.0, 1.1 = HTTP/1.1, 2.0 = HTTP/2 (HTTP/2 will fail without -S)"));
1603 printf(" %s\n", "--enable-automatic-decompression");
1604 printf(" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING)."));
1605 printf(" %s\n", "--haproxy-protocol");
1606 printf(" %s\n", _("Send HAProxy proxy protocol v1 header (CURLOPT_HAPROXYPROTOCOL)."));
1607 printf(" %s\n", "--cookie-jar=FILE");
1608 printf(" %s\n", _("Store cookies in the cookie jar and send them out when requested."));
1609 printf(" %s\n",
1610 _("Specify an empty string as FILE to enable curl's cookie engine without saving"));
1611 printf(" %s\n",
1612 _("the cookies to disk. Only enabling the engine without saving to disk requires"));
1613 printf(" %s\n",
1614 _("handling multiple requests internally to curl, so use it with --onredirect=curl"));
1615 printf("\n");
1616
1617 printf(UT_WARN_CRIT);
1618
1619 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1620
1621 printf(UT_VERBOSE);
1622
1623 printf(UT_OUTPUT_FORMAT);
1624
1625 printf("\n");
1626 printf("%s\n", _("Notes:"));
1627 printf(" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
1628 printf(" %s\n",
1629 _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
1630 printf(" %s\n",
1631 _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response"));
1632 printf(" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
1633 printf(" %s\n",
1634 _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
1635 printf(" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
2550 1636
2551 library = strtok (ssl_version, "/"); 1637#ifdef LIBCURL_FEATURE_SSL
2552 if (library == NULL) return CURLHELP_SSL_LIBRARY_UNKNOWN; 1638 printf("\n");
1639 printf(" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
1640 printf(" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
1641 printf(" %s\n", _("certificate is still valid for the specified number of days."));
1642 printf("\n");
1643 printf(" %s\n", _("Please note that this plugin does not check if the presented server"));
1644 printf(" %s\n", _("certificate matches the hostname of the server, or if the certificate"));
1645 printf(" %s\n", _("has a valid chain of trust to one of the locally installed CAs."));
1646 printf("\n");
1647 printf("%s\n", _("Examples:"));
1648 printf(" %s\n\n", "CHECK CONTENT: check_curl -w 5 -c 10 --ssl -H www.verisign.com");
1649 printf(" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
1650 printf(" %s\n",
1651 _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1652 printf(" %s\n",
1653 _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1654 printf(" %s\n", _("a STATE_CRITICAL will be returned."));
1655 printf("\n");
1656 printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 14");
1657 printf(" %s\n",
1658 _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
1659 printf(" %s\n",
1660 _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1661 printf(" %s\n",
1662 _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
1663 printf(" %s\n\n", _("the certificate is expired."));
1664 printf("\n");
1665 printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 30,14");
1666 printf(" %s\n",
1667 _("When the certificate of 'www.verisign.com' is valid for more than 30 days,"));
1668 printf(" %s\n",
1669 _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1670 printf(" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned."));
1671 printf(" %s\n",
1672 _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days"));
1673#endif
2553 1674
2554 if (strcmp (library, "OpenSSL") == 0) 1675 printf("\n %s\n", "CHECK WEBSERVER CONTENT VIA PROXY:");
2555 ssl_library = CURLHELP_SSL_LIBRARY_OPENSSL; 1676 printf(" %s\n", _("It is recommended to use an environment proxy like:"));
2556 else if (strcmp (library, "LibreSSL") == 0) 1677 printf(" %s\n",
2557 ssl_library = CURLHELP_SSL_LIBRARY_LIBRESSL; 1678 _("http_proxy=http://192.168.100.35:3128 ./check_curl -H www.monitoring-plugins.org"));
2558 else if (strcmp (library, "GnuTLS") == 0) 1679 printf(" %s\n", _("legacy proxy requests in check_http style still work:"));
2559 ssl_library = CURLHELP_SSL_LIBRARY_GNUTLS; 1680 printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u http://www.monitoring-plugins.org/ "
2560 else if (strcmp (library, "NSS") == 0) 1681 "-H www.monitoring-plugins.org"));
2561 ssl_library = CURLHELP_SSL_LIBRARY_NSS;
2562 1682
2563 if (verbose >= 2) 1683#ifdef LIBCURL_FEATURE_SSL
2564 printf ("* SSL library string is : %s %s (%d)\n", version_data->ssl_version, library, ssl_library); 1684 printf("\n %s\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: ");
1685 printf(" %s\n", _("It is recommended to use an environment proxy like:"));
1686 printf(" %s\n",
1687 _("https_proxy=http://192.168.100.35:3128 ./check_curl -H www.verisign.com -S"));
1688 printf(" %s\n", _("legacy proxy requests in check_http style still work:"));
1689 printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u https://www.verisign.com/ -S -j "
1690 "CONNECT -H www.verisign.com "));
1691 printf(" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> "
1692 "-S(sl) -j CONNECT -H <webserver>"));
1693 printf(" %s\n",
1694 _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1695 printf(" %s\n",
1696 _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1697 printf(" %s\n", _("a STATE_CRITICAL will be returned."));
2565 1698
2566 free (ssl_version); 1699#endif
2567 1700
2568 return ssl_library; 1701 printf(UT_SUPPORT);
2569} 1702}
2570 1703
2571const char* 1704void print_usage(void) {
2572curlhelp_get_ssl_library_string (curlhelp_ssl_library ssl_library) 1705 printf("%s\n", _("Usage:"));
2573{ 1706 printf(" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n", progname);
2574 switch (ssl_library) { 1707 printf(" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate "
2575 case CURLHELP_SSL_LIBRARY_OPENSSL: 1708 "file>] [-D]\n");
2576 return "OpenSSL"; 1709 printf(" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n");
2577 case CURLHELP_SSL_LIBRARY_LIBRESSL: 1710 printf(" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport|curl>]\n");
2578 return "LibreSSL"; 1711 printf(" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive "
2579 case CURLHELP_SSL_LIBRARY_GNUTLS: 1712 "regex>]\n");
2580 return "GnuTLS"; 1713 printf(" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
2581 case CURLHELP_SSL_LIBRARY_NSS: 1714 printf(" [-A string] [-k string] [-S <version>] [--sni] [--haproxy-protocol]\n");
2582 return "NSS"; 1715 printf(" [-T <content-type>] [-j method]\n");
2583 case CURLHELP_SSL_LIBRARY_UNKNOWN: 1716 printf(" [--http-version=<version>] [--enable-automatic-decompression]\n");
2584 default: 1717 printf(" [--cookie-jar=<cookie jar file>\n");
2585 return "unknown"; 1718 printf(" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n", progname);
2586 } 1719 printf(" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n");
1720 printf("\n");
1721#ifdef LIBCURL_FEATURE_SSL
1722 printf("%s\n", _("In the first form, make an HTTP request."));
1723 printf("%s\n\n", _("In the second form, connect to the server and check the TLS certificate."));
1724#endif
2587} 1725}
2588 1726
1727void print_curl_version(void) { printf("%s\n", curl_version()); }
1728
2589#ifdef LIBCURL_FEATURE_SSL 1729#ifdef LIBCURL_FEATURE_SSL
2590#ifndef USE_OPENSSL 1730# ifndef USE_OPENSSL
2591time_t 1731time_t parse_cert_date(const char *s) {
2592parse_cert_date (const char *s) 1732 if (!s) {
2593{ 1733 return -1;
2594 struct tm tm; 1734 }
2595 time_t date; 1735
2596 char *res; 1736 /* Jan 17 14:25:12 2020 GMT */
2597 1737 struct tm tm;
2598 if (!s) return -1; 1738 char *res = strptime(s, "%Y-%m-%d %H:%M:%S GMT", &tm);
2599 1739 /* Sep 11 12:00:00 2020 GMT */
2600 /* Jan 17 14:25:12 2020 GMT */ 1740 if (res == NULL) {
2601 res = strptime (s, "%Y-%m-%d %H:%M:%S GMT", &tm); 1741 strptime(s, "%Y %m %d %H:%M:%S GMT", &tm);
2602 /* Sep 11 12:00:00 2020 GMT */ 1742 }
2603 if (res == NULL) strptime (s, "%Y %m %d %H:%M:%S GMT", &tm); 1743 time_t date = mktime(&tm);
2604 date = mktime (&tm); 1744
2605 1745 return date;
2606 return date;
2607} 1746}
1747# endif /* USE_OPENSSL */
1748#endif /* LIBCURL_FEATURE_SSL */
2608 1749
1750#ifdef LIBCURL_FEATURE_SSL
1751# ifndef USE_OPENSSL
2609/* TODO: this needs cleanup in the sslutils.c, maybe we the #else case to 1752/* TODO: this needs cleanup in the sslutils.c, maybe we the #else case to
2610 * OpenSSL could be this function 1753 * OpenSSL could be this function
2611 */ 1754 */
2612int 1755int net_noopenssl_check_certificate(cert_ptr_union *cert_ptr, int days_till_exp_warn,
2613net_noopenssl_check_certificate (cert_ptr_union* cert_ptr, int days_till_exp_warn, int days_till_exp_crit) 1756 int days_till_exp_crit) {
2614{ 1757
2615 int i; 1758 if (verbose >= 2) {
2616 struct curl_slist* slist; 1759 printf("**** REQUEST CERTIFICATES ****\n");
2617 int cname_found = 0; 1760 }
2618 char* start_date_str = NULL; 1761
2619 char* end_date_str = NULL; 1762 char *start_date_str = NULL;
2620 time_t start_date; 1763 char *end_date_str = NULL;
2621 time_t end_date; 1764 bool have_first_cert = false;
2622 char *tz; 1765 bool cname_found = false;
2623 float time_left; 1766 for (int i = 0; i < cert_ptr->to_certinfo->num_of_certs; i++) {
2624 int days_left; 1767 if (have_first_cert) {
2625 int time_remaining; 1768 break;
2626 char timestamp[50] = ""; 1769 }
2627 int status = STATE_UNKNOWN; 1770
2628 1771 struct curl_slist *slist;
2629 if (verbose >= 2) 1772 for (slist = cert_ptr->to_certinfo->certinfo[i]; slist; slist = slist->next) {
2630 printf ("**** REQUEST CERTIFICATES ****\n"); 1773 /* find first common name in subject,
2631 1774 * TODO: check alternative subjects for
2632 for (i = 0; i < cert_ptr->to_certinfo->num_of_certs; i++) { 1775 * TODO: have a decent parser here and not a hack
2633 for (slist = cert_ptr->to_certinfo->certinfo[i]; slist; slist = slist->next) { 1776 * multi-host certificate, check wildcards
2634 /* find first common name in subject, 1777 */
2635 * TODO: check alternative subjects for 1778 if (strncasecmp(slist->data, "Subject:", 8) == 0) {
2636 * TODO: have a decent parser here and not a hack 1779 int d = 3;
2637 * multi-host certificate, check wildcards 1780 char *p = strstr(slist->data, "CN=");
2638 */ 1781 if (p == NULL) {
2639 if (strncasecmp (slist->data, "Subject:", 8) == 0) { 1782 d = 5;
2640 int d = 3; 1783 p = strstr(slist->data, "CN = ");
2641 char* p = strstr (slist->data, "CN="); 1784 }
2642 if (p == NULL) { 1785 if (p != NULL) {
2643 d = 5; 1786 if (strncmp(host_name, p + d, strlen(host_name)) == 0) {
2644 p = strstr (slist->data, "CN = "); 1787 cname_found = true;
2645 } 1788 }
2646 if (p != NULL) { 1789 }
2647 if (strncmp (host_name, p+d, strlen (host_name)) == 0) { 1790 } else if (strncasecmp(slist->data, "Start Date:", 11) == 0) {
2648 cname_found = 1; 1791 start_date_str = &slist->data[11];
2649 } 1792 } else if (strncasecmp(slist->data, "Expire Date:", 12) == 0) {
2650 } 1793 end_date_str = &slist->data[12];
2651 } else if (strncasecmp (slist->data, "Start Date:", 11) == 0) { 1794 } else if (strncasecmp(slist->data, "Cert:", 5) == 0) {
2652 start_date_str = &slist->data[11]; 1795 have_first_cert = true;
2653 } else if (strncasecmp (slist->data, "Expire Date:", 12) == 0) { 1796 break;
2654 end_date_str = &slist->data[12]; 1797 }
2655 } else if (strncasecmp (slist->data, "Cert:", 5) == 0) { 1798 if (verbose >= 2) {
2656 goto HAVE_FIRST_CERT; 1799 printf("%d ** %s\n", i, slist->data);
2657 } 1800 }
2658 if (verbose >= 2) 1801 }
2659 printf ("%d ** %s\n", i, slist->data); 1802 }
2660 } 1803
2661 } 1804 if (verbose >= 2) {
2662HAVE_FIRST_CERT: 1805 printf("**** REQUEST CERTIFICATES ****\n");
2663 1806 }
2664 if (verbose >= 2) 1807
2665 printf ("**** REQUEST CERTIFICATES ****\n"); 1808 if (!cname_found) {
2666 1809 printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject."));
2667 if (!cname_found) {
2668 printf("%s\n",_("CRITICAL - Cannot retrieve certificate subject."));
2669 return STATE_CRITICAL; 1810 return STATE_CRITICAL;
2670 } 1811 }
2671 1812
2672 start_date = parse_cert_date (start_date_str); 1813 time_t start_date = parse_cert_date(start_date_str);
2673 if (start_date <= 0) { 1814 if (start_date <= 0) {
2674 snprintf (msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Start Date' in certificate: '%s'"), 1815 snprintf(msg, DEFAULT_BUFFER_SIZE,
2675 start_date_str); 1816 _("WARNING - Unparsable 'Start Date' in certificate: '%s'"), start_date_str);
2676 puts (msg); 1817 puts(msg);
2677 return STATE_WARNING; 1818 return STATE_WARNING;
2678 } 1819 }
2679 1820
2680 end_date = parse_cert_date (end_date_str); 1821 time_t end_date = parse_cert_date(end_date_str);
2681 if (end_date <= 0) { 1822 if (end_date <= 0) {
2682 snprintf (msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Expire Date' in certificate: '%s'"), 1823 snprintf(msg, DEFAULT_BUFFER_SIZE,
2683 start_date_str); 1824 _("WARNING - Unparsable 'Expire Date' in certificate: '%s'"), start_date_str);
2684 puts (msg); 1825 puts(msg);
2685 return STATE_WARNING; 1826 return STATE_WARNING;
2686 } 1827 }
2687 1828
2688 time_left = difftime (end_date, time(NULL)); 1829 float time_left = difftime(end_date, time(NULL));
2689 days_left = time_left / 86400; 1830 int days_left = time_left / 86400;
2690 tz = getenv("TZ"); 1831 char *tz = getenv("TZ");
2691 setenv("TZ", "GMT", 1); 1832 setenv("TZ", "GMT", 1);
2692 tzset(); 1833 tzset();
1834
1835 char timestamp[50] = "";
2693 strftime(timestamp, 50, "%c %z", localtime(&end_date)); 1836 strftime(timestamp, 50, "%c %z", localtime(&end_date));
2694 if (tz) 1837 if (tz) {
2695 setenv("TZ", tz, 1); 1838 setenv("TZ", tz, 1);
2696 else 1839 } else {
2697 unsetenv("TZ"); 1840 unsetenv("TZ");
1841 }
2698 tzset(); 1842 tzset();
2699 1843
1844 mp_state_enum status = STATE_UNKNOWN;
1845 int time_remaining;
2700 if (days_left > 0 && days_left <= days_till_exp_warn) { 1846 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); 1847 printf(_("%s - Certificate '%s' expires in %d day(s) (%s).\n"),
2702 if (days_left > days_till_exp_crit) 1848 (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, days_left,
1849 timestamp);
1850 if (days_left > days_till_exp_crit) {
2703 status = STATE_WARNING; 1851 status = STATE_WARNING;
2704 else 1852 } else {
2705 status = STATE_CRITICAL; 1853 status = STATE_CRITICAL;
1854 }
2706 } else if (days_left == 0 && time_left > 0) { 1855 } else if (days_left == 0 && time_left > 0) {
2707 if (time_left >= 3600) 1856 if (time_left >= 3600) {
2708 time_remaining = (int) time_left / 3600; 1857 time_remaining = (int)time_left / 3600;
2709 else 1858 } else {
2710 time_remaining = (int) time_left / 60; 1859 time_remaining = (int)time_left / 60;
1860 }
2711 1861
2712 printf (_("%s - Certificate '%s' expires in %u %s (%s)\n"), 1862 printf(_("%s - Certificate '%s' expires in %u %s (%s)\n"),
2713 (days_left>days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, time_remaining, 1863 (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, time_remaining,
2714 time_left >= 3600 ? "hours" : "minutes", timestamp); 1864 time_left >= 3600 ? "hours" : "minutes", timestamp);
2715 1865
2716 if ( days_left > days_till_exp_crit) 1866 if (days_left > days_till_exp_crit) {
2717 status = STATE_WARNING; 1867 status = STATE_WARNING;
2718 else 1868 } else {
2719 status = STATE_CRITICAL; 1869 status = STATE_CRITICAL;
1870 }
2720 } else if (time_left < 0) { 1871 } else if (time_left < 0) {
2721 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), host_name, timestamp); 1872 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), host_name, timestamp);
2722 status=STATE_CRITICAL; 1873 status = STATE_CRITICAL;
2723 } else if (days_left == 0) { 1874 } 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); 1875 printf(_("%s - Certificate '%s' just expired (%s).\n"),
2725 if (days_left > days_till_exp_crit) 1876 (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, timestamp);
1877 if (days_left > days_till_exp_crit) {
2726 status = STATE_WARNING; 1878 status = STATE_WARNING;
2727 else 1879 } else {
2728 status = STATE_CRITICAL; 1880 status = STATE_CRITICAL;
1881 }
2729 } else { 1882 } else {
2730 printf(_("OK - Certificate '%s' will expire on %s.\n"), host_name, timestamp); 1883 printf(_("OK - Certificate '%s' will expire on %s.\n"), host_name, timestamp);
2731 status = STATE_OK; 1884 status = STATE_OK;
2732 } 1885 }
2733 return status; 1886 return status;
2734} 1887}
2735#endif /* USE_OPENSSL */ 1888# endif /* USE_OPENSSL */
2736#endif /* LIBCURL_FEATURE_SSL */ 1889#endif /* LIBCURL_FEATURE_SSL */
diff --git a/plugins/check_curl.d/check_curl_helpers.c b/plugins/check_curl.d/check_curl_helpers.c
new file mode 100644
index 00000000..c3c2ba55
--- /dev/null
+++ b/plugins/check_curl.d/check_curl_helpers.c
@@ -0,0 +1,1267 @@
1#include "./check_curl_helpers.h"
2#include <stdbool.h>
3#include <arpa/inet.h>
4#include <netinet/in.h>
5#include <netdb.h>
6#include <stdlib.h>
7#include "../utils.h"
8#include "check_curl.d/config.h"
9#include "output.h"
10#include "perfdata.h"
11#include "states.h"
12
13extern int verbose;
14char errbuf[MAX_INPUT_BUFFER];
15bool is_openssl_callback = false;
16bool add_sslctx_verify_fun = false;
17
18check_curl_configure_curl_wrapper
19check_curl_configure_curl(const check_curl_static_curl_config config,
20 check_curl_working_state working_state, bool check_cert,
21 bool on_redirect_dependent, int follow_method, int max_depth) {
22 check_curl_configure_curl_wrapper result = {
23 .errorcode = OK,
24 .curl_state =
25 {
26 .curl_global_initialized = false,
27 .curl_easy_initialized = false,
28 .curl = NULL,
29
30 .body_buf_initialized = false,
31 .body_buf = NULL,
32 .header_buf_initialized = false,
33 .header_buf = NULL,
34 .status_line_initialized = false,
35 .status_line = NULL,
36 .put_buf_initialized = false,
37 .put_buf = NULL,
38
39 .header_list = NULL,
40 .host = NULL,
41 },
42 };
43
44 if ((result.curl_state.status_line = calloc(1, sizeof(curlhelp_statusline))) == NULL) {
45 die(STATE_UNKNOWN, "HTTP UNKNOWN - allocation of statusline failed\n");
46 }
47
48 if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) {
49 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n");
50 }
51 result.curl_state.curl_global_initialized = true;
52
53 if ((result.curl_state.curl = curl_easy_init()) == NULL) {
54 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n");
55 }
56 result.curl_state.curl_easy_initialized = true;
57
58 if (verbose >= 1) {
59 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_VERBOSE, 1),
60 "CURLOPT_VERBOSE");
61 }
62
63 /* print everything on stdout like check_http would do */
64 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_STDERR, stdout),
65 "CURLOPT_STDERR");
66
67 if (config.automatic_decompression) {
68#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6)
69 handle_curl_option_return_code(
70 curl_easy_setopt(result.curl_state.curl, CURLOPT_ACCEPT_ENCODING, ""),
71 "CURLOPT_ACCEPT_ENCODING");
72#else
73 handle_curl_option_return_code(
74 curl_easy_setopt(result.curl_state.curl, CURLOPT_ENCODING, ""), "CURLOPT_ENCODING");
75#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */
76 }
77
78 /* initialize buffer for body of the answer */
79 if (curlhelp_initwritebuffer(&result.curl_state.body_buf) < 0) {
80 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n");
81 }
82 result.curl_state.body_buf_initialized = true;
83
84 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_WRITEFUNCTION,
85 curlhelp_buffer_write_callback),
86 "CURLOPT_WRITEFUNCTION");
87 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_WRITEDATA,
88 (void *)result.curl_state.body_buf),
89 "CURLOPT_WRITEDATA");
90
91 /* initialize buffer for header of the answer */
92 if (curlhelp_initwritebuffer(&result.curl_state.header_buf) < 0) {
93 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n");
94 }
95 result.curl_state.header_buf_initialized = true;
96
97 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_HEADERFUNCTION,
98 curlhelp_buffer_write_callback),
99 "CURLOPT_HEADERFUNCTION");
100 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_WRITEHEADER,
101 (void *)result.curl_state.header_buf),
102 "CURLOPT_WRITEHEADER");
103
104 /* set the error buffer */
105 handle_curl_option_return_code(
106 curl_easy_setopt(result.curl_state.curl, CURLOPT_ERRORBUFFER, errbuf),
107 "CURLOPT_ERRORBUFFER");
108
109 /* set timeouts */
110 handle_curl_option_return_code(
111 curl_easy_setopt(result.curl_state.curl, CURLOPT_CONNECTTIMEOUT, config.socket_timeout),
112 "CURLOPT_CONNECTTIMEOUT");
113
114 handle_curl_option_return_code(
115 curl_easy_setopt(result.curl_state.curl, CURLOPT_TIMEOUT, config.socket_timeout),
116 "CURLOPT_TIMEOUT");
117
118 /* enable haproxy protocol */
119 if (config.haproxy_protocol) {
120 handle_curl_option_return_code(
121 curl_easy_setopt(result.curl_state.curl, CURLOPT_HAPROXYPROTOCOL, 1L),
122 "CURLOPT_HAPROXYPROTOCOL");
123 }
124
125 // fill dns resolve cache to make curl connect to the given server_address instead of the
126 // host_name, only required for ssl, because we use the host_name later on to make SNI happy
127 char dnscache[DEFAULT_BUFFER_SIZE];
128 char addrstr[DEFAULT_BUFFER_SIZE / 2];
129 if (working_state.use_ssl && working_state.host_name != NULL) {
130 int res;
131 if ((res = lookup_host(working_state.server_address, addrstr, DEFAULT_BUFFER_SIZE / 2,
132 config.sin_family)) != 0) {
133 die(STATE_CRITICAL,
134 _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"),
135 working_state.server_address, res, gai_strerror(res));
136 }
137
138 snprintf(dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", working_state.host_name,
139 working_state.serverPort, addrstr);
140 result.curl_state.host = curl_slist_append(NULL, dnscache);
141 curl_easy_setopt(result.curl_state.curl, CURLOPT_RESOLVE, result.curl_state.host);
142
143 if (verbose >= 1) {
144 printf("* curl CURLOPT_RESOLVE: %s\n", dnscache);
145 }
146 }
147
148 // If server_address is an IPv6 address it must be surround by square brackets
149 struct in6_addr tmp_in_addr;
150 if (inet_pton(AF_INET6, working_state.server_address, &tmp_in_addr) == 1) {
151 char *new_server_address = calloc(strlen(working_state.server_address) + 3, sizeof(char));
152 if (new_server_address == NULL) {
153 die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n");
154 }
155 snprintf(new_server_address, strlen(working_state.server_address) + 3, "[%s]",
156 working_state.server_address);
157 working_state.server_address = new_server_address;
158 }
159
160 /* compose URL: use the address we want to connect to, set Host: header later */
161 char *url = fmt_url(working_state);
162
163 if (verbose >= 1) {
164 printf("* curl CURLOPT_URL: %s\n", url);
165 }
166 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_URL, url),
167 "CURLOPT_URL");
168
169 free(url);
170
171 /* extract proxy information for legacy proxy https requests */
172 if (!strcmp(working_state.http_method, "CONNECT") ||
173 strstr(working_state.server_url, "http") == working_state.server_url) {
174 handle_curl_option_return_code(
175 curl_easy_setopt(result.curl_state.curl, CURLOPT_PROXY, working_state.server_address),
176 "CURLOPT_PROXY");
177 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_PROXYPORT,
178 (long)working_state.serverPort),
179 "CURLOPT_PROXYPORT");
180 if (verbose >= 2) {
181 printf("* curl CURLOPT_PROXY: %s:%d\n", working_state.server_address,
182 working_state.serverPort);
183 }
184 working_state.http_method = "GET";
185 handle_curl_option_return_code(
186 curl_easy_setopt(result.curl_state.curl, CURLOPT_URL, working_state.server_url),
187 "CURLOPT_URL");
188 }
189
190 /* disable body for HEAD request */
191 if (working_state.http_method && !strcmp(working_state.http_method, "HEAD")) {
192 working_state.no_body = true;
193 }
194
195 /* set HTTP protocol version */
196 handle_curl_option_return_code(
197 curl_easy_setopt(result.curl_state.curl, CURLOPT_HTTP_VERSION, config.curl_http_version),
198 "CURLOPT_HTTP_VERSION");
199
200 /* set HTTP method */
201 if (working_state.http_method) {
202 if (!strcmp(working_state.http_method, "POST")) {
203 handle_curl_option_return_code(
204 curl_easy_setopt(result.curl_state.curl, CURLOPT_POST, 1), "CURLOPT_POST");
205 } else if (!strcmp(working_state.http_method, "PUT")) {
206 handle_curl_option_return_code(
207 curl_easy_setopt(result.curl_state.curl, CURLOPT_UPLOAD, 1), "CURLOPT_UPLOAD");
208 } else {
209 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl,
210 CURLOPT_CUSTOMREQUEST,
211 working_state.http_method),
212 "CURLOPT_CUSTOMREQUEST");
213 }
214 }
215
216 char *force_host_header = NULL;
217 /* check if Host header is explicitly set in options */
218 if (config.http_opt_headers_count) {
219 for (size_t i = 0; i < config.http_opt_headers_count; i++) {
220 if (strncmp(config.http_opt_headers[i], "Host:", 5) == 0) {
221 force_host_header = config.http_opt_headers[i];
222 }
223 }
224 }
225
226 /* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in
227 * anyway */
228 char http_header[DEFAULT_BUFFER_SIZE];
229 if (working_state.host_name != NULL && force_host_header == NULL) {
230 if ((working_state.virtualPort != HTTP_PORT && !working_state.use_ssl) ||
231 (working_state.virtualPort != HTTPS_PORT && working_state.use_ssl)) {
232 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", working_state.host_name,
233 working_state.virtualPort);
234 } else {
235 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", working_state.host_name);
236 }
237 result.curl_state.header_list =
238 curl_slist_append(result.curl_state.header_list, http_header);
239 }
240
241 /* always close connection, be nice to servers */
242 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Connection: close");
243 result.curl_state.header_list = curl_slist_append(result.curl_state.header_list, http_header);
244
245 /* attach additional headers supplied by the user */
246 /* optionally send any other header tag */
247 if (config.http_opt_headers_count) {
248 for (size_t i = 0; i < config.http_opt_headers_count; i++) {
249 result.curl_state.header_list =
250 curl_slist_append(result.curl_state.header_list, config.http_opt_headers[i]);
251 }
252 }
253
254 /* set HTTP headers */
255 handle_curl_option_return_code(
256 curl_easy_setopt(result.curl_state.curl, CURLOPT_HTTPHEADER, result.curl_state.header_list),
257 "CURLOPT_HTTPHEADER");
258
259#ifdef LIBCURL_FEATURE_SSL
260 /* set SSL version, warn about insecure or unsupported versions */
261 if (working_state.use_ssl) {
262 handle_curl_option_return_code(
263 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSLVERSION, config.ssl_version),
264 "CURLOPT_SSLVERSION");
265 }
266
267 /* client certificate and key to present to server (SSL) */
268 if (config.client_cert) {
269 handle_curl_option_return_code(
270 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSLCERT, config.client_cert),
271 "CURLOPT_SSLCERT");
272 }
273
274 if (config.client_privkey) {
275 handle_curl_option_return_code(
276 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSLKEY, config.client_privkey),
277 "CURLOPT_SSLKEY");
278 }
279
280 if (config.ca_cert) {
281 handle_curl_option_return_code(
282 curl_easy_setopt(result.curl_state.curl, CURLOPT_CAINFO, config.ca_cert),
283 "CURLOPT_CAINFO");
284 }
285
286 if (config.ca_cert || config.verify_peer_and_host) {
287 /* per default if we have a CA verify both the peer and the
288 * hostname in the certificate, can be switched off later */
289 handle_curl_option_return_code(
290 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 1),
291 "CURLOPT_SSL_VERIFYPEER");
292 handle_curl_option_return_code(
293 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 2),
294 "CURLOPT_SSL_VERIFYHOST");
295 } else {
296 /* backward-compatible behaviour, be tolerant in checks
297 * TODO: depending on more options have aspects we want
298 * to be less tolerant about ssl verfications
299 */
300 handle_curl_option_return_code(
301 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 0),
302 "CURLOPT_SSL_VERIFYPEER");
303 handle_curl_option_return_code(
304 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 0),
305 "CURLOPT_SSL_VERIFYHOST");
306 }
307
308 /* detect SSL library used by libcurl */
309 curlhelp_ssl_library ssl_library = curlhelp_get_ssl_library();
310
311 /* try hard to get a stack of certificates to verify against */
312 if (check_cert) {
313# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1)
314 /* inform curl to report back certificates */
315 switch (ssl_library) {
316 case CURLHELP_SSL_LIBRARY_OPENSSL:
317 case CURLHELP_SSL_LIBRARY_LIBRESSL:
318 /* set callback to extract certificate with OpenSSL context function (works with
319 * OpenSSL-style libraries only!) */
320# ifdef USE_OPENSSL
321 /* libcurl and monitoring plugins built with OpenSSL, good */
322 add_sslctx_verify_fun = true;
323 is_openssl_callback = true;
324# endif /* USE_OPENSSL */
325 /* libcurl is built with OpenSSL, monitoring plugins, so falling
326 * back to manually extracting certificate information */
327 handle_curl_option_return_code(
328 curl_easy_setopt(result.curl_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
329 break;
330
331 case CURLHELP_SSL_LIBRARY_NSS:
332# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
333 /* NSS: support for CERTINFO is implemented since 7.34.0 */
334 handle_curl_option_return_code(
335 curl_easy_setopt(result.curl_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
336# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
337 die(STATE_CRITICAL,
338 "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library "
339 "'%s' is too old)\n",
340 curlhelp_get_ssl_library_string(ssl_library));
341# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
342 break;
343
344 case CURLHELP_SSL_LIBRARY_GNUTLS:
345# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0)
346 /* GnuTLS: support for CERTINFO is implemented since 7.42.0 */
347 handle_curl_option_return_code(
348 curl_easy_setopt(result.curl_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
349# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
350 die(STATE_CRITICAL,
351 "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library "
352 "'%s' is too old)\n",
353 curlhelp_get_ssl_library_string(ssl_library));
354# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
355 break;
356
357 case CURLHELP_SSL_LIBRARY_UNKNOWN:
358 default:
359 die(STATE_CRITICAL,
360 "HTTP CRITICAL - Cannot retrieve certificates (unknown SSL library '%s', must "
361 "implement first)\n",
362 curlhelp_get_ssl_library_string(ssl_library));
363 break;
364 }
365# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
366 /* old libcurl, our only hope is OpenSSL, otherwise we are out of luck */
367 if (ssl_library == CURLHELP_SSL_LIBRARY_OPENSSL ||
368 ssl_library == CURLHELP_SSL_LIBRARY_LIBRESSL) {
369 add_sslctx_verify_fun = true;
370 } else {
371 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (no "
372 "CURLOPT_SSL_CTX_FUNCTION, no OpenSSL library or libcurl "
373 "too old and has no CURLOPT_CERTINFO)\n");
374 }
375# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
376 }
377
378# if LIBCURL_VERSION_NUM >= \
379 MAKE_LIBCURL_VERSION(7, 10, 6) /* required for CURLOPT_SSL_CTX_FUNCTION */
380 // ssl ctx function is not available with all ssl backends
381 if (curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_CTX_FUNCTION, NULL) !=
382 CURLE_UNKNOWN_OPTION) {
383 handle_curl_option_return_code(
384 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun),
385 "CURLOPT_SSL_CTX_FUNCTION");
386 }
387# endif
388#endif /* LIBCURL_FEATURE_SSL */
389
390 /* set default or user-given user agent identification */
391 handle_curl_option_return_code(
392 curl_easy_setopt(result.curl_state.curl, CURLOPT_USERAGENT, config.user_agent),
393 "CURLOPT_USERAGENT");
394
395 /* proxy-authentication */
396 if (strcmp(config.proxy_auth, "")) {
397 handle_curl_option_return_code(
398 curl_easy_setopt(result.curl_state.curl, CURLOPT_PROXYUSERPWD, config.proxy_auth),
399 "CURLOPT_PROXYUSERPWD");
400 }
401
402 /* authentication */
403 if (strcmp(config.user_auth, "")) {
404 handle_curl_option_return_code(
405 curl_easy_setopt(result.curl_state.curl, CURLOPT_USERPWD, config.user_auth),
406 "CURLOPT_USERPWD");
407 }
408 /* TODO: parameter auth method, bitfield of following methods:
409 * CURLAUTH_BASIC (default)
410 * CURLAUTH_DIGEST
411 * CURLAUTH_DIGEST_IE
412 * CURLAUTH_NEGOTIATE
413 * CURLAUTH_NTLM
414 * CURLAUTH_NTLM_WB
415 *
416 * convenience tokens for typical sets of methods:
417 * CURLAUTH_ANYSAFE: most secure, without BASIC
418 * or CURLAUTH_ANY: most secure, even BASIC if necessary
419 *
420 * handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPAUTH,
421 * (long)CURLAUTH_DIGEST ), "CURLOPT_HTTPAUTH");
422 */
423
424 /* handle redirections */
425 if (on_redirect_dependent) {
426 if (follow_method == FOLLOW_LIBCURL) {
427 handle_curl_option_return_code(
428 curl_easy_setopt(result.curl_state.curl, CURLOPT_FOLLOWLOCATION, 1),
429 "CURLOPT_FOLLOWLOCATION");
430
431 /* default -1 is infinite, not good, could lead to zombie plugins!
432 Setting it to one bigger than maximal limit to handle errors nicely below
433 */
434 handle_curl_option_return_code(
435 curl_easy_setopt(result.curl_state.curl, CURLOPT_MAXREDIRS, max_depth + 1),
436 "CURLOPT_MAXREDIRS");
437
438 /* for now allow only http and https (we are a http(s) check plugin in the end) */
439#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0)
440 handle_curl_option_return_code(
441 curl_easy_setopt(result.curl_state.curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"),
442 "CURLOPT_REDIR_PROTOCOLS_STR");
443#elif LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4)
444 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl,
445 CURLOPT_REDIR_PROTOCOLS,
446 CURLPROTO_HTTP | CURLPROTO_HTTPS),
447 "CURLOPT_REDIRECT_PROTOCOLS");
448#endif
449
450 /* TODO: handle the following aspects of redirection, make them
451 * command line options too later:
452 CURLOPT_POSTREDIR: method switch
453 CURLINFO_REDIRECT_URL: custom redirect option
454 CURLOPT_REDIRECT_PROTOCOLS: allow people to step outside safe protocols
455 CURLINFO_REDIRECT_COUNT: get the number of redirects, print it, maybe a range
456 option here is nice like for expected page size?
457 */
458 } else {
459 /* old style redirection*/
460 }
461 }
462 /* no-body */
463 if (working_state.no_body) {
464 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_NOBODY, 1),
465 "CURLOPT_NOBODY");
466 }
467
468 /* IPv4 or IPv6 forced DNS resolution */
469 if (config.sin_family == AF_UNSPEC) {
470 handle_curl_option_return_code(
471 curl_easy_setopt(result.curl_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER),
472 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)");
473 } else if (config.sin_family == AF_INET) {
474 handle_curl_option_return_code(
475 curl_easy_setopt(result.curl_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4),
476 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)");
477 }
478#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6)
479 else if (config.sin_family == AF_INET6) {
480 handle_curl_option_return_code(
481 curl_easy_setopt(result.curl_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6),
482 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)");
483 }
484#endif
485
486 /* either send http POST data (any data, not only POST)*/
487 if (!strcmp(working_state.http_method, "POST") || !strcmp(working_state.http_method, "PUT")) {
488 /* set content of payload for POST and PUT */
489 if (config.http_content_type) {
490 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s",
491 config.http_content_type);
492 result.curl_state.header_list =
493 curl_slist_append(result.curl_state.header_list, http_header);
494 }
495 /* NULL indicates "HTTP Continue" in libcurl, provide an empty string
496 * in case of no POST/PUT data */
497 if (!working_state.http_post_data) {
498 working_state.http_post_data = "";
499 }
500
501 if (!strcmp(working_state.http_method, "POST")) {
502 /* POST method, set payload with CURLOPT_POSTFIELDS */
503 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl,
504 CURLOPT_POSTFIELDS,
505 working_state.http_post_data),
506 "CURLOPT_POSTFIELDS");
507 } else if (!strcmp(working_state.http_method, "PUT")) {
508 handle_curl_option_return_code(
509 curl_easy_setopt(result.curl_state.curl, CURLOPT_READFUNCTION,
510 (curl_read_callback)curlhelp_buffer_read_callback),
511 "CURLOPT_READFUNCTION");
512 if (curlhelp_initreadbuffer(&result.curl_state.put_buf, working_state.http_post_data,
513 strlen(working_state.http_post_data)) < 0) {
514 die(STATE_UNKNOWN,
515 "HTTP CRITICAL - out of memory allocating read buffer for PUT\n");
516 }
517 result.curl_state.put_buf_initialized = true;
518 handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl,
519 CURLOPT_READDATA,
520 (void *)result.curl_state.put_buf),
521 "CURLOPT_READDATA");
522 handle_curl_option_return_code(
523 curl_easy_setopt(result.curl_state.curl, CURLOPT_INFILESIZE,
524 (curl_off_t)strlen(working_state.http_post_data)),
525 "CURLOPT_INFILESIZE");
526 }
527 }
528
529 /* cookie handling */
530 if (config.cookie_jar_file != NULL) {
531 /* enable reading cookies from a file, and if the filename is an empty string, only
532 * enable the curl cookie engine */
533 handle_curl_option_return_code(
534 curl_easy_setopt(result.curl_state.curl, CURLOPT_COOKIEFILE, config.cookie_jar_file),
535 "CURLOPT_COOKIEFILE");
536 /* now enable saving cookies to a file, but only if the filename is not an empty string,
537 * since writing it would fail */
538 if (*config.cookie_jar_file) {
539 handle_curl_option_return_code(
540 curl_easy_setopt(result.curl_state.curl, CURLOPT_COOKIEJAR, config.cookie_jar_file),
541 "CURLOPT_COOKIEJAR");
542 }
543 }
544
545 result.working_state = working_state;
546
547 return result;
548}
549
550void handle_curl_option_return_code(CURLcode res, const char *option) {
551 if (res != CURLE_OK) {
552 die(STATE_CRITICAL, _("Error while setting cURL option '%s': cURL returned %d - %s"),
553 option, res, curl_easy_strerror(res));
554 }
555}
556
557char *get_header_value(const struct phr_header *headers, const size_t nof_headers,
558 const char *header) {
559 for (size_t i = 0; i < nof_headers; i++) {
560 if (headers[i].name != NULL &&
561 strncasecmp(header, headers[i].name, max(headers[i].name_len, 4)) == 0) {
562 return strndup(headers[i].value, headers[i].value_len);
563 }
564 }
565 return NULL;
566}
567
568check_curl_working_state check_curl_working_state_init() {
569 check_curl_working_state result = {
570 .server_address = NULL,
571 .server_url = DEFAULT_SERVER_URL,
572 .host_name = NULL,
573 .http_method = NULL,
574 .http_post_data = NULL,
575 .virtualPort = 0,
576 .serverPort = HTTP_PORT,
577 .use_ssl = false,
578 .no_body = false,
579 };
580 return result;
581}
582
583check_curl_config check_curl_config_init() {
584 check_curl_config tmp = {
585 .initial_config = check_curl_working_state_init(),
586
587 .curl_config =
588 {
589 .automatic_decompression = false,
590 .socket_timeout = DEFAULT_SOCKET_TIMEOUT,
591 .haproxy_protocol = false,
592 .sin_family = AF_UNSPEC,
593 .curl_http_version = CURL_HTTP_VERSION_NONE,
594 .http_opt_headers = NULL,
595 .http_opt_headers_count = 0,
596 .ssl_version = CURL_SSLVERSION_DEFAULT,
597 .client_cert = NULL,
598 .client_privkey = NULL,
599 .ca_cert = NULL,
600 .verify_peer_and_host = false,
601 .user_agent = {'\0'},
602 .proxy_auth = "",
603 .user_auth = "",
604 .http_content_type = NULL,
605 .cookie_jar_file = NULL,
606 },
607 .max_depth = DEFAULT_MAX_REDIRS,
608 .followmethod = FOLLOW_HTTP_CURL,
609 .followsticky = STICKY_NONE,
610
611 .maximum_age = -1,
612 .regexp = {},
613 .compiled_regex = {},
614 .state_regex = STATE_CRITICAL,
615 .invert_regex = false,
616 .check_cert = false,
617 .continue_after_check_cert = false,
618 .days_till_exp_warn = 0,
619 .days_till_exp_crit = 0,
620 .thlds = mp_thresholds_init(),
621 .page_length_limits = mp_range_init(),
622 .page_length_limits_is_set = false,
623 .server_expect =
624 {
625 .string = HTTP_EXPECT,
626 .is_present = false,
627 },
628 .string_expect = "",
629 .header_expect = "",
630 .on_redirect_result_state = STATE_OK,
631 .on_redirect_dependent = false,
632
633 .show_extended_perfdata = false,
634 .show_body = false,
635
636 .output_format_is_set = false,
637 };
638
639 snprintf(tmp.curl_config.user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s, %s)",
640 "check_curl", NP_VERSION, VERSION, curl_version());
641
642 return tmp;
643}
644
645/* TODO: is there a better way in libcurl to check for the SSL library? */
646curlhelp_ssl_library curlhelp_get_ssl_library(void) {
647 curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
648
649 curl_version_info_data *version_data = curl_version_info(CURLVERSION_NOW);
650 if (version_data == NULL) {
651 return CURLHELP_SSL_LIBRARY_UNKNOWN;
652 }
653
654 char *ssl_version = strdup(version_data->ssl_version);
655 if (ssl_version == NULL) {
656 return CURLHELP_SSL_LIBRARY_UNKNOWN;
657 }
658
659 char *library = strtok(ssl_version, "/");
660 if (library == NULL) {
661 return CURLHELP_SSL_LIBRARY_UNKNOWN;
662 }
663
664 if (strcmp(library, "OpenSSL") == 0) {
665 ssl_library = CURLHELP_SSL_LIBRARY_OPENSSL;
666 } else if (strcmp(library, "LibreSSL") == 0) {
667 ssl_library = CURLHELP_SSL_LIBRARY_LIBRESSL;
668 } else if (strcmp(library, "GnuTLS") == 0) {
669 ssl_library = CURLHELP_SSL_LIBRARY_GNUTLS;
670 } else if (strcmp(library, "NSS") == 0) {
671 ssl_library = CURLHELP_SSL_LIBRARY_NSS;
672 }
673
674 if (verbose >= 2) {
675 printf("* SSL library string is : %s %s (%d)\n", version_data->ssl_version, library,
676 ssl_library);
677 }
678
679 free(ssl_version);
680
681 return ssl_library;
682}
683
684const char *curlhelp_get_ssl_library_string(const curlhelp_ssl_library ssl_library) {
685 switch (ssl_library) {
686 case CURLHELP_SSL_LIBRARY_OPENSSL:
687 return "OpenSSL";
688 case CURLHELP_SSL_LIBRARY_LIBRESSL:
689 return "LibreSSL";
690 case CURLHELP_SSL_LIBRARY_GNUTLS:
691 return "GnuTLS";
692 case CURLHELP_SSL_LIBRARY_NSS:
693 return "NSS";
694 case CURLHELP_SSL_LIBRARY_UNKNOWN:
695 default:
696 return "unknown";
697 }
698}
699
700size_t get_content_length(const curlhelp_write_curlbuf *header_buf,
701 const curlhelp_write_curlbuf *body_buf) {
702 struct phr_header headers[255];
703 size_t nof_headers = 255;
704 size_t msglen;
705 curlhelp_statusline status_line;
706 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major,
707 &status_line.http_minor, &status_line.http_code, &status_line.msg,
708 &msglen, headers, &nof_headers, 0);
709
710 if (res == -1) {
711 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
712 }
713
714 char *content_length_s = get_header_value(headers, nof_headers, "content-length");
715 if (!content_length_s) {
716 return header_buf->buflen + body_buf->buflen;
717 }
718
719 content_length_s += strspn(content_length_s, " \t");
720 size_t content_length = atoi(content_length_s);
721 if (content_length != body_buf->buflen) {
722 /* TODO: should we warn if the actual and the reported body length don't match? */
723 }
724
725 if (content_length_s) {
726 free(content_length_s);
727 }
728
729 return header_buf->buflen + body_buf->buflen;
730}
731
732mp_subcheck check_document_dates(const curlhelp_write_curlbuf *header_buf, const int maximum_age) {
733 struct phr_header headers[255];
734 size_t nof_headers = 255;
735 curlhelp_statusline status_line;
736 size_t msglen;
737 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major,
738 &status_line.http_minor, &status_line.http_code, &status_line.msg,
739 &msglen, headers, &nof_headers, 0);
740
741 if (res == -1) {
742 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
743 }
744
745 char *server_date = get_header_value(headers, nof_headers, "date");
746 char *document_date = get_header_value(headers, nof_headers, "last-modified");
747
748 mp_subcheck sc_document_dates = mp_subcheck_init();
749 if (!server_date || !*server_date) {
750 xasprintf(&sc_document_dates.output, _("Server date unknown"));
751 sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_UNKNOWN);
752 } else if (!document_date || !*document_date) {
753 xasprintf(&sc_document_dates.output, _("Document modification date unknown, "));
754 sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL);
755 } else {
756 time_t srv_data = curl_getdate(server_date, NULL);
757 time_t doc_data = curl_getdate(document_date, NULL);
758
759 if (verbose >= 2) {
760 printf("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data,
761 document_date, (int)doc_data);
762 }
763
764 if (srv_data <= 0) {
765 xasprintf(&sc_document_dates.output, _("Server date \"%100s\" unparsable"),
766 server_date);
767 sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL);
768 } else if (doc_data <= 0) {
769
770 xasprintf(&sc_document_dates.output, _("Document date \"%100s\" unparsable"),
771 document_date);
772 sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL);
773 } else if (doc_data > srv_data + 30) {
774
775 xasprintf(&sc_document_dates.output, _("Document is %d seconds in the future"),
776 (int)doc_data - (int)srv_data);
777
778 sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL);
779 } else if (doc_data < srv_data - maximum_age) {
780 time_t last_modified = (srv_data - doc_data);
781 if (last_modified > (60 * 60 * 24 * 2)) { // two days hardcoded?
782 xasprintf(&sc_document_dates.output, _("Last modified %.1f days ago"),
783 ((float)last_modified) / (60 * 60 * 24));
784 sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL);
785 } else {
786 xasprintf(&sc_document_dates.output, _("Last modified %ld:%02ld:%02ld ago"),
787 last_modified / (60 * 60), (last_modified / 60) % 60, last_modified % 60);
788 sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL);
789 }
790 } else {
791 // TODO is this the OK case?
792 time_t last_modified = (srv_data - doc_data);
793 xasprintf(&sc_document_dates.output, _("Last modified %ld:%02ld:%02ld ago"),
794 last_modified / (60 * 60), (last_modified / 60) % 60, last_modified % 60);
795 sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_OK);
796 }
797 }
798
799 if (server_date) {
800 free(server_date);
801 }
802 if (document_date) {
803 free(document_date);
804 }
805
806 return sc_document_dates;
807}
808
809void curlhelp_free_statusline(curlhelp_statusline *status_line) { free(status_line->first_line); }
810
811int curlhelp_parse_statusline(const char *buf, curlhelp_statusline *status_line) {
812 /* find last start of a new header */
813 const char *start = strrstr2(buf, "\r\nHTTP/");
814 if (start != NULL) {
815 start += 2;
816 buf = start;
817 }
818
819 char *first_line_end = strstr(buf, "\r\n");
820 if (first_line_end == NULL) {
821 return -1;
822 }
823
824 size_t first_line_len = (size_t)(first_line_end - buf);
825 status_line->first_line = (char *)calloc(first_line_len + 1, sizeof(char));
826 if (status_line->first_line == NULL) {
827 return -1;
828 }
829 memcpy(status_line->first_line, buf, first_line_len);
830 status_line->first_line[first_line_len] = '\0';
831 char *first_line_buf = strdup(status_line->first_line);
832
833 /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */
834 char *temp_string = strtok(first_line_buf, "/");
835 if (temp_string == NULL) {
836 free(first_line_buf);
837 return -1;
838 }
839 if (strcmp(temp_string, "HTTP") != 0) {
840 free(first_line_buf);
841 return -1;
842 }
843
844 temp_string = strtok(NULL, " ");
845 if (temp_string == NULL) {
846 free(first_line_buf);
847 return -1;
848 }
849
850 char *temp_string_2;
851 if (strchr(temp_string, '.') != NULL) {
852
853 /* HTTP 1.x case */
854 strtok(temp_string, ".");
855 status_line->http_major = (int)strtol(temp_string, &temp_string_2, 10);
856 if (*temp_string_2 != '\0') {
857 free(first_line_buf);
858 return -1;
859 }
860 strtok(NULL, " ");
861 status_line->http_minor = (int)strtol(temp_string, &temp_string_2, 10);
862 if (*temp_string_2 != '\0') {
863 free(first_line_buf);
864 return -1;
865 }
866 temp_string += 4; /* 1.x SP */
867 } else {
868 /* HTTP 2 case */
869 status_line->http_major = (int)strtol(temp_string, &temp_string_2, 10);
870 status_line->http_minor = 0;
871 temp_string += 2; /* 2 SP */
872 }
873
874 /* status code: "404" or "404.1", then SP */
875 temp_string = strtok(temp_string, " ");
876 if (temp_string == NULL) {
877 free(first_line_buf);
878 return -1;
879 }
880 if (strchr(temp_string, '.') != NULL) {
881 char *ppp;
882 ppp = strtok(temp_string, ".");
883 status_line->http_code = (int)strtol(ppp, &temp_string_2, 10);
884 if (*temp_string_2 != '\0') {
885 free(first_line_buf);
886 return -1;
887 }
888 ppp = strtok(NULL, "");
889 status_line->http_subcode = (int)strtol(ppp, &temp_string_2, 10);
890 if (*temp_string_2 != '\0') {
891 free(first_line_buf);
892 return -1;
893 }
894 temp_string += 6; /* 400.1 SP */
895 } else {
896 status_line->http_code = (int)strtol(temp_string, &temp_string_2, 10);
897 status_line->http_subcode = -1;
898 if (*temp_string_2 != '\0') {
899 free(first_line_buf);
900 return -1;
901 }
902 temp_string += 4; /* 400 SP */
903 }
904
905 /* Human readable message: "Not Found" CRLF */
906
907 temp_string = strtok(temp_string, "");
908 if (temp_string == NULL) {
909 status_line->msg = "";
910 return 0;
911 }
912 status_line->msg = status_line->first_line + (temp_string - first_line_buf);
913 free(first_line_buf);
914
915 return 0;
916}
917
918/* TODO: where to put this, it's actually part of sstrings2 (logically)?
919 */
920const char *strrstr2(const char *haystack, const char *needle) {
921 if (haystack == NULL || needle == NULL) {
922 return NULL;
923 }
924
925 if (haystack[0] == '\0' || needle[0] == '\0') {
926 return NULL;
927 }
928
929 int counter = 0;
930 const char *prev_pos = NULL;
931 const char *pos = haystack;
932 size_t len = strlen(needle);
933 for (;;) {
934 pos = strstr(pos, needle);
935 if (pos == NULL) {
936 if (counter == 0) {
937 return NULL;
938 }
939 return prev_pos;
940 }
941 counter++;
942 prev_pos = pos;
943 pos += len;
944 if (*pos == '\0') {
945 return prev_pos;
946 }
947 }
948}
949
950void curlhelp_freereadbuffer(curlhelp_read_curlbuf *buf) {
951 free(buf->buf);
952 buf->buf = NULL;
953}
954
955void curlhelp_freewritebuffer(curlhelp_write_curlbuf *buf) {
956 free(buf->buf);
957 buf->buf = NULL;
958}
959
960int curlhelp_initreadbuffer(curlhelp_read_curlbuf **buf, const char *data, size_t datalen) {
961 if ((*buf = calloc(1, sizeof(curlhelp_read_curlbuf))) == NULL) {
962 return 1;
963 }
964
965 (*buf)->buflen = datalen;
966 (*buf)->buf = (char *)calloc((*buf)->buflen, sizeof(char));
967 if ((*buf)->buf == NULL) {
968 return -1;
969 }
970 memcpy((*buf)->buf, data, datalen);
971 (*buf)->pos = 0;
972 return 0;
973}
974
975size_t curlhelp_buffer_read_callback(void *buffer, size_t size, size_t nmemb, void *stream) {
976 curlhelp_read_curlbuf *buf = (curlhelp_read_curlbuf *)stream;
977
978 size_t minimalSize = min(nmemb * size, buf->buflen - buf->pos);
979
980 memcpy(buffer, buf->buf + buf->pos, minimalSize);
981 buf->pos += minimalSize;
982
983 return minimalSize;
984}
985
986int curlhelp_initwritebuffer(curlhelp_write_curlbuf **buf) {
987 if ((*buf = calloc(1, sizeof(curlhelp_write_curlbuf))) == NULL) {
988 return 1;
989 }
990 (*buf)->bufsize = DEFAULT_BUFFER_SIZE * sizeof(char);
991 (*buf)->buflen = 0;
992 (*buf)->buf = (char *)calloc((*buf)->bufsize, sizeof(char));
993 if ((*buf)->buf == NULL) {
994 return -1;
995 }
996 return 0;
997}
998
999size_t curlhelp_buffer_write_callback(void *buffer, size_t size, size_t nmemb, void *stream) {
1000 curlhelp_write_curlbuf *buf = (curlhelp_write_curlbuf *)stream;
1001
1002 while (buf->bufsize < buf->buflen + size * nmemb + 1) {
1003 buf->bufsize = buf->bufsize * 2;
1004 buf->buf = (char *)realloc(buf->buf, buf->bufsize);
1005 if (buf->buf == NULL) {
1006 fprintf(stderr, "malloc failed (%d) %s\n", errno, strerror(errno));
1007 return 0;
1008 }
1009 }
1010
1011 memcpy(buf->buf + buf->buflen, buffer, size * nmemb);
1012 buf->buflen += size * nmemb;
1013 buf->buf[buf->buflen] = '\0';
1014
1015 return size * nmemb;
1016}
1017
1018void cleanup(check_curl_global_state global_state) {
1019 if (global_state.status_line_initialized) {
1020 curlhelp_free_statusline(global_state.status_line);
1021 }
1022 global_state.status_line_initialized = false;
1023
1024 if (global_state.curl_easy_initialized) {
1025 curl_easy_cleanup(global_state.curl);
1026 }
1027 global_state.curl_easy_initialized = false;
1028
1029 if (global_state.curl_global_initialized) {
1030 curl_global_cleanup();
1031 }
1032 global_state.curl_global_initialized = false;
1033
1034 if (global_state.body_buf_initialized) {
1035 curlhelp_freewritebuffer(global_state.body_buf);
1036 }
1037 global_state.body_buf_initialized = false;
1038
1039 if (global_state.header_buf_initialized) {
1040 curlhelp_freewritebuffer(global_state.header_buf);
1041 }
1042 global_state.header_buf_initialized = false;
1043
1044 if (global_state.put_buf_initialized) {
1045 curlhelp_freereadbuffer(global_state.put_buf);
1046 }
1047 global_state.put_buf_initialized = false;
1048
1049 if (global_state.header_list) {
1050 curl_slist_free_all(global_state.header_list);
1051 }
1052
1053 if (global_state.host) {
1054 curl_slist_free_all(global_state.host);
1055 }
1056}
1057
1058int lookup_host(const char *host, char *buf, size_t buflen, sa_family_t addr_family) {
1059 struct addrinfo hints = {
1060 .ai_family = addr_family,
1061 .ai_socktype = SOCK_STREAM,
1062 .ai_flags = AI_CANONNAME,
1063 };
1064
1065 struct addrinfo *result;
1066 int errcode = getaddrinfo(host, NULL, &hints, &result);
1067 if (errcode != 0) {
1068 return errcode;
1069 }
1070
1071 strcpy(buf, "");
1072 struct addrinfo *res = result;
1073
1074 size_t buflen_remaining = buflen - 1;
1075 size_t addrstr_len;
1076 char addrstr[100];
1077 void *ptr = {0};
1078 while (res) {
1079 switch (res->ai_family) {
1080 case AF_INET:
1081 ptr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
1082 break;
1083 case AF_INET6:
1084 ptr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
1085 break;
1086 }
1087
1088 inet_ntop(res->ai_family, ptr, addrstr, 100);
1089 if (verbose >= 1) {
1090 printf("* getaddrinfo IPv%d address: %s\n", res->ai_family == PF_INET6 ? 6 : 4,
1091 addrstr);
1092 }
1093
1094 // Append all IPs to buf as a comma-separated string
1095 addrstr_len = strlen(addrstr);
1096 if (buflen_remaining > addrstr_len + 1) {
1097 if (buf[0] != '\0') {
1098 strncat(buf, ",", buflen_remaining);
1099 buflen_remaining -= 1;
1100 }
1101 strncat(buf, addrstr, buflen_remaining);
1102 buflen_remaining -= addrstr_len;
1103 }
1104
1105 res = res->ai_next;
1106 }
1107
1108 freeaddrinfo(result);
1109
1110 return 0;
1111}
1112
1113/* Checks if the server 'reply' is one of the expected 'statuscodes' */
1114bool expected_statuscode(const char *reply, const char *statuscodes) {
1115 char *expected;
1116
1117 if ((expected = strdup(statuscodes)) == NULL) {
1118 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
1119 }
1120
1121 bool result = false;
1122 for (char *code = strtok(expected, ","); code != NULL; code = strtok(NULL, ",")) {
1123 if (strstr(reply, code) != NULL) {
1124 result = true;
1125 break;
1126 }
1127 }
1128
1129 free(expected);
1130 return result;
1131}
1132
1133/* returns a string "HTTP/1.x" or "HTTP/2" */
1134char *string_statuscode(int major, int minor) {
1135 static char buf[10];
1136
1137 switch (major) {
1138 case 1:
1139 snprintf(buf, sizeof(buf), "HTTP/%d.%d", major, minor);
1140 break;
1141 case 2:
1142 case 3:
1143 snprintf(buf, sizeof(buf), "HTTP/%d", major);
1144 break;
1145 default:
1146 /* assuming here HTTP/N with N>=4 */
1147 snprintf(buf, sizeof(buf), "HTTP/%d", major);
1148 break;
1149 }
1150
1151 return buf;
1152}
1153
1154/* check whether a file exists */
1155void test_file(char *path) {
1156 if (access(path, R_OK) == 0) {
1157 return;
1158 }
1159 usage2(_("file does not exist or is not readable"), path);
1160}
1161
1162mp_subcheck mp_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn,
1163 int days_till_exp_crit);
1164
1165mp_subcheck check_curl_certificate_checks(CURL *curl, X509 *cert, int warn_days_till_exp,
1166 int crit_days_till_exp) {
1167 mp_subcheck sc_cert_result = mp_subcheck_init();
1168 sc_cert_result = mp_set_subcheck_default_state(sc_cert_result, STATE_OK);
1169
1170#ifdef LIBCURL_FEATURE_SSL
1171 if (is_openssl_callback) {
1172# ifdef USE_OPENSSL
1173 /* check certificate with OpenSSL functions, curl has been built against OpenSSL
1174 * and we actually have OpenSSL in the monitoring tools
1175 */
1176 return mp_net_ssl_check_certificate(cert, warn_days_till_exp, crit_days_till_exp);
1177# else /* USE_OPENSSL */
1178 xasprintf(&result.output, "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL "
1179 "callback used and not linked against OpenSSL\n");
1180 mp_set_subcheck_state(result, STATE_CRITICAL);
1181# endif /* USE_OPENSSL */
1182 } else {
1183 struct curl_slist *slist;
1184
1185 cert_ptr_union cert_ptr = {0};
1186 cert_ptr.to_info = NULL;
1187 CURLcode res = curl_easy_getinfo(curl, CURLINFO_CERTINFO, &cert_ptr.to_info);
1188 if (!res && cert_ptr.to_info) {
1189# ifdef USE_OPENSSL
1190 /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert
1191 * parsing We only check the first certificate and assume it's the one of
1192 * the server
1193 */
1194 char *raw_cert = NULL;
1195 bool got_first_cert = false;
1196 for (int i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) {
1197 if (got_first_cert) {
1198 break;
1199 }
1200
1201 for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) {
1202 if (verbose >= 2) {
1203 printf("%d ** %s\n", i, slist->data);
1204 }
1205 if (strncmp(slist->data, "Cert:", 5) == 0) {
1206 raw_cert = &slist->data[5];
1207 got_first_cert = true;
1208 break;
1209 }
1210 }
1211 }
1212
1213 if (!raw_cert) {
1214
1215 xasprintf(&sc_cert_result.output,
1216 _("Cannot retrieve certificates from CERTINFO information - "
1217 "certificate data was empty"));
1218 sc_cert_result = mp_set_subcheck_state(sc_cert_result, STATE_CRITICAL);
1219 return sc_cert_result;
1220 }
1221
1222 BIO *cert_BIO = BIO_new(BIO_s_mem());
1223 BIO_write(cert_BIO, raw_cert, (int)strlen(raw_cert));
1224
1225 cert = PEM_read_bio_X509(cert_BIO, NULL, NULL, NULL);
1226 if (!cert) {
1227 xasprintf(&sc_cert_result.output,
1228 _("Cannot read certificate from CERTINFO information - BIO error"));
1229 sc_cert_result = mp_set_subcheck_state(sc_cert_result, STATE_CRITICAL);
1230 return sc_cert_result;
1231 }
1232
1233 BIO_free(cert_BIO);
1234 return mp_net_ssl_check_certificate(cert, warn_days_till_exp, crit_days_till_exp);
1235# else /* USE_OPENSSL */
1236 /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our
1237 * disposal, so we use the libcurl CURLINFO data
1238 */
1239 return net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn,
1240 days_till_exp_crit);
1241# endif /* USE_OPENSSL */
1242 } else {
1243 xasprintf(&sc_cert_result.output,
1244 _("Cannot retrieve certificates - cURL returned %d - %s"), res,
1245 curl_easy_strerror(res));
1246 mp_set_subcheck_state(sc_cert_result, STATE_CRITICAL);
1247 }
1248 }
1249#endif /* LIBCURL_FEATURE_SSL */
1250
1251 return sc_cert_result;
1252}
1253
1254char *fmt_url(check_curl_working_state workingState) {
1255 char *url = calloc(DEFAULT_BUFFER_SIZE, sizeof(char));
1256 if (url == NULL) {
1257 die(STATE_UNKNOWN, "memory allocation failed");
1258 }
1259
1260 snprintf(url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", workingState.use_ssl ? "https" : "http",
1261 (workingState.use_ssl & (workingState.host_name != NULL))
1262 ? workingState.host_name
1263 : workingState.server_address,
1264 workingState.serverPort, workingState.server_url);
1265
1266 return url;
1267}
diff --git a/plugins/check_curl.d/check_curl_helpers.h b/plugins/check_curl.d/check_curl_helpers.h
new file mode 100644
index 00000000..87e45a9d
--- /dev/null
+++ b/plugins/check_curl.d/check_curl_helpers.h
@@ -0,0 +1,124 @@
1#include "./config.h"
2#include <curl/curl.h>
3#include "../picohttpparser/picohttpparser.h"
4#include "output.h"
5
6#if defined(HAVE_SSL) && defined(USE_OPENSSL)
7# include <openssl/opensslv.h>
8#endif
9
10/* for buffers for header and body */
11typedef struct {
12 size_t buflen;
13 size_t bufsize;
14 char *buf;
15} curlhelp_write_curlbuf;
16
17/* for buffering the data sent in PUT */
18typedef struct {
19 size_t buflen;
20 off_t pos;
21 char *buf;
22} curlhelp_read_curlbuf;
23
24/* for parsing the HTTP status line */
25typedef struct {
26 int http_major; /* major version of the protocol, always 1 (HTTP/0.9
27 * never reached the big internet most likely) */
28 int http_minor; /* minor version of the protocol, usually 0 or 1 */
29 int http_code; /* HTTP return code as in RFC 2145 */
30 int http_subcode; /* Microsoft IIS extension, HTTP subcodes, see
31 * http://support.microsoft.com/kb/318380/en-us */
32 const char *msg; /* the human readable message */
33 char *first_line; /* a copy of the first line */
34} curlhelp_statusline;
35
36typedef struct {
37 bool curl_global_initialized;
38 bool curl_easy_initialized;
39
40 bool body_buf_initialized;
41 curlhelp_write_curlbuf *body_buf;
42
43 bool header_buf_initialized;
44 curlhelp_write_curlbuf *header_buf;
45
46 bool status_line_initialized;
47 curlhelp_statusline *status_line;
48
49 bool put_buf_initialized;
50 curlhelp_read_curlbuf *put_buf;
51
52 CURL *curl;
53
54 struct curl_slist *header_list;
55 struct curl_slist *host;
56} check_curl_global_state;
57
58/* to know the underlying SSL library used by libcurl */
59typedef enum curlhelp_ssl_library {
60 CURLHELP_SSL_LIBRARY_UNKNOWN,
61 CURLHELP_SSL_LIBRARY_OPENSSL,
62 CURLHELP_SSL_LIBRARY_LIBRESSL,
63 CURLHELP_SSL_LIBRARY_GNUTLS,
64 CURLHELP_SSL_LIBRARY_NSS
65} curlhelp_ssl_library;
66
67#define MAKE_LIBCURL_VERSION(major, minor, patch) ((major) * 0x10000 + (minor) * 0x100 + (patch))
68
69typedef struct {
70 int errorcode;
71 check_curl_global_state curl_state;
72 check_curl_working_state working_state;
73} check_curl_configure_curl_wrapper;
74
75check_curl_configure_curl_wrapper check_curl_configure_curl(check_curl_static_curl_config config,
76 check_curl_working_state working_state,
77 bool check_cert,
78 bool on_redirect_dependent,
79 int follow_method, int max_depth);
80
81void handle_curl_option_return_code(CURLcode res, const char *option);
82
83int curlhelp_initwritebuffer(curlhelp_write_curlbuf **buf);
84size_t curlhelp_buffer_write_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/,
85 void * /*stream*/);
86void curlhelp_freewritebuffer(curlhelp_write_curlbuf * /*buf*/);
87
88int curlhelp_initreadbuffer(curlhelp_read_curlbuf **buf, const char * /*data*/, size_t /*datalen*/);
89size_t curlhelp_buffer_read_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/,
90 void * /*stream*/);
91void curlhelp_freereadbuffer(curlhelp_read_curlbuf * /*buf*/);
92
93curlhelp_ssl_library curlhelp_get_ssl_library(void);
94const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library /*ssl_library*/);
95
96typedef union {
97 struct curl_slist *to_info;
98 struct curl_certinfo *to_certinfo;
99} cert_ptr_union;
100int net_noopenssl_check_certificate(cert_ptr_union *, int, int);
101
102int curlhelp_parse_statusline(const char * /*buf*/, curlhelp_statusline * /*status_line*/);
103void curlhelp_free_statusline(curlhelp_statusline * /*status_line*/);
104
105char *get_header_value(const struct phr_header *headers, size_t nof_headers, const char *header);
106mp_subcheck check_document_dates(const curlhelp_write_curlbuf * /*header_buf*/,
107 int /*maximum_age*/);
108size_t get_content_length(const curlhelp_write_curlbuf *header_buf,
109 const curlhelp_write_curlbuf *body_buf);
110int lookup_host(const char *host, char *buf, size_t buflen, sa_family_t addr_family);
111CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm);
112
113#define INET_ADDR_MAX_SIZE INET6_ADDRSTRLEN
114const char *strrstr2(const char *haystack, const char *needle);
115
116void cleanup(check_curl_global_state global_state);
117
118bool expected_statuscode(const char *reply, const char *statuscodes);
119char *string_statuscode(int major, int minor);
120
121void test_file(char *path);
122mp_subcheck check_curl_certificate_checks(CURL *curl, X509 *cert, int warn_days_till_exp,
123 int crit_days_till_exp);
124char *fmt_url(check_curl_working_state workingState);
diff --git a/plugins/check_curl.d/config.h b/plugins/check_curl.d/config.h
new file mode 100644
index 00000000..f51b2ee9
--- /dev/null
+++ b/plugins/check_curl.d/config.h
@@ -0,0 +1,116 @@
1#pragma once
2
3#include "../../config.h"
4#include "../common.h"
5#include "../../lib/states.h"
6#include "../../lib/thresholds.h"
7#include <stddef.h>
8#include <string.h>
9#include <sys/socket.h>
10#include "curl/curl.h"
11#include "perfdata.h"
12#include "regex.h"
13
14enum {
15 MAX_RE_SIZE = 1024,
16 HTTP_PORT = 80,
17 HTTPS_PORT = 443,
18 MAX_PORT = 65535,
19 DEFAULT_MAX_REDIRS = 15
20};
21
22enum {
23 FOLLOW_HTTP_CURL = 0,
24 FOLLOW_LIBCURL = 1
25};
26
27enum {
28 STICKY_NONE = 0,
29 STICKY_HOST = 1,
30 STICKY_PORT = 2
31};
32
33#define HTTP_EXPECT "HTTP/"
34#define DEFAULT_BUFFER_SIZE 2048
35#define DEFAULT_SERVER_URL "/"
36
37typedef struct {
38 char *server_address;
39 char *server_url;
40 char *host_name;
41
42 char *http_method;
43
44 char *http_post_data;
45
46 unsigned short virtualPort;
47 unsigned short serverPort;
48
49 bool use_ssl;
50 bool no_body;
51} check_curl_working_state;
52
53check_curl_working_state check_curl_working_state_init();
54
55typedef struct {
56 bool automatic_decompression;
57 bool haproxy_protocol;
58 long socket_timeout;
59 sa_family_t sin_family;
60 int curl_http_version;
61 char **http_opt_headers;
62 size_t http_opt_headers_count;
63 int ssl_version;
64 char *client_cert;
65 char *client_privkey;
66 char *ca_cert;
67 bool verify_peer_and_host;
68 char user_agent[DEFAULT_BUFFER_SIZE];
69 char proxy_auth[MAX_INPUT_BUFFER];
70 char user_auth[MAX_INPUT_BUFFER];
71 char *http_content_type;
72 char *cookie_jar_file;
73} check_curl_static_curl_config;
74
75typedef struct {
76 check_curl_working_state initial_config;
77
78 check_curl_static_curl_config curl_config;
79 int max_depth;
80 int followmethod;
81 int followsticky;
82
83 int maximum_age;
84
85 // the original regex string from the command line
86 char regexp[MAX_RE_SIZE];
87
88 // the compiled regex for usage later
89 regex_t compiled_regex;
90
91 mp_state_enum state_regex;
92 bool invert_regex;
93 bool check_cert;
94 bool continue_after_check_cert;
95 int days_till_exp_warn;
96 int days_till_exp_crit;
97 mp_thresholds thlds;
98 mp_range page_length_limits;
99 bool page_length_limits_is_set;
100 struct {
101 char string[MAX_INPUT_BUFFER];
102 bool is_present;
103 } server_expect;
104 char string_expect[MAX_INPUT_BUFFER];
105 char header_expect[MAX_INPUT_BUFFER];
106 mp_state_enum on_redirect_result_state;
107 bool on_redirect_dependent;
108
109 bool show_extended_perfdata;
110 bool show_body;
111
112 bool output_format_is_set;
113 mp_output_format output_format;
114} check_curl_config;
115
116check_curl_config check_curl_config_init();
diff --git a/plugins/check_dbi.c b/plugins/check_dbi.c
index 29c85206..468ded31 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,27 @@ 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*/,
75 double * /*res_val*/, double * /*res_time*/, mp_dbi_metric /*metric*/,
76 mp_dbi_type /*type*/, char * /*np_dbi_query*/);
103 77
104int do_query (dbi_conn, const char **, double *, double *); 78int main(int argc, char **argv) {
105
106int
107main (int argc, char **argv)
108{
109 int status = STATE_UNKNOWN; 79 int status = STATE_UNKNOWN;
110 80
111 dbi_driver driver; 81 dbi_driver driver;
@@ -113,714 +83,762 @@ main (int argc, char **argv)
113 83
114 unsigned int server_version; 84 unsigned int server_version;
115 85
116 struct timeval start_timeval, end_timeval; 86 struct timeval start_timeval;
87 struct timeval end_timeval;
117 double conn_time = 0.0; 88 double conn_time = 0.0;
118 double query_time = 0.0; 89 double query_time = 0.0;
119 90
120 const char *query_val_str = NULL; 91 const char *query_val_str = NULL;
121 double query_val = 0.0; 92 double query_val = 0.0;
122 93
123 int i; 94 setlocale(LC_ALL, "");
124 95 bindtextdomain(PACKAGE, LOCALEDIR);
125 setlocale (LC_ALL, ""); 96 textdomain(PACKAGE);
126 bindtextdomain (PACKAGE, LOCALEDIR);
127 textdomain (PACKAGE);
128 97
129 /* Parse extra opts if any */ 98 /* Parse extra opts if any */
130 argv = np_extra_opts (&argc, argv, progname); 99 argv = np_extra_opts(&argc, argv, progname);
100
101 check_dbi_config_wrapper tmp = process_arguments(argc, argv);
102
103 if (tmp.errorcode == ERROR) {
104 usage4(_("Could not parse arguments"));
105 }
131 106
132 if (process_arguments (argc, argv) == ERROR) 107 const check_dbi_config config = tmp.config;
133 usage4 (_("Could not parse arguments"));
134 108
135 /* Set signal handling and alarm */ 109 /* Set signal handling and alarm */
136 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 110 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
137 usage4 (_("Cannot catch SIGALRM")); 111 usage4(_("Cannot catch SIGALRM"));
138 } 112 }
139 alarm (timeout_interval); 113 alarm(timeout_interval);
140 114
141 if (verbose > 2) 115 if (verbose > 2) {
142 printf ("Initializing DBI\n"); 116 printf("Initializing DBI\n");
117 }
143 118
144 dbi_inst *instance_p = { 0 }; 119 dbi_inst *instance_p = {0};
145 120
146 if (dbi_initialize_r(NULL, instance_p) < 0) { 121 if (dbi_initialize_r(NULL, instance_p) < 0) {
147 printf ("UNKNOWN - failed to initialize DBI; possibly you don't have any drivers installed.\n"); 122 printf(
123 "UNKNOWN - failed to initialize DBI; possibly you don't have any drivers installed.\n");
148 return STATE_UNKNOWN; 124 return STATE_UNKNOWN;
149 } 125 }
150 126
151 if (instance_p == NULL) { 127 if (instance_p == NULL) {
152 printf ("UNKNOWN - failed to initialize DBI.\n"); 128 printf("UNKNOWN - failed to initialize DBI.\n");
153 return STATE_UNKNOWN; 129 return STATE_UNKNOWN;
154 } 130 }
155 131
156 if (verbose) 132 if (verbose) {
157 printf ("Opening DBI driver '%s'\n", np_dbi_driver); 133 printf("Opening DBI driver '%s'\n", config.dbi_driver);
134 }
158 135
159 driver = dbi_driver_open_r(np_dbi_driver, instance_p); 136 driver = dbi_driver_open_r(config.dbi_driver, instance_p);
160 if (! driver) { 137 if (!driver) {
161 printf ("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", 138 printf("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n",
162 np_dbi_driver); 139 config.dbi_driver);
163 140
164 printf ("Known drivers:\n"); 141 printf("Known drivers:\n");
165 for (driver = dbi_driver_list_r(NULL, instance_p); driver; driver = dbi_driver_list_r(driver, instance_p)) { 142 for (driver = dbi_driver_list_r(NULL, instance_p); driver;
166 printf (" - %s\n", dbi_driver_get_name (driver)); 143 driver = dbi_driver_list_r(driver, instance_p)) {
144 printf(" - %s\n", dbi_driver_get_name(driver));
167 } 145 }
168 return STATE_UNKNOWN; 146 return STATE_UNKNOWN;
169 } 147 }
170 148
171 /* make a connection to the database */ 149 /* make a connection to the database */
172 gettimeofday (&start_timeval, NULL); 150 gettimeofday(&start_timeval, NULL);
173 151
174 conn = dbi_conn_open (driver); 152 conn = dbi_conn_open(driver);
175 if (! conn) { 153 if (!conn) {
176 printf ("UNKNOWN - failed top open connection object.\n"); 154 printf("UNKNOWN - failed top open connection object.\n");
177 dbi_conn_close (conn); 155 dbi_conn_close(conn);
178 return STATE_UNKNOWN; 156 return STATE_UNKNOWN;
179 } 157 }
180 158
181 for (i = 0; i < np_dbi_options_num; ++i) { 159 for (size_t i = 0; i < config.dbi_options_num; ++i) {
182 const char *opt; 160 const char *opt;
183 161
184 if (verbose > 1) 162 if (verbose > 1) {
185 printf ("Setting DBI driver option '%s' to '%s'\n", 163 printf("Setting DBI driver option '%s' to '%s'\n", config.dbi_options[i].key,
186 np_dbi_options[i].key, np_dbi_options[i].value); 164 config.dbi_options[i].value);
165 }
187 166
188 if (! dbi_conn_set_option (conn, np_dbi_options[i].key, np_dbi_options[i].value)) 167 if (!dbi_conn_set_option(conn, config.dbi_options[i].key, config.dbi_options[i].value)) {
189 continue; 168 continue;
169 }
190 /* else: status != 0 */ 170 /* else: status != 0 */
191 171
192 np_dbi_print_error (conn, "UNKNOWN - failed to set option '%s' to '%s'", 172 np_dbi_print_error(conn, "UNKNOWN - failed to set option '%s' to '%s'",
193 np_dbi_options[i].key, np_dbi_options[i].value); 173 config.dbi_options[i].key, config.dbi_options[i].value);
194 printf ("Known driver options:\n"); 174 printf("Known driver options:\n");
195 175
196 for (opt = dbi_conn_get_option_list (conn, NULL); opt; 176 for (opt = dbi_conn_get_option_list(conn, NULL); opt;
197 opt = dbi_conn_get_option_list (conn, opt)) { 177 opt = dbi_conn_get_option_list(conn, opt)) {
198 printf (" - %s\n", opt); 178 printf(" - %s\n", opt);
199 } 179 }
200 dbi_conn_close (conn); 180 dbi_conn_close(conn);
201 return STATE_UNKNOWN; 181 return STATE_UNKNOWN;
202 } 182 }
203 183
204 if (host) { 184 if (config.host) {
205 if (verbose > 1) 185 if (verbose > 1) {
206 printf ("Setting DBI driver option 'host' to '%s'\n", host); 186 printf("Setting DBI driver option 'host' to '%s'\n", config.host);
207 dbi_conn_set_option (conn, "host", host); 187 }
188 dbi_conn_set_option(conn, "host", config.host);
208 } 189 }
209 190
210 if (verbose) { 191 if (verbose) {
211 const char *dbname, *host; 192 const char *dbname;
193 const char *host;
212 194
213 dbname = dbi_conn_get_option (conn, "dbname"); 195 dbname = dbi_conn_get_option(conn, "dbname");
214 host = dbi_conn_get_option (conn, "host"); 196 host = dbi_conn_get_option(conn, "host");
215 197
216 if (! dbname) 198 if (!dbname) {
217 dbname = "<unspecified>"; 199 dbname = "<unspecified>";
218 if (! host) 200 }
201 if (!host) {
219 host = "<unspecified>"; 202 host = "<unspecified>";
203 }
220 204
221 printf ("Connecting to database '%s' at host '%s'\n", 205 printf("Connecting to database '%s' at host '%s'\n", dbname, host);
222 dbname, host);
223 } 206 }
224 207
225 if (dbi_conn_connect (conn) < 0) { 208 if (dbi_conn_connect(conn) < 0) {
226 np_dbi_print_error (conn, "UNKNOWN - failed to connect to database"); 209 np_dbi_print_error(conn, "UNKNOWN - failed to connect to database");
227 return STATE_UNKNOWN; 210 return STATE_UNKNOWN;
228 } 211 }
229 212
230 gettimeofday (&end_timeval, NULL); 213 gettimeofday(&end_timeval, NULL);
231 conn_time = timediff (start_timeval, end_timeval); 214 conn_time = timediff(start_timeval, end_timeval);
232 215
233 server_version = dbi_conn_get_engine_version (conn); 216 server_version = dbi_conn_get_engine_version(conn);
234 if (verbose) 217 if (verbose) {
235 printf ("Connected to server version %u\n", server_version); 218 printf("Connected to server version %u\n", server_version);
219 }
236 220
237 if (metric == METRIC_SERVER_VERSION) 221 if (config.metric == METRIC_SERVER_VERSION) {
238 status = get_status (server_version, dbi_thresholds); 222 status = get_status(server_version, config.dbi_thresholds);
223 }
239 224
240 if (verbose) 225 if (verbose) {
241 printf ("Time elapsed: %f\n", conn_time); 226 printf("Time elapsed: %f\n", conn_time);
227 }
242 228
243 if (metric == METRIC_CONN_TIME) 229 if (config.metric == METRIC_CONN_TIME) {
244 status = get_status (conn_time, dbi_thresholds); 230 status = get_status(conn_time, config.dbi_thresholds);
231 }
245 232
246 /* select a database */ 233 /* select a database */
247 if (np_dbi_database) { 234 if (config.dbi_database) {
248 if (verbose > 1) 235 if (verbose > 1) {
249 printf ("Selecting database '%s'\n", np_dbi_database); 236 printf("Selecting database '%s'\n", config.dbi_database);
237 }
250 238
251 if (dbi_conn_select_db (conn, np_dbi_database)) { 239 if (dbi_conn_select_db(conn, config.dbi_database)) {
252 np_dbi_print_error (conn, "UNKNOWN - failed to select database '%s'", 240 np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'",
253 np_dbi_database); 241 config.dbi_database);
254 return STATE_UNKNOWN; 242 return STATE_UNKNOWN;
255 } 243 }
256 } 244 }
257 245
258 if (np_dbi_query) { 246 if (config.dbi_query) {
259 /* execute query */ 247 /* execute query */
260 status = do_query (conn, &query_val_str, &query_val, &query_time); 248 status = do_query(conn, &query_val_str, &query_val, &query_time, config.metric, config.type,
261 if (status != STATE_OK) 249 config.dbi_query);
250 if (status != STATE_OK) {
262 /* do_query prints an error message in this case */ 251 /* do_query prints an error message in this case */
263 return status; 252 return status;
253 }
264 254
265 if (metric == METRIC_QUERY_RESULT) { 255 if (config.metric == METRIC_QUERY_RESULT) {
266 if (expect) { 256 if (config.expect) {
267 if ((! query_val_str) || strcmp (query_val_str, expect)) 257 if ((!query_val_str) || strcmp(query_val_str, config.expect)) {
268 status = STATE_CRITICAL; 258 status = STATE_CRITICAL;
269 else 259 } else {
270 status = STATE_OK; 260 status = STATE_OK;
271 } 261 }
272 else if (expect_re_str) { 262 } else if (config.expect_re_str) {
273 int err; 263 int err;
274 264
275 err = regexec (&expect_re, query_val_str, 0, NULL, /* flags = */ 0); 265 regex_t expect_re = {};
276 if (! err) 266 err = regexec(&expect_re, query_val_str, 0, NULL, /* flags = */ 0);
267 if (!err) {
277 status = STATE_OK; 268 status = STATE_OK;
278 else if (err == REG_NOMATCH) 269 } else if (err == REG_NOMATCH) {
279 status = STATE_CRITICAL; 270 status = STATE_CRITICAL;
280 else { 271 } else {
281 char errmsg[1024]; 272 char errmsg[1024];
282 regerror (err, &expect_re, errmsg, sizeof (errmsg)); 273 regerror(err, &expect_re, errmsg, sizeof(errmsg));
283 printf ("ERROR - failed to execute regular expression: %s\n", 274 printf("ERROR - failed to execute regular expression: %s\n", errmsg);
284 errmsg);
285 status = STATE_CRITICAL; 275 status = STATE_CRITICAL;
286 } 276 }
277 } else {
278 status = get_status(query_val, config.dbi_thresholds);
287 } 279 }
288 else 280 } else if (config.metric == METRIC_QUERY_TIME) {
289 status = get_status (query_val, dbi_thresholds); 281 status = get_status(query_time, config.dbi_thresholds);
290 } 282 }
291 else if (metric == METRIC_QUERY_TIME)
292 status = get_status (query_time, dbi_thresholds);
293 } 283 }
294 284
295 if (verbose) 285 if (verbose) {
296 printf("Closing connection\n"); 286 printf("Closing connection\n");
297 dbi_conn_close (conn); 287 }
288 dbi_conn_close(conn);
298 289
299 /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error 290 /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error
300 * which should have been reported and handled (abort) before 291 * which should have been reported and handled (abort) before
301 * ... unless we expected a string to be returned */ 292 * ... unless we expected a string to be returned */
302 assert ((metric != METRIC_QUERY_RESULT) || (! isnan (query_val)) 293 assert((config.metric != METRIC_QUERY_RESULT) || (!isnan(query_val)) ||
303 || (type == TYPE_STRING)); 294 (config.type == TYPE_STRING));
304 295
305 assert ((type != TYPE_STRING) || (expect || expect_re_str)); 296 assert((config.type != TYPE_STRING) || (config.expect || config.expect_re_str));
306 297
307 printf ("%s - connection time: %fs", state_text (status), conn_time); 298 printf("%s - connection time: %fs", state_text(status), conn_time);
308 if (np_dbi_query) { 299 if (config.dbi_query) {
309 if (type == TYPE_STRING) { 300 if (config.type == TYPE_STRING) {
310 assert (expect || expect_re_str); 301 assert(config.expect || config.expect_re_str);
311 printf (", '%s' returned '%s' in %fs", np_dbi_query, 302 printf(", '%s' returned '%s' in %fs", config.dbi_query,
312 query_val_str ? query_val_str : "<nothing>", query_time); 303 query_val_str ? query_val_str : "<nothing>", query_time);
313 if (status != STATE_OK) { 304 if (status != STATE_OK) {
314 if (expect) 305 if (config.expect) {
315 printf (" (expected '%s')", expect); 306 printf(" (expected '%s')", config.expect);
316 else if (expect_re_str) 307 } else if (config.expect_re_str) {
317 printf (" (expected regex /%s/%s)", expect_re_str, 308 printf(" (expected regex /%s/%s)", config.expect_re_str,
318 ((expect_re_cflags & REG_ICASE) ? "i" : "")); 309 ((config.expect_re_cflags & REG_ICASE) ? "i" : ""));
310 }
319 } 311 }
312 } else if (isnan(query_val)) {
313 printf(", '%s' query execution time: %fs", config.dbi_query, query_time);
314 } else {
315 printf(", '%s' returned %f in %fs", config.dbi_query, query_val, query_time);
320 } 316 }
321 else if (isnan (query_val)) 317 }
322 printf (", '%s' query execution time: %fs", np_dbi_query, query_time); 318
323 else 319 printf(
324 printf (", '%s' returned %f in %fs", np_dbi_query, query_val, query_time); 320 " | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time,
325 } 321 ((config.metric == METRIC_CONN_TIME) && config.warning_range) ? config.warning_range : "",
326 322 ((config.metric == METRIC_CONN_TIME) && config.critical_range) ? config.critical_range : "",
327 printf (" | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time, 323 server_version,
328 ((metric == METRIC_CONN_TIME) && warning_range) ? warning_range : "", 324 ((config.metric == METRIC_SERVER_VERSION) && config.warning_range) ? config.warning_range
329 ((metric == METRIC_CONN_TIME) && critical_range) ? critical_range : "", 325 : "",
330 server_version, 326 ((config.metric == METRIC_SERVER_VERSION) && config.critical_range) ? config.critical_range
331 ((metric == METRIC_SERVER_VERSION) && warning_range) ? warning_range : "", 327 : "");
332 ((metric == METRIC_SERVER_VERSION) && critical_range) ? critical_range : ""); 328 if (config.dbi_query) {
333 if (np_dbi_query) { 329 if (!isnan(query_val)) { /* this is also true when -e is used */
334 if (! isnan (query_val)) /* this is also true when -e is used */ 330 printf(" query=%f;%s;%s;;", query_val,
335 printf (" query=%f;%s;%s;;", query_val, 331 ((config.metric == METRIC_QUERY_RESULT) && config.warning_range)
336 ((metric == METRIC_QUERY_RESULT) && warning_range) ? warning_range : "", 332 ? config.warning_range
337 ((metric == METRIC_QUERY_RESULT) && critical_range) ? critical_range : ""); 333 : "",
338 printf (" querytime=%fs;%s;%s;0;", query_time, 334 ((config.metric == METRIC_QUERY_RESULT) && config.critical_range)
339 ((metric == METRIC_QUERY_TIME) && warning_range) ? warning_range : "", 335 ? config.critical_range
340 ((metric == METRIC_QUERY_TIME) && critical_range) ? critical_range : ""); 336 : "");
341 } 337 }
342 printf ("\n"); 338 printf(" querytime=%fs;%s;%s;0;", query_time,
339 ((config.metric == METRIC_QUERY_TIME) && config.warning_range) ? config.warning_range
340 : "",
341 ((config.metric == METRIC_QUERY_TIME) && config.critical_range)
342 ? config.critical_range
343 : "");
344 }
345 printf("\n");
343 return status; 346 return status;
344} 347}
345 348
346/* process command-line arguments */ 349/* process command-line arguments */
347int 350check_dbi_config_wrapper process_arguments(int argc, char **argv) {
348process_arguments (int argc, char **argv)
349{
350 int c;
351 351
352 int option = 0; 352 int option = 0;
353 static struct option longopts[] = { 353 static struct option longopts[] = {STD_LONG_OPTS,
354 STD_LONG_OPTS, 354
355 355 {"expect", required_argument, 0, 'e'},
356 {"expect", required_argument, 0, 'e'}, 356 {"regex", required_argument, 0, 'r'},
357 {"regex", required_argument, 0, 'r'}, 357 {"regexi", required_argument, 0, 'R'},
358 {"regexi", required_argument, 0, 'R'}, 358 {"metric", required_argument, 0, 'm'},
359 {"metric", required_argument, 0, 'm'}, 359 {"driver", required_argument, 0, 'd'},
360 {"driver", required_argument, 0, 'd'}, 360 {"option", required_argument, 0, 'o'},
361 {"option", required_argument, 0, 'o'}, 361 {"query", required_argument, 0, 'q'},
362 {"query", required_argument, 0, 'q'}, 362 {"database", required_argument, 0, 'D'},
363 {"database", required_argument, 0, 'D'}, 363 {0, 0, 0, 0}};
364 {0, 0, 0, 0} 364
365 check_dbi_config_wrapper result = {
366 .config = check_dbi_config_init(),
367 .errorcode = OK,
365 }; 368 };
369 int option_char;
370 while (true) {
371 option_char = getopt_long(argc, argv, "Vvht:c:w:e:r:R:m:H:d:o:q:D:", longopts, &option);
366 372
367 while (1) { 373 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; 374 break;
375 }
373 376
374 switch (c) { 377 switch (option_char) {
375 case '?': /* usage */ 378 case '?': /* usage */
376 usage5 (); 379 usage5();
377 case 'h': /* help */ 380 case 'h': /* help */
378 print_help (); 381 print_help();
379 exit (STATE_UNKNOWN); 382 exit(STATE_UNKNOWN);
380 case 'V': /* version */ 383 case 'V': /* version */
381 print_revision (progname, NP_VERSION); 384 print_revision(progname, NP_VERSION);
382 exit (STATE_UNKNOWN); 385 exit(STATE_UNKNOWN);
383 386
384 case 'c': /* critical range */ 387 case 'c': /* critical range */
385 critical_range = optarg; 388 result.config.critical_range = optarg;
386 type = TYPE_NUMERIC; 389 result.config.type = TYPE_NUMERIC;
387 break; 390 break;
388 case 'w': /* warning range */ 391 case 'w': /* warning range */
389 warning_range = optarg; 392 result.config.warning_range = optarg;
390 type = TYPE_NUMERIC; 393 result.config.type = TYPE_NUMERIC;
391 break; 394 break;
392 case 'e': 395 case 'e':
393 expect = optarg; 396 result.config.expect = optarg;
394 type = TYPE_STRING; 397 result.config.type = TYPE_STRING;
395 break; 398 break;
396 case 'R': 399 case 'R':
397 expect_re_cflags = REG_ICASE; 400 result.config.expect_re_cflags = REG_ICASE;
398 /* fall through */ 401 /* fall through */
399 case 'r': 402 case 'r': {
400 { 403 int err;
401 int err; 404
402 405 result.config.expect_re_cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
403 expect_re_cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 406 result.config.expect_re_str = optarg;
404 expect_re_str = optarg; 407 result.config.type = TYPE_STRING;
405 type = TYPE_STRING; 408
406 409 regex_t expect_re = {};
407 err = regcomp (&expect_re, expect_re_str, expect_re_cflags); 410 err = regcomp(&expect_re, result.config.expect_re_str, result.config.expect_re_cflags);
408 if (err) { 411 if (err) {
409 char errmsg[1024]; 412 char errmsg[1024];
410 regerror (err, &expect_re, errmsg, sizeof (errmsg)); 413 regerror(err, &expect_re, errmsg, sizeof(errmsg));
411 printf ("ERROR - failed to compile regular expression: %s\n", 414 printf("ERROR - failed to compile regular expression: %s\n", errmsg);
412 errmsg); 415
413 return ERROR; 416 result.errorcode = ERROR;
414 } 417 return result;
415 break;
416 } 418 }
419 break;
420 }
417 421
418 case 'm': 422 case 'm':
419 if (! strcasecmp (optarg, "CONN_TIME")) 423 if (!strcasecmp(optarg, "CONN_TIME")) {
420 metric = METRIC_CONN_TIME; 424 result.config.metric = METRIC_CONN_TIME;
421 else if (! strcasecmp (optarg, "SERVER_VERSION")) 425 } else if (!strcasecmp(optarg, "SERVER_VERSION")) {
422 metric = METRIC_SERVER_VERSION; 426 result.config.metric = METRIC_SERVER_VERSION;
423 else if (! strcasecmp (optarg, "QUERY_RESULT")) 427 } else if (!strcasecmp(optarg, "QUERY_RESULT")) {
424 metric = METRIC_QUERY_RESULT; 428 result.config.metric = METRIC_QUERY_RESULT;
425 else if (! strcasecmp (optarg, "QUERY_TIME")) 429 } else if (!strcasecmp(optarg, "QUERY_TIME")) {
426 metric = METRIC_QUERY_TIME; 430 result.config.metric = METRIC_QUERY_TIME;
427 else 431 } else {
428 usage2 (_("Invalid metric"), optarg); 432 usage2(_("Invalid metric"), optarg);
433 }
429 break; 434 break;
430 case 't': /* timeout */ 435 case 't': /* timeout */
431 if (!is_intnonneg (optarg)) 436 if (!is_intnonneg(optarg)) {
432 usage2 (_("Timeout interval must be a positive integer"), optarg); 437 usage2(_("Timeout interval must be a positive integer"), optarg);
433 else 438 } else {
434 timeout_interval = atoi (optarg); 439 timeout_interval = atoi(optarg);
440 }
435 441
436 break; 442 break;
437 case 'H': /* host */ 443 case 'H': /* host */
438 if (!is_host (optarg)) 444 if (!is_host(optarg)) {
439 usage2 (_("Invalid hostname/address"), optarg); 445 usage2(_("Invalid hostname/address"), optarg);
440 else 446 } else {
441 host = optarg; 447 result.config.host = optarg;
448 }
442 break; 449 break;
443 case 'v': 450 case 'v':
444 verbose++; 451 verbose++;
445 break; 452 break;
446 453
447 case 'd': 454 case 'd':
448 np_dbi_driver = optarg; 455 result.config.dbi_driver = optarg;
449 break; 456 break;
450 case 'o': 457 case 'o': {
451 { 458 driver_option_t *new = NULL;
452 driver_option_t *new;
453
454 char *k, *v;
455 459
456 k = optarg; 460 char *key = optarg;
457 v = strchr (k, (int)'='); 461 char *value = strchr(key, '=');
458 462
459 if (! v) 463 if (!value) {
460 usage2 (_("Option must be '<key>=<value>'"), optarg); 464 usage2(_("Option must be '<key>=<value>'"), optarg);
465 }
461 466
462 *v = '\0'; 467 *value = '\0';
463 ++v; 468 ++value;
464 469
465 new = realloc (np_dbi_options, 470 new = realloc(result.config.dbi_options,
466 (np_dbi_options_num + 1) * sizeof (*new)); 471 (result.config.dbi_options_num + 1) * sizeof(*new));
467 if (! new) { 472 if (!new) {
468 printf ("UNKNOWN - failed to reallocate memory\n"); 473 printf("UNKNOWN - failed to reallocate memory\n");
469 exit (STATE_UNKNOWN); 474 exit(STATE_UNKNOWN);
470 } 475 }
471 476
472 np_dbi_options = new; 477 result.config.dbi_options = new;
473 new = np_dbi_options + np_dbi_options_num; 478 new = result.config.dbi_options + result.config.dbi_options_num;
474 ++np_dbi_options_num; 479 result.config.dbi_options_num++;
475 480
476 new->key = k; 481 new->key = key;
477 new->value = v; 482 new->value = value;
478 } 483 } break;
479 break;
480 case 'q': 484 case 'q':
481 np_dbi_query = optarg; 485 result.config.dbi_query = optarg;
482 break; 486 break;
483 case 'D': 487 case 'D':
484 np_dbi_database = optarg; 488 result.config.dbi_database = optarg;
485 break; 489 break;
486 } 490 }
487 } 491 }
488 492
489 set_thresholds (&dbi_thresholds, warning_range, critical_range); 493 set_thresholds(&result.config.dbi_thresholds, result.config.warning_range,
494 result.config.critical_range);
490 495
491 return validate_arguments (); 496 return validate_arguments(result);
492} 497}
493 498
494int 499check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper config_wrapper) {
495validate_arguments () 500 if (!config_wrapper.config.dbi_driver) {
496{ 501 usage("Must specify a DBI driver");
497 if (! np_dbi_driver) 502 }
498 usage ("Must specify a DBI driver");
499 503
500 if (((metric == METRIC_QUERY_RESULT) || (metric == METRIC_QUERY_TIME)) 504 if (((config_wrapper.config.metric == METRIC_QUERY_RESULT) ||
501 && (! np_dbi_query)) 505 (config_wrapper.config.metric == METRIC_QUERY_TIME)) &&
502 usage ("Must specify a query to execute (metric == QUERY_RESULT)"); 506 (!config_wrapper.config.dbi_query)) {
507 usage("Must specify a query to execute (metric == QUERY_RESULT)");
508 }
503 509
504 if ((metric != METRIC_CONN_TIME) 510 if ((config_wrapper.config.metric != METRIC_CONN_TIME) &&
505 && (metric != METRIC_SERVER_VERSION) 511 (config_wrapper.config.metric != METRIC_SERVER_VERSION) &&
506 && (metric != METRIC_QUERY_RESULT) 512 (config_wrapper.config.metric != METRIC_QUERY_RESULT) &&
507 && (metric != METRIC_QUERY_TIME)) 513 (config_wrapper.config.metric != METRIC_QUERY_TIME)) {
508 usage ("Invalid metric specified"); 514 usage("Invalid metric specified");
515 }
509 516
510 if (expect && (warning_range || critical_range || expect_re_str)) 517 if (config_wrapper.config.expect &&
511 usage ("Do not mix -e and -w/-c/-r/-R"); 518 (config_wrapper.config.warning_range || config_wrapper.config.critical_range ||
519 config_wrapper.config.expect_re_str)) {
520 usage("Do not mix -e and -w/-c/-r/-R");
521 }
512 522
513 if (expect_re_str && (warning_range || critical_range || expect)) 523 if (config_wrapper.config.expect_re_str &&
514 usage ("Do not mix -r/-R and -w/-c/-e"); 524 (config_wrapper.config.warning_range || config_wrapper.config.critical_range ||
525 config_wrapper.config.expect)) {
526 usage("Do not mix -r/-R and -w/-c/-e");
527 }
515 528
516 if (expect && (metric != METRIC_QUERY_RESULT)) 529 if (config_wrapper.config.expect && (config_wrapper.config.metric != METRIC_QUERY_RESULT)) {
517 usage ("Option -e requires metric QUERY_RESULT"); 530 usage("Option -e requires metric QUERY_RESULT");
531 }
518 532
519 if (expect_re_str && (metric != METRIC_QUERY_RESULT)) 533 if (config_wrapper.config.expect_re_str &&
520 usage ("Options -r/-R require metric QUERY_RESULT"); 534 (config_wrapper.config.metric != METRIC_QUERY_RESULT)) {
535 usage("Options -r/-R require metric QUERY_RESULT");
536 }
521 537
522 return OK; 538 config_wrapper.errorcode = OK;
539 return config_wrapper;
523} 540}
524 541
525void 542void print_help(void) {
526print_help (void) 543 print_revision(progname, NP_VERSION);
527{
528 print_revision (progname, NP_VERSION);
529 544
530 printf (COPYRIGHT, copyright, email); 545 printf(COPYRIGHT, copyright, email);
531 546
532 printf (_("This program connects to an (SQL) database using DBI and checks the\n" 547 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" 548 "specified metric against threshold levels. The default metric is\n"
534 "the result of the specified query.\n")); 549 "the result of the specified query.\n"));
535 550
536 printf ("\n\n"); 551 printf("\n\n");
537 552
538 print_usage (); 553 print_usage();
539 554
540 printf (UT_HELP_VRSN); 555 printf(UT_HELP_VRSN);
541/* include this conditionally to avoid 'zero-length printf format string' 556/* include this conditionally to avoid 'zero-length printf format string'
542 * compiler warnings */ 557 * compiler warnings */
543#ifdef NP_EXTRA_OPTS 558#ifdef NP_EXTRA_OPTS
544 printf (UT_EXTRA_OPTS); 559 printf(UT_EXTRA_OPTS);
545#endif 560#endif
546 printf ("\n"); 561 printf("\n");
547 562
548 printf (" %s\n", "-d, --driver=STRING"); 563 printf(" %s\n", "-d, --driver=STRING");
549 printf (" %s\n", _("DBI driver to use")); 564 printf(" %s\n", _("DBI driver to use"));
550 printf (" %s\n", "-o, --option=STRING"); 565 printf(" %s\n", "-o, --option=STRING");
551 printf (" %s\n", _("DBI driver options")); 566 printf(" %s\n", _("DBI driver options"));
552 printf (" %s\n", "-q, --query=STRING"); 567 printf(" %s\n", "-q, --query=STRING");
553 printf (" %s\n", _("query to execute")); 568 printf(" %s\n", _("query to execute"));
554 printf ("\n"); 569 printf(" %s\n", "-H STRING");
555 570 printf(" %s\n", _("target database host"));
556 printf (UT_WARN_CRIT_RANGE); 571 printf("\n");
557 printf (" %s\n", "-e, --expect=STRING"); 572
558 printf (" %s\n", _("String to expect as query result")); 573 printf(UT_WARN_CRIT_RANGE);
559 printf (" %s\n", _("Do not mix with -w, -c, -r, or -R!")); 574 printf(" %s\n", "-e, --expect=STRING");
560 printf (" %s\n", "-r, --regex=REGEX"); 575 printf(" %s\n", _("String to expect as query result"));
561 printf (" %s\n", _("Extended POSIX regular expression to check query result against")); 576 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!")); 577 printf(" %s\n", "-r, --regex=REGEX");
563 printf (" %s\n", "-R, --regexi=REGEX"); 578 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")); 579 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!")); 580 printf(" %s\n", "-R, --regexi=REGEX");
566 printf (" %s\n", "-m, --metric=METRIC"); 581 printf(" %s\n", _("Case-insensitive extended POSIX regex to check query result against"));
567 printf (" %s\n", _("Metric to check thresholds against. Available metrics:")); 582 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")); 583 printf(" %s\n", "-m, --metric=METRIC");
569 printf (" QUERY_RESULT - %s\n", _("result (first column of first row) of the query")); 584 printf(" %s\n", _("Metric to check thresholds against. Available metrics:"));
570 printf (" QUERY_TIME - %s\n", _("time used to execute the query")); 585 printf(" CONN_TIME - %s\n", _("time used for setting up the database connection"));
571 printf (" %s\n", _("(ignore the query result)")); 586 printf(" QUERY_RESULT - %s\n", _("result (first column of first row) of the query"));
572 printf ("\n"); 587 printf(" QUERY_TIME - %s\n", _("time used to execute the query"));
573 588 printf(" %s\n", _("(ignore the query result)"));
574 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 589 printf("\n");
575 590
576 printf (UT_VERBOSE); 591 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
577 592
578 printf ("\n"); 593 printf(UT_VERBOSE);
579 printf (" %s\n", _("A DBI driver (-d option) is required. If the specified metric operates")); 594
580 printf (" %s\n\n", _("on a query, one has to be specified (-q option).")); 595 printf("\n");
581 596 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,")); 597 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")); 598
584 printf (" %s\n", _("result will be parsed and, in QUERY_RESULT mode, compared with the")); 599 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")); 600 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).")); 601 printf(" %s\n", _("result will be parsed and, in QUERY_RESULT mode, compared with the"));
587 602 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")); 603 printf(" %s\n\n", _("(strings representing numbers are fine)."));
589 printf (" %s\n", _("driver. See its documentation at http://libdbi-drivers.sourceforge.net/")); 604
590 printf (" %s\n\n", _("for details.")); 605 printf(" %s\n", _("The number and type of required DBI driver options depends on the actual"));
591 606 printf(" %s\n", _("driver. See its documentation at http://libdbi-drivers.sourceforge.net/"));
592 printf (" %s\n", _("Examples:")); 607 printf(" %s\n\n", _("for details."));
593 printf (" check_dbi -d pgsql -o username=postgres -m QUERY_RESULT \\\n"); 608
594 printf (" -q 'SELECT COUNT(*) FROM pg_stat_activity' -w 5 -c 10\n"); 609 printf(" %s\n", _("Examples:"));
595 printf (" Warning if more than five connections; critical if more than ten.\n\n"); 610 printf(" check_dbi -d pgsql -o username=postgres -m QUERY_RESULT \\\n");
596 611 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"); 612 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"); 613
599 printf (" Warning if less than 5 or more than 20 users are logged in; critical\n"); 614 printf(" check_dbi -d mysql -H localhost -o username=user -o password=secret \\\n");
600 printf (" if more than 50 users.\n\n"); 615 printf(" -q 'SELECT COUNT(*) FROM logged_in_users -w 5:20 -c 0:50\n");
601 616 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"); 617 printf(" if more than 50 users.\n\n");
603 printf (" -m CONN_TIME -w 0.5 -c 2\n"); 618
604 printf (" Warning if connecting to the database takes more than half of a second;\n"); 619 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"); 620 printf(" -m CONN_TIME -w 0.5 -c 2\n");
606 621 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"); 622 printf(" critical if it takes more than 2 seconds.\n\n");
608 printf (" -q 'SELECT concat(@@version, \" \", @@version_comment)' \\\n"); 623
609 printf (" -r '^5\\.[01].*MySQL Enterprise Server'\n"); 624 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"); 625 printf(" -q 'SELECT concat(@@version, \" \", @@version_comment)' \\\n");
611 printf (" version 5.0.x or 5.1.x.\n\n"); 626 printf(" -r '^5\\.[01].*MySQL Enterprise Server'\n");
612 627 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"); 628 printf(" version 5.0.x or 5.1.x.\n\n");
614 printf (" -w 090000:090099 -c 090000:090199\n"); 629
615 printf (" Warn if the PostgreSQL server version is not 9.0.x; critical if the version\n"); 630 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"); 631 printf(" -w 090000:090099 -c 090000:090199\n");
617 632 printf(" Warn if the PostgreSQL server version is not 9.0.x; critical if the version\n");
618 printf (UT_SUPPORT); 633 printf(" is less than 9.x or higher than 9.1.x.\n");
634
635 printf(UT_SUPPORT);
619} 636}
620 637
621void 638void print_usage(void) {
622print_usage (void) 639 printf("%s\n", _("Usage:"));
623{ 640 printf("%s -d <DBI driver> [-o <DBI driver option> [...]] [-q <query>]\n", progname);
624 printf ("%s\n", _("Usage:")); 641 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); 642 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} 643}
629 644
630#define CHECK_IGNORE_ERROR(s) \ 645const char *get_field_str(dbi_conn conn, dbi_result res, unsigned short field_type,
631 do { \ 646 mp_dbi_metric metric, mp_dbi_type type) {
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; 647 const char *str;
640 648
641 if (field_type != DBI_TYPE_STRING) { 649 if (field_type != DBI_TYPE_STRING) {
642 printf ("CRITICAL - result value is not a string\n"); 650 printf("CRITICAL - result value is not a string\n");
643 return NULL; 651 return NULL;
644 } 652 }
645 653
646 str = dbi_result_get_string_idx (res, 1); 654 str = dbi_result_get_string_idx(res, 1);
647 if ((! str) || (strcmp (str, "ERROR") == 0)) { 655 if ((!str) || (strcmp(str, "ERROR") == 0)) {
648 CHECK_IGNORE_ERROR (NULL); 656 if (metric != METRIC_QUERY_RESULT) {
649 np_dbi_print_error (conn, "CRITICAL - failed to fetch string value"); 657 return NULL;
658 }
659 np_dbi_print_error(conn, "CRITICAL - failed to fetch string value");
650 return NULL; 660 return NULL;
651 } 661 }
652 662
653 if ((verbose && (type == TYPE_STRING)) || (verbose > 2)) 663 if ((verbose && (type == TYPE_STRING)) || (verbose > 2)) {
654 printf ("Query returned string '%s'\n", str); 664 printf("Query returned string '%s'\n", str);
665 }
655 return str; 666 return str;
656} 667}
657 668
658double 669double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type, mp_dbi_metric metric,
659get_field (dbi_conn conn, dbi_result res, unsigned short *field_type) 670 mp_dbi_type type) {
660{
661 double val = NAN; 671 double val = NAN;
662 672
663 if (*field_type == DBI_TYPE_INTEGER) { 673 if (*field_type == DBI_TYPE_INTEGER) {
664 val = (double)dbi_result_get_longlong_idx (res, 1); 674 val = (double)dbi_result_get_longlong_idx(res, 1);
665 } 675 } else if (*field_type == DBI_TYPE_DECIMAL) {
666 else if (*field_type == DBI_TYPE_DECIMAL) { 676 val = dbi_result_get_double_idx(res, 1);
667 val = dbi_result_get_double_idx (res, 1); 677 } else if (*field_type == DBI_TYPE_STRING) {
668 }
669 else if (*field_type == DBI_TYPE_STRING) {
670 const char *val_str; 678 const char *val_str;
671 char *endptr = NULL; 679 char *endptr = NULL;
672 680
673 val_str = get_field_str (conn, res, *field_type); 681 val_str = get_field_str(conn, res, *field_type, metric, type);
674 if (! val_str) { 682 if (!val_str) {
675 CHECK_IGNORE_ERROR (NAN); 683 if (metric != METRIC_QUERY_RESULT) {
684 return NAN;
685 }
676 *field_type = DBI_TYPE_ERROR; 686 *field_type = DBI_TYPE_ERROR;
677 return NAN; 687 return NAN;
678 } 688 }
679 689
680 val = strtod (val_str, &endptr); 690 val = strtod(val_str, &endptr);
681 if (endptr == val_str) { 691 if (endptr == val_str) {
682 CHECK_IGNORE_ERROR (NAN); 692 if (metric != METRIC_QUERY_RESULT) {
683 printf ("CRITICAL - result value is not a numeric: %s\n", val_str); 693 return NAN;
694 }
695 printf("CRITICAL - result value is not a numeric: %s\n", val_str);
684 *field_type = DBI_TYPE_ERROR; 696 *field_type = DBI_TYPE_ERROR;
685 return NAN; 697 return NAN;
686 } 698 }
687 else if ((endptr != NULL) && (*endptr != '\0')) { 699 if ((endptr != NULL) && (*endptr != '\0')) {
688 if (verbose) 700 if (verbose) {
689 printf ("Garbage after value: %s\n", endptr); 701 printf("Garbage after value: %s\n", endptr);
702 }
690 } 703 }
691 } 704 } else {
692 else { 705 if (metric != METRIC_QUERY_RESULT) {
693 CHECK_IGNORE_ERROR (NAN); 706 return NAN;
694 printf ("CRITICAL - cannot parse value of type %s (%i)\n", 707 }
695 (*field_type == DBI_TYPE_BINARY) 708 printf("CRITICAL - cannot parse value of type %s (%i)\n",
696 ? "BINARY" 709 (*field_type == DBI_TYPE_BINARY) ? "BINARY"
697 : (*field_type == DBI_TYPE_DATETIME) 710 : (*field_type == DBI_TYPE_DATETIME) ? "DATETIME"
698 ? "DATETIME" 711 : "<unknown>",
699 : "<unknown>", 712 *field_type);
700 *field_type);
701 *field_type = DBI_TYPE_ERROR; 713 *field_type = DBI_TYPE_ERROR;
702 return NAN; 714 return NAN;
703 } 715 }
704 return val; 716 return val;
705} 717}
706 718
707double 719mp_state_enum get_query_result(dbi_conn conn, dbi_result res, const char **res_val_str,
708get_query_result (dbi_conn conn, dbi_result res, const char **res_val_str, double *res_val) 720 double *res_val, mp_dbi_metric metric, mp_dbi_type type) {
709{
710 unsigned short field_type; 721 unsigned short field_type;
711 double val = NAN; 722 double val = NAN;
712 723
713 if (dbi_result_get_numrows (res) == DBI_ROW_ERROR) { 724 if (dbi_result_get_numrows(res) == DBI_ROW_ERROR) {
714 CHECK_IGNORE_ERROR (STATE_OK); 725 if (metric != METRIC_QUERY_RESULT) {
715 np_dbi_print_error (conn, "CRITICAL - failed to fetch rows"); 726 return STATE_OK;
727 }
728 np_dbi_print_error(conn, "CRITICAL - failed to fetch rows");
716 return STATE_CRITICAL; 729 return STATE_CRITICAL;
717 } 730 }
718 731
719 if (dbi_result_get_numrows (res) < 1) { 732 if (dbi_result_get_numrows(res) < 1) {
720 CHECK_IGNORE_ERROR (STATE_OK); 733 if (metric != METRIC_QUERY_RESULT) {
721 printf ("WARNING - no rows returned\n"); 734 return STATE_OK;
735 }
736 printf("WARNING - no rows returned\n");
722 return STATE_WARNING; 737 return STATE_WARNING;
723 } 738 }
724 739
725 if (dbi_result_get_numfields (res) == DBI_FIELD_ERROR) { 740 if (dbi_result_get_numfields(res) == DBI_FIELD_ERROR) {
726 CHECK_IGNORE_ERROR (STATE_OK); 741 if (metric != METRIC_QUERY_RESULT) {
727 np_dbi_print_error (conn, "CRITICAL - failed to fetch fields"); 742 return STATE_OK;
743 }
744 np_dbi_print_error(conn, "CRITICAL - failed to fetch fields");
728 return STATE_CRITICAL; 745 return STATE_CRITICAL;
729 } 746 }
730 747
731 if (dbi_result_get_numfields (res) < 1) { 748 if (dbi_result_get_numfields(res) < 1) {
732 CHECK_IGNORE_ERROR (STATE_OK); 749 if (metric != METRIC_QUERY_RESULT) {
733 printf ("WARNING - no fields returned\n"); 750 return STATE_OK;
751 }
752 printf("WARNING - no fields returned\n");
734 return STATE_WARNING; 753 return STATE_WARNING;
735 } 754 }
736 755
737 if (dbi_result_first_row (res) != 1) { 756 if (dbi_result_first_row(res) != 1) {
738 CHECK_IGNORE_ERROR (STATE_OK); 757 if (metric != METRIC_QUERY_RESULT) {
739 np_dbi_print_error (conn, "CRITICAL - failed to fetch first row"); 758 return STATE_OK;
759 }
760 np_dbi_print_error(conn, "CRITICAL - failed to fetch first row");
740 return STATE_CRITICAL; 761 return STATE_CRITICAL;
741 } 762 }
742 763
743 field_type = dbi_result_get_field_type_idx (res, 1); 764 field_type = dbi_result_get_field_type_idx(res, 1);
744 if (field_type != DBI_TYPE_ERROR) { 765 if (field_type != DBI_TYPE_ERROR) {
745 if (type == TYPE_STRING) 766 if (type == TYPE_STRING) {
746 /* the value will be freed in dbi_result_free */ 767 /* the value will be freed in dbi_result_free */
747 *res_val_str = strdup (get_field_str (conn, res, field_type)); 768 *res_val_str = strdup(get_field_str(conn, res, field_type, metric, type));
748 else 769 } else {
749 val = get_field (conn, res, &field_type); 770 val = get_field(conn, res, &field_type, metric, type);
771 }
750 } 772 }
751 773
752 *res_val = val; 774 *res_val = val;
753 775
754 if (field_type == DBI_TYPE_ERROR) { 776 if (field_type == DBI_TYPE_ERROR) {
755 CHECK_IGNORE_ERROR (STATE_OK); 777 if (metric != METRIC_QUERY_RESULT) {
756 np_dbi_print_error (conn, "CRITICAL - failed to fetch data"); 778 return STATE_OK;
779 }
780 np_dbi_print_error(conn, "CRITICAL - failed to fetch data");
757 return STATE_CRITICAL; 781 return STATE_CRITICAL;
758 } 782 }
759 783
760 dbi_result_free (res); 784 dbi_result_free(res);
761 return STATE_OK; 785 return STATE_OK;
762} 786}
763 787
764#undef CHECK_IGNORE_ERROR 788mp_state_enum do_query(dbi_conn conn, const char **res_val_str, double *res_val, double *res_time,
765 789 mp_dbi_metric metric, mp_dbi_type type, 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; 790 dbi_result res;
770 791
771 struct timeval timeval_start, timeval_end; 792 struct timeval timeval_start;
772 int status = STATE_OK; 793 struct timeval timeval_end;
794 mp_state_enum status = STATE_OK;
773 795
774 assert (np_dbi_query); 796 assert(np_dbi_query);
775 797
776 if (verbose) 798 if (verbose) {
777 printf ("Executing query '%s'\n", np_dbi_query); 799 printf("Executing query '%s'\n", np_dbi_query);
800 }
778 801
779 gettimeofday (&timeval_start, NULL); 802 gettimeofday(&timeval_start, NULL);
780 803
781 res = dbi_conn_query (conn, np_dbi_query); 804 res = dbi_conn_query(conn, np_dbi_query);
782 if (! res) { 805 if (!res) {
783 np_dbi_print_error (conn, "CRITICAL - failed to execute query '%s'", np_dbi_query); 806 np_dbi_print_error(conn, "CRITICAL - failed to execute query '%s'", np_dbi_query);
784 return STATE_CRITICAL; 807 return STATE_CRITICAL;
785 } 808 }
786 809
787 status = get_query_result (conn, res, res_val_str, res_val); 810 status = get_query_result(conn, res, res_val_str, res_val, metric, type);
788 811
789 gettimeofday (&timeval_end, NULL); 812 gettimeofday(&timeval_end, NULL);
790 *res_time = timediff (timeval_start, timeval_end); 813 *res_time = timediff(timeval_start, timeval_end);
791 814
792 if (verbose) 815 if (verbose) {
793 printf ("Time elapsed: %f\n", *res_time); 816 printf("Time elapsed: %f\n", *res_time);
817 }
794 818
795 return status; 819 return status;
796} 820}
797 821
798double 822double timediff(struct timeval start, struct timeval end) {
799timediff (struct timeval start, struct timeval end)
800{
801 double diff; 823 double diff;
802 824
803 while (start.tv_usec > end.tv_usec) { 825 while (start.tv_usec > end.tv_usec) {
804 --end.tv_sec; 826 --end.tv_sec;
805 end.tv_usec += 1000000; 827 end.tv_usec += 1000000;
806 } 828 }
807 diff = (double)(end.tv_sec - start.tv_sec) 829 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; 830 return diff;
810} 831}
811 832
812void 833void np_dbi_print_error(dbi_conn conn, char *fmt, ...) {
813np_dbi_print_error (dbi_conn conn, char *fmt, ...)
814{
815 const char *errmsg = NULL; 834 const char *errmsg = NULL;
816 va_list ap; 835 va_list ap;
817 836
818 va_start (ap, fmt); 837 va_start(ap, fmt);
819 838
820 dbi_conn_error (conn, &errmsg); 839 dbi_conn_error(conn, &errmsg);
821 vprintf (fmt, ap); 840 vprintf(fmt, ap);
822 printf (": %s\n", errmsg); 841 printf(": %s\n", errmsg);
823 842
824 va_end (ap); 843 va_end(ap);
825} 844}
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..c27e5f13 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,323 @@ 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,
85 usage_va(_("Cannot catch SIGALRM")); 85 config.dig_args, config.query_transport, config.server_port, config.dns_server,
86 86 config.query_address, config.record_type, config.number_tries, timeout_interval_dig);
87 /* Parse extra opts if any */ 87
88 argv=np_extra_opts (&argc, argv, progname); 88 alarm(timeout_interval);
89 89 struct timeval start_time;
90 if (process_arguments (argc, argv) == ERROR) 90 gettimeofday(&start_time, NULL);
91 usage_va(_("Could not parse arguments")); 91
92 92 if (verbose) {
93 /* dig applies the timeout to each try, so we need to work around this */ 93 printf("%s\n", command_line);
94 timeout_interval_dig = timeout_interval / number_tries + number_tries; 94 if (config.expected_address != NULL) {
95 95 printf(_("Looking for: '%s'\n"), config.expected_address);
96 /* get the command to run */ 96 } else {
97 xasprintf (&command_line, "%s %s %s -p %d @%s %s %s +retry=%d +time=%d", 97 printf(_("Looking for: '%s'\n"), config.query_address);
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
101 gettimeofday (&tv, NULL); 101 output chld_out;
102 102 output chld_err;
103 if (verbose) { 103 char *msg = NULL;
104 printf ("%s\n", command_line); 104 mp_state_enum result = STATE_UNKNOWN;
105 if(expected_address != NULL) { 105 /* run the command */
106 printf (_("Looking for: '%s'\n"), expected_address); 106 if (np_runcmd(command_line, &chld_out, &chld_err, 0) != 0) {
107 } else { 107 result = STATE_WARNING;
108 printf (_("Looking for: '%s'\n"), query_address); 108 msg = (char *)_("dig returned an error status");
109 } 109 }
110 } 110
111 111 for (size_t i = 0; i < chld_out.lines; i++) {
112 /* run the command */ 112 /* the server is responding, we just got the host name... */
113 if(np_runcmd(command_line, &chld_out, &chld_err, 0) != 0) { 113 if (strstr(chld_out.line[i], ";; ANSWER SECTION:")) {
114 result = STATE_WARNING; 114
115 msg = (char *)_("dig returned an error status"); 115 /* loop through the whole 'ANSWER SECTION' */
116 } 116 for (; i < chld_out.lines; i++) {
117 117 /* get the host address */
118 for(i = 0; i < chld_out.lines; i++) { 118 if (verbose) {
119 /* the server is responding, we just got the host name... */ 119 printf("%s\n", chld_out.line[i]);
120 if (strstr (chld_out.line[i], ";; ANSWER SECTION:")) { 120 }
121 121
122 /* loop through the whole 'ANSWER SECTION' */ 122 if (strcasestr(chld_out.line[i], (config.expected_address == NULL
123 for(; i < chld_out.lines; i++) { 123 ? config.query_address
124 /* get the host address */ 124 : config.expected_address)) != NULL) {
125 if (verbose) 125 msg = chld_out.line[i];
126 printf ("%s\n", chld_out.line[i]); 126 result = STATE_OK;
127 127
128 if (strcasestr (chld_out.line[i], (expected_address == NULL ? query_address : expected_address)) != NULL) { 128 /* Translate output TAB -> SPACE */
129 msg = chld_out.line[i]; 129 char *temp = msg;
130 result = STATE_OK; 130 while ((temp = strchr(temp, '\t')) != NULL) {
131 131 *temp = ' ';
132 /* Translate output TAB -> SPACE */ 132 }
133 t = msg; 133 break;
134 while ((t = strchr(t, '\t')) != NULL) *t = ' '; 134 }
135 break; 135 }
136 } 136
137 } 137 if (result == STATE_UNKNOWN) {
138 138 msg = (char *)_("Server not found in ANSWER SECTION");
139 if (result == STATE_UNKNOWN) { 139 result = STATE_WARNING;
140 msg = (char *)_("Server not found in ANSWER SECTION"); 140 }
141 result = STATE_WARNING; 141
142 } 142 /* we found the answer section, so break out of the loop */
143 143 break;
144 /* we found the answer section, so break out of the loop */ 144 }
145 break; 145 }
146 } 146
147 } 147 if (result == STATE_UNKNOWN) {
148 148 msg = (char *)_("No ANSWER SECTION found");
149 if (result == STATE_UNKNOWN) { 149 result = STATE_CRITICAL;
150 msg = (char *)_("No ANSWER SECTION found"); 150 }
151 result = STATE_CRITICAL; 151
152 } 152 /* If we get anything on STDERR, at least set warning */
153 153 if (chld_err.buflen > 0) {
154 /* If we get anything on STDERR, at least set warning */ 154 result = max_state(result, STATE_WARNING);
155 if(chld_err.buflen > 0) { 155 if (!msg) {
156 result = max_state(result, STATE_WARNING); 156 for (size_t i = 0; i < chld_err.lines; i++) {
157 if(!msg) for(i = 0; i < chld_err.lines; i++) { 157 msg = strchr(chld_err.line[0], ':');
158 msg = strchr(chld_err.line[0], ':'); 158 if (msg) {
159 if(msg) { 159 msg++;
160 msg++; 160 break;
161 break; 161 }
162 } 162 }
163 } 163 }
164 } 164 }
165 165
166 microsec = deltime (tv); 166 long microsec = deltime(start_time);
167 elapsed_time = (double)microsec / 1.0e6; 167 double elapsed_time = (double)microsec / 1.0e6;
168 168
169 if (critical_interval > UNDEFINED && elapsed_time > critical_interval) 169 if (config.critical_interval > UNDEFINED && elapsed_time > config.critical_interval) {
170 result = STATE_CRITICAL; 170 result = STATE_CRITICAL;
171 171 }
172 else if (warning_interval > UNDEFINED && elapsed_time > warning_interval) 172
173 result = STATE_WARNING; 173 else if (config.warning_interval > UNDEFINED && elapsed_time > config.warning_interval) {
174 174 result = STATE_WARNING;
175 printf ("DNS %s - %.3f seconds response time (%s)|%s\n", 175 }
176 state_text (result), elapsed_time, 176
177 msg ? msg : _("Probably a non-existent host/domain"), 177 printf("DNS %s - %.3f seconds response time (%s)|%s\n", state_text(result), elapsed_time,
178 fperfdata("time", elapsed_time, "s", 178 msg ? msg : _("Probably a non-existent host/domain"),
179 (warning_interval>UNDEFINED ? true:false), 179 fperfdata("time", elapsed_time, "s", (config.warning_interval > UNDEFINED),
180 warning_interval, 180 config.warning_interval, (config.critical_interval > UNDEFINED),
181 (critical_interval>UNDEFINED ? true:false), 181 config.critical_interval, true, 0, false, 0));
182 critical_interval, 182 exit(result);
183 true, 0, false, 0));
184 return result;
185} 183}
186 184
187
188
189/* process command-line arguments */ 185/* process command-line arguments */
190int 186check_dig_config_wrapper process_arguments(int argc, char **argv) {
191process_arguments (int argc, char **argv) 187 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
192{ 188 {"query_address", required_argument, 0, 'l'},
193 int c; 189 {"warning", required_argument, 0, 'w'},
194 190 {"critical", required_argument, 0, 'c'},
195 int option = 0; 191 {"timeout", required_argument, 0, 't'},
196 static struct option longopts[] = { 192 {"dig-arguments", required_argument, 0, 'A'},
197 {"hostname", required_argument, 0, 'H'}, 193 {"verbose", no_argument, 0, 'v'},
198 {"query_address", required_argument, 0, 'l'}, 194 {"version", no_argument, 0, 'V'},
199 {"warning", required_argument, 0, 'w'}, 195 {"help", no_argument, 0, 'h'},
200 {"critical", required_argument, 0, 'c'}, 196 {"record_type", required_argument, 0, 'T'},
201 {"timeout", required_argument, 0, 't'}, 197 {"expected_address", required_argument, 0, 'a'},
202 {"dig-arguments", required_argument, 0, 'A'}, 198 {"port", required_argument, 0, 'p'},
203 {"verbose", no_argument, 0, 'v'}, 199 {"use-ipv4", no_argument, 0, '4'},
204 {"version", no_argument, 0, 'V'}, 200 {"use-ipv6", no_argument, 0, '6'},
205 {"help", no_argument, 0, 'h'}, 201 {0, 0, 0, 0}};
206 {"record_type", required_argument, 0, 'T'}, 202
207 {"expected_address", required_argument, 0, 'a'}, 203 check_dig_config_wrapper result = {
208 {"port", required_argument, 0, 'p'}, 204 .errorcode = OK,
209 {"use-ipv4", no_argument, 0, '4'}, 205 .config = check_dig_config_init(),
210 {"use-ipv6", no_argument, 0, '6'}, 206 };
211 {0, 0, 0, 0} 207
212 }; 208 if (argc < 2) {
213 209 result.errorcode = ERROR;
214 if (argc < 2) 210 return result;
215 return ERROR; 211 }
216 212
217 while (1) { 213 int option = 0;
218 c = getopt_long (argc, argv, "hVvt:l:H:w:c:T:p:a:A:46", longopts, &option); 214 while (true) {
219 215 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) 216
221 break; 217 if (option_index == -1 || option_index == EOF) {
222 218 break;
223 switch (c) { 219 }
224 case 'h': /* help */ 220
225 print_help (); 221 switch (option_index) {
226 exit (STATE_UNKNOWN); 222 case 'h': /* help */
227 case 'V': /* version */ 223 print_help();
228 print_revision (progname, NP_VERSION); 224 exit(STATE_UNKNOWN);
229 exit (STATE_UNKNOWN); 225 case 'V': /* version */
230 case 'H': /* hostname */ 226 print_revision(progname, NP_VERSION);
231 host_or_die(optarg); 227 exit(STATE_UNKNOWN);
232 dns_server = optarg; 228 case 'H': /* hostname */
233 break; 229 host_or_die(optarg);
234 case 'p': /* server port */ 230 result.config.dns_server = optarg;
235 if (is_intpos (optarg)) { 231 break;
236 server_port = atoi (optarg); 232 case 'p': /* server port */
237 } 233 if (is_intpos(optarg)) {
238 else { 234 result.config.server_port = atoi(optarg);
239 usage_va(_("Port must be a positive integer - %s"), optarg); 235 } else {
240 } 236 usage_va(_("Port must be a positive integer - %s"), optarg);
241 break; 237 }
242 case 'l': /* address to lookup */ 238 break;
243 query_address = optarg; 239 case 'l': /* address to lookup */
244 break; 240 result.config.query_address = optarg;
245 case 'w': /* warning */ 241 break;
246 if (is_nonnegative (optarg)) { 242 case 'w': /* warning */
247 warning_interval = strtod (optarg, NULL); 243 if (is_nonnegative(optarg)) {
248 } 244 result.config.warning_interval = strtod(optarg, NULL);
249 else { 245 } else {
250 usage_va(_("Warning interval must be a positive integer - %s"), optarg); 246 usage_va(_("Warning interval must be a positive integer - %s"), optarg);
251 } 247 }
252 break; 248 break;
253 case 'c': /* critical */ 249 case 'c': /* critical */
254 if (is_nonnegative (optarg)) { 250 if (is_nonnegative(optarg)) {
255 critical_interval = strtod (optarg, NULL); 251 result.config.critical_interval = strtod(optarg, NULL);
256 } 252 } else {
257 else { 253 usage_va(_("Critical interval must be a positive integer - %s"), optarg);
258 usage_va(_("Critical interval must be a positive integer - %s"), optarg); 254 }
259 } 255 break;
260 break; 256 case 't': /* timeout */
261 case 't': /* timeout */ 257 if (is_intnonneg(optarg)) {
262 if (is_intnonneg (optarg)) { 258 timeout_interval = atoi(optarg);
263 timeout_interval = atoi (optarg); 259 } else {
264 } 260 usage_va(_("Timeout interval must be a positive integer - %s"), optarg);
265 else { 261 }
266 usage_va(_("Timeout interval must be a positive integer - %s"), optarg); 262 break;
267 } 263 case 'A': /* dig arguments */
268 break; 264 result.config.dig_args = strdup(optarg);
269 case 'A': /* dig arguments */ 265 break;
270 dig_args = strdup(optarg); 266 case 'v': /* verbose */
271 break; 267 verbose++;
272 case 'v': /* verbose */ 268 break;
273 verbose = true; 269 case 'T':
274 break; 270 result.config.record_type = optarg;
275 case 'T': 271 break;
276 record_type = optarg; 272 case 'a':
277 break; 273 result.config.expected_address = optarg;
278 case 'a': 274 break;
279 expected_address = optarg; 275 case '4':
280 break; 276 result.config.query_transport = "-4";
281 case '4': 277 break;
282 query_transport = "-4"; 278 case '6':
283 break; 279 result.config.query_transport = "-6";
284 case '6': 280 break;
285 query_transport = "-6"; 281 default: /* usage5 */
286 break; 282 usage5();
287 default: /* usage5 */ 283 }
288 usage5(); 284 }
289 } 285
290 } 286 int index = optind;
291 287 if (result.config.dns_server == NULL) {
292 c = optind; 288 if (index < argc) {
293 if (dns_server == NULL) { 289 host_or_die(argv[index]);
294 if (c < argc) { 290 result.config.dns_server = argv[index];
295 host_or_die(argv[c]); 291 } else {
296 dns_server = argv[c]; 292 if (strcmp(result.config.query_transport, "-6") == 0) {
297 } 293 result.config.dns_server = strdup("::1");
298 else { 294 } else {
299 if (strcmp(query_transport,"-6") == 0) 295 result.config.dns_server = strdup("127.0.0.1");
300 dns_server = strdup("::1"); 296 }
301 else 297 }
302 dns_server = strdup ("127.0.0.1"); 298 }
303 } 299
304 } 300 return validate_arguments(result);
305
306 return validate_arguments ();
307} 301}
308 302
309 303check_dig_config_wrapper validate_arguments(check_dig_config_wrapper config_wrapper) {
310 304 if (config_wrapper.config.query_address == NULL) {
311int 305 config_wrapper.errorcode = ERROR;
312validate_arguments (void) 306 }
313{ 307 return config_wrapper;
314 if (query_address != NULL)
315 return OK;
316 else
317 return ERROR;
318} 308}
319 309
310void print_help(void) {
311 char *myport;
320 312
313 xasprintf(&myport, "%d", DEFAULT_PORT);
321 314
322void 315 print_revision(progname, NP_VERSION);
323print_help (void)
324{
325 char *myport;
326 316
327 xasprintf (&myport, "%d", DEFAULT_PORT); 317 printf("Copyright (c) 2000 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n");
318 printf(COPYRIGHT, copyright, email);
328 319
329 print_revision (progname, NP_VERSION); 320 printf(_("This plugin tests the DNS service on the specified host using dig"));
330 321
331 printf ("Copyright (c) 2000 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n"); 322 printf("\n\n");
332 printf (COPYRIGHT, copyright, email);
333 323
334 printf (_("This plugin tests the DNS service on the specified host using dig")); 324 print_usage();
335 325
336 printf ("\n\n"); 326 printf(UT_HELP_VRSN);
337 327
338 print_usage (); 328 printf(UT_EXTRA_OPTS);
339 329
340 printf (UT_HELP_VRSN); 330 printf(UT_HOST_PORT, 'p', myport);
341 331
342 printf (UT_EXTRA_OPTS); 332 printf(" %s\n", "-4, --use-ipv4");
333 printf(" %s\n", _("Force dig to only use IPv4 query transport"));
334 printf(" %s\n", "-6, --use-ipv6");
335 printf(" %s\n", _("Force dig to only use IPv6 query transport"));
336 printf(" %s\n", "-l, --query_address=STRING");
337 printf(" %s\n", _("Machine name to lookup"));
338 printf(" %s\n", "-T, --record_type=STRING");
339 printf(" %s\n", _("Record type to lookup (default: A)"));
340 printf(" %s\n", "-a, --expected_address=STRING");
341 printf(" %s\n",
342 _("An address expected to be in the answer section. If not set, uses whatever"));
343 printf(" %s\n", _("was in -l"));
344 printf(" %s\n", "-A, --dig-arguments=STRING");
345 printf(" %s\n", _("Pass STRING as argument(s) to dig"));
346 printf(UT_WARN_CRIT);
347 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
348 printf(UT_VERBOSE);
343 349
344 printf (UT_HOST_PORT, 'p', myport); 350 printf("\n");
351 printf("%s\n", _("Examples:"));
352 printf(" %s\n", "check_dig -H DNSSERVER -l www.example.com -A \"+tcp\"");
353 printf(" %s\n", "This will send a tcp query to DNSSERVER for www.example.com");
345 354
346 printf (" %s\n","-4, --use-ipv4"); 355 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} 356}
370 357
371 358void print_usage(void) {
372 359 printf("%s\n", _("Usage:"));
373void 360 printf("%s -l <query_address> [-H <host>] [-p <server port>]\n", progname);
374print_usage (void) 361 printf(" [-T <query type>] [-w <warning interval>] [-c <critical interval>]\n");
375{ 362 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} 363}
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..d42b5486 100644
--- a/plugins/check_disk.c
+++ b/plugins/check_disk.c
@@ -1,1161 +1,1304 @@
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,
82 char *crit_freespace_units, char *warn_freespace_percent,
83 char *crit_freespace_percent, char *warn_freeinodes_percent,
84 char *crit_freeinodes_percent);
85static double calculate_percent(uintmax_t /*value*/, uintmax_t /*total*/);
86static bool stat_path(parameter_list_elem * /*parameters*/, bool /*ignore_missing*/);
87
88/*
89 * Puts the values from a struct fs_usage into a parameter_list with an additional flag to control
90 * how reserved and inodes should be judged (ignored or not)
91 */
92static parameter_list_elem get_path_stats(parameter_list_elem parameters, struct fs_usage fsp,
93 bool freespace_ignore_reserved);
94static mp_subcheck evaluate_filesystem(measurement_unit measurement_unit,
95 bool display_inodes_perfdata, byte_unit unit);
96
97void print_usage(void);
98static void print_help(void);
99
100static int verbose = 0;
101
102// This would not be necessary in C23!!
103const byte_unit Bytes_Factor = 1;
104const byte_unit KibiBytes_factor = 1024;
105const byte_unit MebiBytes_factor = 1048576;
106const byte_unit GibiBytes_factor = 1073741824;
107const byte_unit TebiBytes_factor = 1099511627776;
108const byte_unit PebiBytes_factor = 1125899906842624;
109const byte_unit ExbiBytes_factor = 1152921504606846976;
110const byte_unit KiloBytes_factor = 1000;
111const byte_unit MegaBytes_factor = 1000000;
112const byte_unit GigaBytes_factor = 1000000000;
113const byte_unit TeraBytes_factor = 1000000000000;
114const byte_unit PetaBytes_factor = 1000000000000000;
115const byte_unit ExaBytes_factor = 1000000000000000000;
116
117int main(int argc, char **argv) {
118 setlocale(LC_ALL, "");
119 bindtextdomain(PACKAGE, LOCALEDIR);
120 textdomain(PACKAGE);
101 121
102static struct name_list *dp_exclude_list; 122#ifdef __CYGWIN__
123 char mountdir[32];
124#endif
103 125
104static struct parameter_list *path_select_list = NULL; 126 // Parse extra opts if any
127 argv = np_extra_opts(&argc, argv, progname);
128
129 check_disk_config_wrapper tmp_config = process_arguments(argc, argv);
130 if (tmp_config.errorcode == ERROR) {
131 usage4(_("Could not parse arguments"));
132 }
133
134 check_disk_config config = tmp_config.config;
135
136 if (config.output_format_is_set) {
137 mp_set_format(config.output_format);
138 }
139
140 if (config.erronly) {
141 mp_set_level_of_detail(MP_DETAIL_NON_OK_ONLY);
142 }
143
144 if (!config.path_ignored) {
145 mp_int_fs_list_set_best_match(config.path_select_list, config.mount_list,
146 config.exact_match);
147 }
148
149 // Error if no match found for specified paths
150 for (parameter_list_elem *elem = config.path_select_list.first; elem;) {
151 if (!elem->best_match && config.ignore_missing) {
152 /* Delete the path from the list so that it is not stat-checked later in the code. */
153 elem = mp_int_fs_list_del(&config.path_select_list, elem);
154 continue;
155 }
156 if (!elem->best_match) {
157 /* Without --ignore-missing option, exit with Critical state. */
158 die(STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), elem->name);
159 }
160
161 elem = mp_int_fs_list_get_next(elem);
162 }
163
164 mp_check overall = mp_check_init();
165 if (config.path_select_list.length == 0) {
166 mp_subcheck none_sc = mp_subcheck_init();
167 xasprintf(&none_sc.output, "No filesystems were found for the provided parameters");
168 if (config.ignore_missing) {
169 none_sc = mp_set_subcheck_state(none_sc, STATE_OK);
170 } else {
171 none_sc = mp_set_subcheck_state(none_sc, STATE_UNKNOWN);
172 if (verbose >= 2) {
173 printf("None of the provided paths were found\n");
174 }
175 }
176 mp_add_subcheck_to_check(&overall, none_sc);
177 mp_exit(overall);
178 }
105 179
106/* Linked list of mounted filesystems. */ 180 // Filter list first
107static struct mount_entry *mount_list; 181 for (parameter_list_elem *path = config.path_select_list.first; path;) {
182 if (!path->best_match) {
183 path = mp_int_fs_list_del(&config.path_select_list, path);
184 continue;
185 }
108 186
109/* For long options that have no equivalent short option, use a 187 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 188
118#ifdef _AIX 189#ifdef __CYGWIN__
119#pragma alloca 190 if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11) {
191 path = mp_int_fs_list_del(&config.path_select_list, path);
192 continue;
193 }
194
195 char *mountdir = NULL;
196 snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10);
197 if (GetDriveType(mountdir) != DRIVE_FIXED) {
198 mount_entry->me_remote = 1;
199 }
120#endif 200#endif
121 201
122int process_arguments (int, char **); 202 /* Remove filesystems already seen */
123void print_path (const char *mypath); 203 if (np_seen_name(config.seen, mount_entry->me_mountdir)) {
124void set_all_thresholds (struct parameter_list *path); 204 path = mp_int_fs_list_del(&config.path_select_list, path);
125int validate_arguments (uintmax_t, uintmax_t, double, double, double, double, char *); 205 continue;
126void print_help (void); 206 }
127void print_usage (void); 207
128double calculate_percent(uintmax_t, uintmax_t); 208 if (path->group == NULL) {
129bool stat_path (struct parameter_list *p); 209 if (config.fs_exclude_list &&
130void get_stats (struct parameter_list *p, struct fs_usage *fsp); 210 np_find_regmatch(config.fs_exclude_list, mount_entry->me_type)) {
131void get_path_stats (struct parameter_list *p, struct fs_usage *fsp); 211 // Skip excluded fs's
132 212 path = mp_int_fs_list_del(&config.path_select_list, path);
133char *exclude_device; 213 continue;
134char *units; 214 }
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 215
181#ifdef __CYGWIN__ 216 if (config.device_path_exclude_list &&
182 char mountdir[32]; 217 (np_find_name(config.device_path_exclude_list, mount_entry->me_devname) ||
183#endif 218 np_find_name(config.device_path_exclude_list, mount_entry->me_mountdir))) {
219 // Skip excluded device or mount paths
220 path = mp_int_fs_list_del(&config.path_select_list, path);
221 continue;
222 }
184 223
185 output = strdup (""); 224 if (config.fs_include_list &&
186 ignored = strdup (""); 225 !np_find_regmatch(config.fs_include_list, mount_entry->me_type)) {
187 details = strdup (""); 226 // Skip not included fstypes
188 perf = strdup (""); 227 path = mp_int_fs_list_del(&config.path_select_list, path);
189 perf_ilabel = strdup (""); 228 continue;
190 stat_buf = malloc(sizeof *stat_buf); 229 }
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 230
273#ifdef __CYGWIN__ 231 /* Skip remote filesystems if we're not interested in them */
274 if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11) 232 if (mount_entry->me_remote && config.show_local_fs) {
275 continue; 233 if (config.stat_remote_fs) {
276 snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10); 234 // TODO Stat here
277 if (GetDriveType(mountdir) != DRIVE_FIXED) 235 if (!stat_path(path, config.ignore_missing) && config.ignore_missing) {
278 me->me_remote = 1; 236 }
279#endif 237 }
280 /* Filters */ 238 continue;
281 239 }
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 240
241 // TODO why stat here? remove unstatable fs?
242 if (!stat_path(path, config.ignore_missing)) {
243 // if (config.ignore_missing) {
244 // xasprintf(&ignored, "%s %s;", ignored, path->name);
245 // }
246 // not accessible, remove from list
247 path = mp_int_fs_list_del(&config.path_select_list, path);
248 continue;
249 }
250 }
251
252 path = mp_int_fs_list_get_next(path);
253 }
254
255 // now get the actual measurements
256 for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem;) {
257 // Get actual metrics here
258 struct mount_entry *mount_entry = filesystem->best_match;
259 struct fs_usage fsp = {0};
260 get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp);
261
262 if (fsp.fsu_blocks != 0 && strcmp("none", mount_entry->me_mountdir) != 0) {
263 *filesystem = get_path_stats(*filesystem, fsp, config.freespace_ignore_reserved);
264
265 if (verbose >= 3) {
266 printf("For %s, used_units=%lu free_units=%lu total_units=%lu "
267 "fsp.fsu_blocksize=%lu\n",
268 mount_entry->me_mountdir, filesystem->used_bytes, filesystem->free_bytes,
269 filesystem->total_bytes, fsp.fsu_blocksize);
270 }
271 } else {
272 // failed to retrieve file system data or not mounted?
273 filesystem = mp_int_fs_list_del(&config.path_select_list, filesystem);
274 continue;
275 }
276 filesystem = mp_int_fs_list_get_next(filesystem);
277 }
278
279 if (verbose > 2) {
280 for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem;
281 filesystem = mp_int_fs_list_get_next(filesystem)) {
282 assert(filesystem->best_match != NULL);
283 if (filesystem->best_match == NULL) {
284 printf("Filesystem path %s has no mount_entry!\n", filesystem->name);
285 } else {
286 // printf("Filesystem path %s has a mount_entry!\n", filesystem->name);
287 }
288 }
289 }
290
291 measurement_unit_list *measurements = NULL;
292 measurement_unit_list *current = NULL;
293 // create measuring units, because of groups
294 for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem;
295 filesystem = mp_int_fs_list_get_next(filesystem)) {
296 assert(filesystem->best_match != NULL);
297
298 if (filesystem->group == NULL) {
299 // create a measurement unit for the fs
300 measurement_unit unit =
301 create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
302 if (measurements == NULL) {
303 measurements = current = add_measurement_list(NULL, unit);
304 } else {
305 current = add_measurement_list(measurements, unit);
306 }
307 } else {
308 // Grouped elements are consecutive
309 if (measurements == NULL) {
310 // first entry
311 measurement_unit unit =
312 create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
313 unit.name = strdup(filesystem->group);
314 measurements = current = add_measurement_list(NULL, unit);
315 } else {
316 // if this is the first element of a group, the name of the previous entry is
317 // different
318 if (strcmp(filesystem->group, current->unit.name) != 0) {
319 // so, this must be the first element of a group
320 measurement_unit unit =
321 create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
322 unit.name = filesystem->group;
323 current = add_measurement_list(measurements, unit);
324
325 } else {
326 // NOT the first entry of a group, add info to the other one
327 current->unit = add_filesystem_to_measurement_unit(current->unit, *filesystem);
328 }
329 }
330 }
331 }
332
333 /* Process for every path in list */
334 if (measurements != NULL) {
335 for (measurement_unit_list *unit = measurements; unit; unit = unit->next) {
336 mp_subcheck unit_sc = evaluate_filesystem(unit->unit, config.display_inodes_perfdata,
337 config.display_unit);
338 mp_add_subcheck_to_check(&overall, unit_sc);
339 }
340 } else {
341 // Apparently no machting fs found
342 mp_subcheck none_sc = mp_subcheck_init();
343 xasprintf(&none_sc.output, "No filesystems were found for the provided parameters");
344
345 if (config.ignore_missing) {
346 none_sc = mp_set_subcheck_state(none_sc, STATE_OK);
347 } else {
348 none_sc = mp_set_subcheck_state(none_sc, STATE_UNKNOWN);
349 }
350 mp_add_subcheck_to_check(&overall, none_sc);
351 }
352
353 mp_exit(overall);
354}
461 355
462double calculate_percent(uintmax_t value, uintmax_t total) { 356double calculate_percent(uintmax_t value, uintmax_t total) {
463 double pct = -1; 357 double pct = -1;
464 if(value <= DBL_MAX && total != 0) { 358 if (value <= DBL_MAX && total != 0) {
465 pct = (double)value / total * 100.0; 359 pct = (double)value / (double)total * 100.0;
466 } 360 }
467 return pct; 361
362 return pct;
468} 363}
469 364
470/* process command-line arguments */ 365/* process command-line arguments */
471int 366check_disk_config_wrapper process_arguments(int argc, char **argv) {
472process_arguments (int argc, char **argv) 367
473{ 368 check_disk_config_wrapper result = {
474 int c, err; 369 .errorcode = OK,
475 struct parameter_list *se; 370 .config = check_disk_config_init(),
476 struct parameter_list *temp_list = NULL, *previous = NULL; 371 };
477 struct mount_entry *me; 372
478 regex_t re; 373 if (argc < 2) {
479 int cflags = REG_NOSUB | REG_EXTENDED; 374 result.errorcode = ERROR;
480 int default_cflags = cflags; 375 return result;
481 char errbuf[MAX_INPUT_BUFFER]; 376 }
482 int fnd = 0; 377
483 378 enum {
484 int option = 0; 379 output_format_index = CHAR_MAX + 1,
485 static struct option longopts[] = { 380 display_unit_index,
486 {"timeout", required_argument, 0, 't'}, 381 };
487 {"warning", required_argument, 0, 'w'}, 382
488 {"critical", required_argument, 0, 'c'}, 383 static struct option longopts[] = {{"timeout", required_argument, 0, 't'},
489 {"iwarning", required_argument, 0, 'W'}, 384 {"warning", required_argument, 0, 'w'},
490 /* Dang, -C is taken. We might want to reshuffle this. */ 385 {"critical", required_argument, 0, 'c'},
491 {"icritical", required_argument, 0, 'K'}, 386 {"iwarning", required_argument, 0, 'W'},
492 {"kilobytes", no_argument, 0, 'k'}, 387 {"icritical", required_argument, 0, 'K'},
493 {"megabytes", no_argument, 0, 'm'}, 388 {"kilobytes", no_argument, 0, 'k'},
494 {"units", required_argument, 0, 'u'}, 389 {"megabytes", no_argument, 0, 'm'},
495 {"path", required_argument, 0, 'p'}, 390 {"units", required_argument, 0, 'u'},
496 {"partition", required_argument, 0, 'p'}, 391 {"path", required_argument, 0, 'p'},
497 {"exclude_device", required_argument, 0, 'x'}, 392 {"partition", required_argument, 0, 'p'},
498 {"exclude-type", required_argument, 0, 'X'}, 393 {"exclude_device", required_argument, 0, 'x'},
499 {"include-type", required_argument, 0, 'N'}, 394 {"exclude-type", required_argument, 0, 'X'},
500 {"group", required_argument, 0, 'g'}, 395 {"include-type", required_argument, 0, 'N'},
501 {"eregi-path", required_argument, 0, 'R'}, 396 {"group", required_argument, 0, 'g'},
502 {"eregi-partition", required_argument, 0, 'R'}, 397 {"eregi-path", required_argument, 0, 'R'},
503 {"ereg-path", required_argument, 0, 'r'}, 398 {"eregi-partition", required_argument, 0, 'R'},
504 {"ereg-partition", required_argument, 0, 'r'}, 399 {"ereg-path", required_argument, 0, 'r'},
505 {"freespace-ignore-reserved", no_argument, 0, 'f'}, 400 {"ereg-partition", required_argument, 0, 'r'},
506 {"ignore-ereg-path", required_argument, 0, 'i'}, 401 {"freespace-ignore-reserved", no_argument, 0, 'f'},
507 {"ignore-ereg-partition", required_argument, 0, 'i'}, 402 {"ignore-ereg-path", required_argument, 0, 'i'},
508 {"ignore-eregi-path", required_argument, 0, 'I'}, 403 {"ignore-ereg-partition", required_argument, 0, 'i'},
509 {"ignore-eregi-partition", required_argument, 0, 'I'}, 404 {"ignore-eregi-path", required_argument, 0, 'I'},
510 {"ignore-missing", no_argument, 0, 'n'}, 405 {"ignore-eregi-partition", required_argument, 0, 'I'},
511 {"local", no_argument, 0, 'l'}, 406 {"ignore-missing", no_argument, 0, 'n'},
512 {"stat-remote-fs", no_argument, 0, 'L'}, 407 {"local", no_argument, 0, 'l'},
513 {"iperfdata", no_argument, 0, 'P'}, 408 {"stat-remote-fs", no_argument, 0, 'L'},
514 {"mountpoint", no_argument, 0, 'M'}, 409 {"iperfdata", no_argument, 0, 'P'},
515 {"errors-only", no_argument, 0, 'e'}, 410 {"mountpoint", no_argument, 0, 'M'},
516 {"exact-match", no_argument, 0, 'E'}, 411 {"errors-only", no_argument, 0, 'e'},
517 {"all", no_argument, 0, 'A'}, 412 {"exact-match", no_argument, 0, 'E'},
518 {"verbose", no_argument, 0, 'v'}, 413 {"all", no_argument, 0, 'A'},
519 {"quiet", no_argument, 0, 'q'}, 414 {"verbose", no_argument, 0, 'v'},
520 {"clear", no_argument, 0, 'C'}, 415 {"quiet", no_argument, 0, 'q'},
521 {"version", no_argument, 0, 'V'}, 416 {"clear", no_argument, 0, 'C'},
522 {"help", no_argument, 0, 'h'}, 417 {"version", no_argument, 0, 'V'},
523 {0, 0, 0, 0} 418 {"help", no_argument, 0, 'h'},
524 }; 419 {"output-format", required_argument, 0, output_format_index},
525 420 {"display-unit", required_argument, 0, display_unit_index},
526 if (argc < 2) 421 {0, 0, 0, 0}};
527 return ERROR; 422
528 423 for (int index = 1; index < argc; index++) {
529 np_add_regex(&fs_exclude_list, "iso9660", REG_EXTENDED); 424 if (strcmp("-to", argv[index]) == 0) {
530 425 strcpy(argv[index], "-t");
531 for (c = 1; c < argc; c++) 426 }
532 if (strcmp ("-to", argv[c]) == 0) 427 }
533 strcpy (argv[c], "-t"); 428
534 429 int cflags = REG_NOSUB | REG_EXTENDED;
535 while (1) { 430 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); 431 char *warn_freespace_units = NULL;
537 432 char *crit_freespace_units = NULL;
538 if (c == -1 || c == EOF) 433 char *warn_freespace_percent = NULL;
539 break; 434 char *crit_freespace_percent = NULL;
540 435 char *warn_freeinodes_percent = NULL;
541 switch (c) { 436 char *crit_freeinodes_percent = NULL;
542 case 't': /* timeout period */ 437
543 if (is_integer (optarg)) { 438 bool path_selected = false;
544 timeout_interval = atoi (optarg); 439 char *group = NULL;
545 break; 440 byte_unit unit = MebiBytes_factor;
546 } 441
547 else { 442 result.config.mount_list = read_file_system_list(false);
548 usage2 (_("Timeout interval must be a positive integer"), optarg); 443
549 } 444 np_add_regex(&result.config.fs_exclude_list, "iso9660", REG_EXTENDED);
550 445
551 /* See comments for 'c' */ 446 while (true) {
552 case 'w': /* warning threshold */ 447 int option = 0;
448 int option_index = getopt_long(
449 argc, argv, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLPg:R:r:i:I:MEAn", longopts, &option);
450
451 if (option_index == -1 || option_index == EOF) {
452 break;
453 }
454
455 switch (option_index) {
456 case 't': /* timeout period */
457 if (is_integer(optarg)) {
458 timeout_interval = atoi(optarg);
459 break;
460 } else {
461 usage2(_("Timeout interval must be a positive integer"), optarg);
462 }
463
464 /* See comments for 'c' */
465 case 'w': /* warning threshold */
553 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) { 466 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) {
554 die(STATE_UNKNOWN, "Argument for --warning invalid or missing: %s\n", optarg); 467 die(STATE_UNKNOWN, "Argument for --warning invalid or missing: %s\n", optarg);
555 } 468 }
556 469
557 if (strstr(optarg, "%")) { 470 if (strstr(optarg, "%")) {
558 if (*optarg == '@') { 471 if (*optarg == '@') {
559 warn_freespace_percent = optarg; 472 warn_freespace_percent = optarg;
560 } else { 473 } else {
561 xasprintf(&warn_freespace_percent, "@%s", optarg); 474 xasprintf(&warn_freespace_percent, "@%s", optarg);
562 } 475 }
563 } else { 476 } else {
564 if (*optarg == '@') { 477 if (*optarg == '@') {
565 warn_freespace_units = optarg; 478 warn_freespace_units = optarg;
566 } else { 479 } else {
567 xasprintf(&warn_freespace_units, "@%s", optarg); 480 xasprintf(&warn_freespace_units, "@%s", optarg);
568 } 481 }
569 } 482 }
570 break; 483 break;
571 484
572 /* Awful mistake where the range values do not make sense. Normally, 485 /* 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 486 * 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 487 * 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 488 * force @ at the beginning of the range, so that it is backwards compatible
576 */ 489 */
577 case 'c': /* critical threshold */ 490 case 'c': /* critical threshold */
578 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) { 491 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) {
579 die(STATE_UNKNOWN, "Argument for --critical invalid or missing: %s\n", optarg); 492 die(STATE_UNKNOWN, "Argument for --critical invalid or missing: %s\n", optarg);
580 } 493 }
581 494
582 if (strstr(optarg, "%")) { 495 if (strstr(optarg, "%")) {
583 if (*optarg == '@') { 496 if (*optarg == '@') {
584 crit_freespace_percent = optarg; 497 crit_freespace_percent = optarg;
585 } else { 498 } else {
586 xasprintf(&crit_freespace_percent, "@%s", optarg); 499 xasprintf(&crit_freespace_percent, "@%s", optarg);
587 } 500 }
588 } else { 501 } else {
589 if (*optarg == '@') { 502 if (*optarg == '@') {
590 crit_freespace_units = optarg; 503 crit_freespace_units = optarg;
591 } else { 504 } else {
592 xasprintf(&crit_freespace_units, "@%s", optarg); 505 xasprintf(&crit_freespace_units, "@%s", optarg);
593 } 506 }
594 } 507 }
595 break; 508 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 509
510 case 'W': /* warning inode threshold */
511 if (*optarg == '@') {
512 warn_freeinodes_percent = optarg;
513 } else {
514 xasprintf(&warn_freeinodes_percent, "@%s", optarg);
515 }
516 break;
517 case 'K': /* critical inode threshold */
518 if (*optarg == '@') {
519 crit_freeinodes_percent = optarg;
520 } else {
521 xasprintf(&crit_freeinodes_percent, "@%s", optarg);
522 }
523 break;
524 case 'u':
525 if (!strcasecmp(optarg, "bytes")) {
526 unit = Bytes_Factor;
527 } else if (!strcmp(optarg, "KiB")) {
528 unit = KibiBytes_factor;
529 } else if (!strcmp(optarg, "kB")) {
530 unit = KiloBytes_factor;
531 } else if (!strcmp(optarg, "MiB")) {
532 unit = MebiBytes_factor;
533 } else if (!strcmp(optarg, "MB")) {
534 unit = MegaBytes_factor;
535 } else if (!strcmp(optarg, "GiB")) {
536 unit = GibiBytes_factor;
537 } else if (!strcmp(optarg, "GB")) {
538 unit = GigaBytes_factor;
539 } else if (!strcmp(optarg, "TiB")) {
540 unit = TebiBytes_factor;
541 } else if (!strcmp(optarg, "TB")) {
542 unit = TeraBytes_factor;
543 } else if (!strcmp(optarg, "PiB")) {
544 unit = PebiBytes_factor;
545 } else if (!strcmp(optarg, "PB")) {
546 unit = PetaBytes_factor;
547 } else {
548 die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
549 }
550 break;
551 case 'k':
552 unit = KibiBytes_factor;
553 break;
554 case 'm':
555 unit = MebiBytes_factor;
556 break;
557 case display_unit_index:
558 if (!strcasecmp(optarg, "bytes")) {
559 result.config.display_unit = Bytes;
560 } else if (!strcmp(optarg, "KiB")) {
561 result.config.display_unit = KibiBytes;
562 } else if (!strcmp(optarg, "kB")) {
563 result.config.display_unit = KiloBytes;
564 } else if (!strcmp(optarg, "MiB")) {
565 result.config.display_unit = MebiBytes;
566 } else if (!strcmp(optarg, "MB")) {
567 result.config.display_unit = MegaBytes;
568 } else if (!strcmp(optarg, "GiB")) {
569 result.config.display_unit = GibiBytes;
570 } else if (!strcmp(optarg, "GB")) {
571 result.config.display_unit = GigaBytes;
572 } else if (!strcmp(optarg, "TiB")) {
573 result.config.display_unit = TebiBytes;
574 } else if (!strcmp(optarg, "TB")) {
575 result.config.display_unit = TeraBytes;
576 } else if (!strcmp(optarg, "PiB")) {
577 result.config.display_unit = PebiBytes;
578 } else if (!strcmp(optarg, "PB")) {
579 result.config.display_unit = PetaBytes;
580 } else {
581 die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
582 }
583 break;
584 case 'L':
585 result.config.stat_remote_fs = true;
586 /* fallthrough */
587 case 'l':
588 result.config.show_local_fs = true;
589 break;
590 case 'P':
591 result.config.display_inodes_perfdata = true;
592 break;
593 case 'p': /* select path */ {
594 if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
595 crit_freespace_percent || warn_freeinodes_percent || crit_freeinodes_percent)) {
596 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"),
597 _("Must set a threshold value before using -p\n"));
598 }
902 599
600 /* add parameter if not found. overwrite thresholds if path has already been added */
601 parameter_list_elem *search_entry;
602 if (!(search_entry = mp_int_fs_list_find(result.config.path_select_list, optarg))) {
603 search_entry = mp_int_fs_list_append(&result.config.path_select_list, optarg);
903 604
904void 605 // struct stat stat_buf = {};
905print_path (const char *mypath) 606 // if (stat(optarg, &stat_buf) && result.config.ignore_missing) {
906{ 607 // result.config.path_ignored = true;
907 if (mypath == NULL) 608 // break;
908 printf ("\n"); 609 // }
909 else 610 }
910 printf (_(" for %s\n"), mypath); 611 search_entry->group = group;
911} 612 set_all_thresholds(search_entry, warn_freespace_units, crit_freespace_units,
613 warn_freespace_percent, crit_freespace_percent,
614
615 warn_freeinodes_percent, crit_freeinodes_percent);
616
617 /* With autofs, it is required to stat() the path before re-populating the mount_list */
618 // if (!stat_path(se, result.config.ignore_missing)) {
619 // break;
620 // }
621 mp_int_fs_list_set_best_match(result.config.path_select_list, result.config.mount_list,
622 result.config.exact_match);
623
624 path_selected = true;
625 } break;
626 case 'x': /* exclude path or partition */
627 np_add_name(&result.config.device_path_exclude_list, optarg);
628 break;
629 case 'X': /* exclude file system type */ {
630 int err = np_add_regex(&result.config.fs_exclude_list, optarg, REG_EXTENDED);
631 if (err != 0) {
632 char errbuf[MAX_INPUT_BUFFER];
633 regerror(err, &result.config.fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
634 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"),
635 _("Could not compile regular expression"), errbuf);
636 }
637 break;
638 case 'N': /* include file system type */
639 err = np_add_regex(&result.config.fs_include_list, optarg, REG_EXTENDED);
640 if (err != 0) {
641 char errbuf[MAX_INPUT_BUFFER];
642 regerror(err, &result.config.fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
643 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"),
644 _("Could not compile regular expression"), errbuf);
645 }
646 } break;
647 case 'v': /* verbose */
648 verbose++;
649 break;
650 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
651 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
652 result.config.erronly = true;
653 break;
654 case 'e':
655 result.config.erronly = true;
656 break;
657 case 'E':
658 if (path_selected) {
659 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"),
660 _("Must set -E before selecting paths\n"));
661 }
662 result.config.exact_match = true;
663 break;
664 case 'f':
665 result.config.freespace_ignore_reserved = true;
666 break;
667 case 'g':
668 if (path_selected) {
669 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"),
670 _("Must set group value before selecting paths\n"));
671 }
672 group = optarg;
673 break;
674 case 'I':
675 cflags |= REG_ICASE;
676 // Intentional fallthrough
677 case 'i': {
678 if (!path_selected) {
679 die(STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"),
680 _("Paths need to be selected before using -i/-I. Use -A to select all paths "
681 "explicitly"));
682 }
683 regex_t regex;
684 int err = regcomp(&regex, optarg, cflags);
685 if (err != 0) {
686 char errbuf[MAX_INPUT_BUFFER];
687 regerror(err, &regex, errbuf, MAX_INPUT_BUFFER);
688 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"),
689 _("Could not compile regular expression"), errbuf);
690 }
912 691
692 for (parameter_list_elem *elem = result.config.path_select_list.first; elem;) {
693 if (elem->best_match) {
694 if (np_regex_match_mount_entry(elem->best_match, &regex)) {
913 695
914void 696 if (verbose >= 3) {
915set_all_thresholds (struct parameter_list *path) 697 printf("ignoring %s matching regex\n", elem->name);
916{ 698 }
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 699
931void 700 elem = mp_int_fs_list_del(&result.config.path_select_list, elem);
932print_help (void) 701 continue;
933{ 702 }
934 print_revision (progname, NP_VERSION); 703 }
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 704
705 elem = mp_int_fs_list_get_next(elem);
706 }
1031 707
708 cflags = default_cflags;
709 } break;
710 case 'n':
711 result.config.ignore_missing = true;
712 break;
713 case 'A':
714 optarg = strdup(".*");
715 // Intentional fallthrough
716 case 'R':
717 cflags |= REG_ICASE;
718 // Intentional fallthrough
719 case 'r': {
720 if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
721 crit_freespace_percent || warn_freeinodes_percent || crit_freeinodes_percent)) {
722 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"),
723 _("Must set a threshold value before using -r/-R/-A "
724 "(--ereg-path/--eregi-path/--all)\n"));
725 }
1032 726
1033void 727 regex_t regex;
1034print_usage (void) 728 int err = regcomp(&regex, optarg, cflags);
1035{ 729 if (err != 0) {
1036 printf ("%s\n", _("Usage:")); 730 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); 731 regerror(err, &regex, errbuf, MAX_INPUT_BUFFER);
1038 printf ("[-C] [-E] [-e] [-f] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n"); 732 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"),
1039 printf ("[-t timeout] [-u unit] [-v] [-X type_regex] [-N type]\n"); 733 _("Could not compile regular expression"), errbuf);
734 }
735
736 bool found = false;
737 for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
738 if (np_regex_match_mount_entry(me, &regex)) {
739 found = true;
740 if (verbose >= 3) {
741 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir,
742 optarg);
743 }
744
745 /* add parameter if not found. overwrite thresholds if path has already been
746 * added */
747 parameter_list_elem *se = NULL;
748 if (!(se = mp_int_fs_list_find(result.config.path_select_list,
749 me->me_mountdir))) {
750 se =
751 mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
752 }
753 se->group = group;
754 set_all_thresholds(se, warn_freespace_units, crit_freespace_units,
755 warn_freespace_percent, crit_freespace_percent,
756 warn_freeinodes_percent, crit_freeinodes_percent);
757 }
758 }
759
760 if (!found) {
761 if (result.config.ignore_missing) {
762 result.config.path_ignored = true;
763 path_selected = true;
764 break;
765 }
766
767 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"),
768 _("Regular expression did not match any path or disk"), optarg);
769 }
770
771 path_selected = true;
772 mp_int_fs_list_set_best_match(result.config.path_select_list, result.config.mount_list,
773 result.config.exact_match);
774 cflags = default_cflags;
775
776 } break;
777 case 'M': /* display mountpoint */
778 result.config.display_mntp = true;
779 break;
780 case 'C': {
781 /* add all mount entries to path_select list if no partitions have been explicitly
782 * defined using -p */
783 if (!path_selected) {
784 parameter_list_elem *path;
785 for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
786 if (!(path = mp_int_fs_list_find(result.config.path_select_list,
787 me->me_mountdir))) {
788 path =
789 mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
790 }
791 path->best_match = me;
792 path->group = group;
793 set_all_thresholds(path, warn_freespace_units, crit_freespace_units,
794 warn_freespace_percent, crit_freespace_percent,
795 warn_freeinodes_percent, crit_freeinodes_percent);
796 }
797 }
798
799 warn_freespace_units = NULL;
800 crit_freespace_units = NULL;
801 warn_freespace_percent = NULL;
802 crit_freespace_percent = NULL;
803 warn_freeinodes_percent = NULL;
804 crit_freeinodes_percent = NULL;
805
806 path_selected = false;
807 group = NULL;
808 } break;
809 case 'V': /* version */
810 print_revision(progname, NP_VERSION);
811 exit(STATE_UNKNOWN);
812 case 'h': /* help */
813 print_help();
814 exit(STATE_UNKNOWN);
815 case '?': /* help */
816 usage(_("Unknown argument"));
817 case output_format_index: {
818 parsed_output_format parser = mp_parse_output_format(optarg);
819 if (!parser.parsing_success) {
820 // TODO List all available formats here, maybe add anothoer usage function
821 printf("Invalid output format: %s\n", optarg);
822 exit(STATE_UNKNOWN);
823 }
824
825 result.config.output_format_is_set = true;
826 result.config.output_format = parser.output_format;
827 break;
828 }
829 }
830 }
831
832 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
833 int index = optind;
834
835 if (argc > index && is_intnonneg(argv[index])) {
836 if (verbose > 0) {
837 printf("Got an positional warn threshold: %s\n", argv[index]);
838 }
839 char *range = argv[index++];
840 mp_range_parsed tmp = mp_parse_range_string(range);
841 if (tmp.error != MP_PARSING_SUCCES) {
842 die(STATE_UNKNOWN, "failed to parse warning threshold");
843 }
844
845 mp_range tmp_range = tmp.range;
846 // Invert range to use it for free instead of used
847 // tmp_range.alert_on_inside_range = !tmp_range.alert_on_inside_range;
848
849 warn_freespace_percent = mp_range_to_string(tmp_range);
850
851 if (verbose > 0) {
852 printf("Positional warning threshold transformed to: %s\n", warn_freespace_percent);
853 }
854 }
855
856 if (argc > index && is_intnonneg(argv[index])) {
857 if (verbose > 0) {
858 printf("Got an positional crit threshold: %s\n", argv[index]);
859 }
860 char *range = argv[index++];
861 mp_range_parsed tmp = mp_parse_range_string(range);
862 if (tmp.error != MP_PARSING_SUCCES) {
863 die(STATE_UNKNOWN, "failed to parse warning threshold");
864 }
865
866 mp_range tmp_range = tmp.range;
867 // Invert range to use it for free instead of used
868 // tmp_range.alert_on_inside_range = !tmp_range.alert_on_inside_range;
869
870 crit_freespace_percent = mp_range_to_string(tmp_range);
871
872 if (verbose > 0) {
873 printf("Positional critical threshold transformed to: %s\n", crit_freespace_percent);
874 }
875 }
876
877 if (argc > index) {
878 if (verbose > 0) {
879 printf("Got an positional filesystem: %s\n", argv[index]);
880 }
881 struct parameter_list *se =
882 mp_int_fs_list_append(&result.config.path_select_list, strdup(argv[index++]));
883 path_selected = true;
884 set_all_thresholds(se, warn_freespace_units, crit_freespace_units, warn_freespace_percent,
885 crit_freespace_percent, warn_freeinodes_percent,
886 crit_freeinodes_percent);
887 }
888
889 // If a list of paths has not been explicitly selected, find entire
890 // mount list and create list of paths
891 if (!path_selected && !result.config.path_ignored) {
892 for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
893 if (me->me_dummy != 0) {
894 // just do not add dummy filesystems
895 continue;
896 }
897
898 parameter_list_elem *path = NULL;
899 if (!(path = mp_int_fs_list_find(result.config.path_select_list, me->me_mountdir))) {
900 path = mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
901 }
902 path->best_match = me;
903 path->group = group;
904 set_all_thresholds(path, warn_freespace_units, crit_freespace_units,
905 warn_freespace_percent, crit_freespace_percent,
906 warn_freeinodes_percent, crit_freeinodes_percent);
907 }
908 }
909
910 // Set thresholds to the appropriate unit
911 for (parameter_list_elem *tmp = result.config.path_select_list.first; tmp;
912 tmp = mp_int_fs_list_get_next(tmp)) {
913
914 mp_perfdata_value factor = mp_create_pd_value(unit);
915
916 if (tmp->freespace_units.critical_is_set) {
917 tmp->freespace_units.critical =
918 mp_range_multiply(tmp->freespace_units.critical, factor);
919 }
920 if (tmp->freespace_units.warning_is_set) {
921 tmp->freespace_units.warning = mp_range_multiply(tmp->freespace_units.warning, factor);
922 }
923 }
924
925 return result;
1040} 926}
1041 927
1042bool 928void set_all_thresholds(parameter_list_elem *path, char *warn_freespace_units,
1043stat_path (struct parameter_list *p) 929 char *crit_freespace_units, char *warn_freespace_percent,
1044{ 930 char *crit_freespace_percent, char *warn_freeinodes_percent,
1045 /* Stat entry to check that dir exists and is accessible */ 931 char *crit_freeinodes_percent) {
1046 if (verbose >= 3) 932 mp_range_parsed tmp;
1047 printf("calling stat on %s\n", p->name); 933
1048 if (stat (p->name, &stat_buf[0])) { 934 if (warn_freespace_units) {
1049 if (verbose >= 3) 935 tmp = mp_parse_range_string(warn_freespace_units);
1050 printf("stat failed on %s\n", p->name); 936 path->freespace_units = mp_thresholds_set_warn(path->freespace_units, tmp.range);
1051 if (ignore_missing == true) { 937 }
1052 return false; 938
1053 } else { 939 if (crit_freespace_units) {
1054 printf("DISK %s - ", _("CRITICAL")); 940 tmp = mp_parse_range_string(crit_freespace_units);
1055 die (STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno)); 941 path->freespace_units = mp_thresholds_set_crit(path->freespace_units, tmp.range);
1056 } 942 }
1057 } 943
1058 return true; 944 if (warn_freespace_percent) {
945 tmp = mp_parse_range_string(warn_freespace_percent);
946 path->freespace_percent = mp_thresholds_set_warn(path->freespace_percent, tmp.range);
947 }
948
949 if (crit_freespace_percent) {
950 tmp = mp_parse_range_string(crit_freespace_percent);
951 path->freespace_percent = mp_thresholds_set_crit(path->freespace_percent, tmp.range);
952 }
953
954 if (warn_freeinodes_percent) {
955 tmp = mp_parse_range_string(warn_freeinodes_percent);
956 path->freeinodes_percent = mp_thresholds_set_warn(path->freeinodes_percent, tmp.range);
957 }
958
959 if (crit_freeinodes_percent) {
960 tmp = mp_parse_range_string(crit_freeinodes_percent);
961 path->freeinodes_percent = mp_thresholds_set_crit(path->freeinodes_percent, tmp.range);
962 }
1059} 963}
1060 964
965void print_help(void) {
966 print_revision(progname, NP_VERSION);
967
968 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
969 printf(COPYRIGHT, copyright, email);
970
971 printf("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
972 printf("%s\n",
973 _("and generates an alert if free space is less than one of the threshold values"));
974
975 printf("\n\n");
976
977 print_usage();
978
979 printf(UT_HELP_VRSN);
980 printf(UT_EXTRA_OPTS);
981
982 printf(" %s\n", "-w, --warning=INTEGER");
983 printf(" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
984 printf(" %s\n", "-w, --warning=PERCENT%");
985 printf(" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
986 printf(" %s\n", "-c, --critical=INTEGER");
987 printf(" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
988 printf(" %s\n", "-c, --critical=PERCENT%");
989 printf(" %s\n", _("Exit with CRITICAL status if less than PERCENT of disk space is free"));
990 printf(" %s\n", "-W, --iwarning=PERCENT%");
991 printf(" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
992 printf(" %s\n", "-K, --icritical=PERCENT%");
993 printf(" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
994 printf(" %s\n", "-p, --path=PATH, --partition=PARTITION");
995 printf(" %s\n",
996 _("Mount point or block device as emitted by the mount(8) command (may be repeated)"));
997 printf(" %s\n", "-x, --exclude_device=PATH <STRING>");
998 printf(" %s\n", _("Ignore device (only works if -p unspecified)"));
999 printf(" %s\n", "-C, --clear");
1000 printf(" %s\n", _("Clear thresholds"));
1001 printf(" %s\n", "-E, --exact-match");
1002 printf(" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
1003 printf(" %s\n", "-e, --errors-only");
1004 printf(" %s\n", _("Display only devices/mountpoints with errors"));
1005 printf(" %s\n", "-f, --freespace-ignore-reserved");
1006 printf(" %s\n", _("Don't account root-reserved blocks into freespace in perfdata"));
1007 printf(" %s\n", "-P, --iperfdata");
1008 printf(" %s\n", _("Display inode usage in perfdata"));
1009 printf(" %s\n", "-g, --group=NAME");
1010 printf(" %s\n",
1011 _("Group paths. Thresholds apply to (free-)space of all partitions together"));
1012 printf(" %s\n", "-l, --local");
1013 printf(" %s\n", _("Only check local filesystems"));
1014 printf(" %s\n", "-L, --stat-remote-fs");
1015 printf(
1016 " %s\n",
1017 _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
1018 printf(" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
1019 printf(" %s\n", "-M, --mountpoint");
1020 printf(" %s\n", _("Display the (block) device instead of the mount point"));
1021 printf(" %s\n", "-A, --all");
1022 printf(" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'"));
1023 printf(" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
1024 printf(" %s\n",
1025 _("Case insensitive regular expression for path/partition (may be repeated)"));
1026 printf(" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
1027 printf(" %s\n", _("Regular expression for path or partition (may be repeated)"));
1028 printf(" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
1029 printf(" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) "
1030 "(may be repeated)"));
1031 printf(" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
1032 printf(" %s\n",
1033 _("Regular expression to ignore selected path or partition (may be repeated)"));
1034 printf(" %s\n", "-n, --ignore-missing");
1035 printf(" %s\n",
1036 _("Return OK if no filesystem matches, filesystem does not exist or is inaccessible."));
1037 printf(" %s\n", _("(Provide this option before -p / -r / --ereg-path if used)"));
1038 printf(UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1039 printf(" %s\n", "-u, --units=STRING");
1040 printf(" %s\n", _("Select the unit used for the absolute value thresholds"));
1041 printf(" %s\n", _("Choose one of \"bytes\", \"KiB\", \"kB\", \"MiB\", \"MB\", \"GiB\", "
1042 "\"GB\", \"TiB\", \"TB\", \"PiB\", \"PB\" (default: MiB)"));
1043 printf(" %s\n", "-k, --kilobytes");
1044 printf(" %s\n", _("Same as '--units kB'"));
1045 printf(" %s\n", "--display-unit");
1046 printf(" %s\n", _("Select the unit used for in the output"));
1047 printf(" %s\n", _("Choose one of \"bytes\", \"KiB\", \"kB\", \"MiB\", \"MB\", \"GiB\", "
1048 "\"GB\", \"TiB\", \"TB\", \"PiB\", \"PB\" (default: MiB)"));
1049 printf(" %s\n", "-m, --megabytes");
1050 printf(" %s\n", _("Same as '--units MB'"));
1051 printf(UT_VERBOSE);
1052 printf(" %s\n", "-X, --exclude-type=TYPE_REGEX");
1053 printf(" %s\n",
1054 _("Ignore all filesystems of types matching given regex(7) (may be repeated)"));
1055 printf(" %s\n", "-N, --include-type=TYPE_REGEX");
1056 printf(
1057 " %s\n",
1058 _("Check only filesystems where the type matches this given regex(7) (may be repeated)"));
1059 printf(UT_OUTPUT_FORMAT);
1060
1061 printf("\n");
1062 printf("%s\n", _("General usage hints:"));
1063 printf(
1064 " %s\n",
1065 _("- Arguments are positional! \"-w 5 -c 1 -p /foo -w6 -c2 -p /bar\" is not the same as"));
1066 printf(" %s\n", _("\"-w 5 -c 1 -p /bar w6 -c2 -p /foo\"."));
1067 printf(" %s\n", _("- The syntax is broadly: \"{thresholds a} {paths a} -C {thresholds b} "
1068 "{thresholds b} ...\""));
1069
1070 printf("\n");
1071 printf("%s\n", _("Examples:"));
1072 printf(" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
1073 printf(" %s\n\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
1074 printf(" %s\n",
1075 "check_disk -w 100 -c 50 -C -w 1000 -c 500 -g sidDATA -r '^/oracle/SID/data.*$'");
1076 printf(
1077 " %s\n",
1078 _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
1079 printf(" %s\n\n",
1080 _("are grouped which means the freespace thresholds are applied to all disks together"));
1081 printf(" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar");
1082 printf(" %s\n",
1083 _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
1084
1085 printf(UT_SUPPORT);
1086}
1061 1087
1062void 1088void print_usage(void) {
1063get_stats (struct parameter_list *p, struct fs_usage *fsp) { 1089 printf("%s\n", _("Usage:"));
1064 struct parameter_list *p_list; 1090 printf(" %s {-w absolute_limit |-w percentage_limit%% | -W inode_percentage_limit } {-c "
1065 struct fs_usage tmpfsp; 1091 "absolute_limit|-c percentage_limit%% | -K "
1066 int first = 1; 1092 "inode_percentage_limit } {-p path | -x device}\n",
1093 progname);
1094 printf("[-C] [-E] [-e] [-f] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
1095 printf("[-t timeout] [-u unit] [-v] [-X type_regex] [-N type]\n");
1096}
1067 1097
1068 if (p->group == NULL) { 1098bool stat_path(parameter_list_elem *parameters, bool ignore_missing) {
1069 get_path_stats(p,fsp); 1099 /* Stat entry to check that dir exists and is accessible */
1070 } else { 1100 if (verbose >= 3) {
1071 /* find all group members */ 1101 printf("calling stat on %s\n", parameters->name);
1072 for (p_list = path_select_list; p_list; p_list=p_list->name_next) { 1102 }
1073#ifdef __CYGWIN__ 1103
1074 if (strncmp(p_list->name, "/cygdrive/", 10) != 0) 1104 struct stat stat_buf = {0};
1075 continue; 1105 if (stat(parameters->name, &stat_buf)) {
1076#endif 1106 if (verbose >= 3) {
1077 if (p_list->group && ! (strcmp(p_list->group, p->group))) { 1107 printf("stat failed on %s\n", parameters->name);
1078 if (! stat_path(p_list)) 1108 }
1079 continue; 1109 if (ignore_missing) {
1080 get_fs_usage (p_list->best_match->me_mountdir, p_list->best_match->me_devname, &tmpfsp); 1110 return false;
1081 get_path_stats(p_list, &tmpfsp); 1111 }
1082 if (verbose >= 3) 1112 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", 1113 die(STATE_CRITICAL, _("%s %s: %s\n"), parameters->name, _("is not accessible"),
1084 p_list->group, 1114 strerror(errno));
1085 tmpfsp.fsu_blocks, 1115 }
1086 tmpfsp.fsu_blocksize, 1116
1087 p_list->best_match->me_mountdir, 1117 return true;
1088 p_list->dused_units, 1118}
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 1119
1120static parameter_list_elem get_path_stats(parameter_list_elem parameters, const struct fs_usage fsp,
1121 bool freespace_ignore_reserved) {
1122 uintmax_t available = fsp.fsu_bavail;
1123 uintmax_t available_to_root = fsp.fsu_bfree;
1124 uintmax_t used = fsp.fsu_blocks - fsp.fsu_bfree;
1125 uintmax_t total;
1126
1127 if (freespace_ignore_reserved) {
1128 /* option activated : we subtract the root-reserved space from the total */
1129 total = fsp.fsu_blocks - available_to_root + available;
1130 } else {
1131 /* default behaviour : take all the blocks into account */
1132 total = fsp.fsu_blocks;
1133 }
1134
1135 parameters.used_bytes = used * fsp.fsu_blocksize;
1136 parameters.free_bytes = available * fsp.fsu_blocksize;
1137 parameters.total_bytes = total * fsp.fsu_blocksize;
1138
1139 /* Free file nodes. Not sure the workaround is required, but in case...*/
1140 parameters.inodes_free = fsp.fsu_ffree;
1141 parameters.inodes_free_to_root = fsp.fsu_ffree; /* Free file nodes for root. */
1142 parameters.inodes_used = fsp.fsu_files - fsp.fsu_ffree;
1143
1144 if (freespace_ignore_reserved) {
1145 /* option activated : we subtract the root-reserved inodes from the total */
1146 /* not all OS report fsp->fsu_favail, only the ones with statvfs syscall */
1147 /* for others, fsp->fsu_ffree == fsp->fsu_favail */
1148 parameters.inodes_total =
1149 fsp.fsu_files - parameters.inodes_free_to_root + parameters.inodes_free;
1150 } else {
1151 /* default behaviour : take all the inodes into account */
1152 parameters.inodes_total = fsp.fsu_files;
1153 }
1154
1155 return parameters;
1129} 1156}
1130 1157
1131void 1158mp_subcheck evaluate_filesystem(measurement_unit measurement_unit, bool display_inodes_perfdata,
1132get_path_stats (struct parameter_list *p, struct fs_usage *fsp) { 1159 byte_unit unit) {
1133 p->available = fsp->fsu_bavail; 1160 mp_subcheck result = mp_subcheck_init();
1134 p->available_to_root = fsp->fsu_bfree; 1161 result = mp_set_subcheck_default_state(result, STATE_UNKNOWN);
1135 p->used = fsp->fsu_blocks - fsp->fsu_bfree; 1162 xasprintf(&result.output, "%s", measurement_unit.name);
1136 if (freespace_ignore_reserved) { 1163
1137 /* option activated : we subtract the root-reserved space from the total */ 1164 if (!measurement_unit.is_group && measurement_unit.filesystem_type) {
1138 p->total = fsp->fsu_blocks - p->available_to_root + p->available; 1165 xasprintf(&result.output, "%s (%s)", result.output, measurement_unit.filesystem_type);
1139 } else { 1166 }
1140 /* default behaviour : take all the blocks into account */ 1167
1141 p->total = fsp->fsu_blocks; 1168 /* Threshold comparisons */
1142 } 1169
1143 1170 // ===============================
1144 p->dused_units = p->used*fsp->fsu_blocksize/mult; 1171 // Free space absolute values test
1145 p->dfree_units = p->available*fsp->fsu_blocksize/mult; 1172 mp_subcheck freespace_bytes_sc = mp_subcheck_init();
1146 p->dtotal_units = p->total*fsp->fsu_blocksize/mult; 1173 freespace_bytes_sc = mp_set_subcheck_default_state(freespace_bytes_sc, STATE_OK);
1147 /* Free file nodes. Not sure the workaround is required, but in case...*/ 1174
1148 p->inodes_free = fsp->fsu_ffree; 1175 if (unit != Humanized) {
1149 p->inodes_free_to_root = fsp->fsu_ffree; /* Free file nodes for root. */ 1176 xasprintf(&freespace_bytes_sc.output, "Free space absolute: %ju%s (of %ju%s)",
1150 p->inodes_used = fsp->fsu_files - fsp->fsu_ffree; 1177 (uintmax_t)(measurement_unit.free_bytes / unit), get_unit_string(unit),
1151 if (freespace_ignore_reserved) { 1178 (uintmax_t)(measurement_unit.total_bytes / unit), get_unit_string(unit));
1152 /* option activated : we subtract the root-reserved inodes from the total */ 1179 } else {
1153 /* not all OS report fsp->fsu_favail, only the ones with statvfs syscall */ 1180 xasprintf(&freespace_bytes_sc.output, "Free space absolute: %s (of %s)",
1154 /* for others, fsp->fsu_ffree == fsp->fsu_favail */ 1181 humanize_byte_value(measurement_unit.free_bytes, false),
1155 p->inodes_total = fsp->fsu_files - p->inodes_free_to_root + p->inodes_free; 1182 humanize_byte_value((unsigned long long)measurement_unit.total_bytes, false));
1156 } else { 1183 }
1157 /* default behaviour : take all the inodes into account */ 1184
1158 p->inodes_total = fsp->fsu_files; 1185 mp_perfdata used_space = perfdata_init();
1159 } 1186 used_space.label = measurement_unit.name;
1160 np_add_name(&seen, p->best_match->me_mountdir); 1187 used_space.value = mp_create_pd_value(measurement_unit.free_bytes);
1188 used_space = mp_set_pd_max_value(used_space, mp_create_pd_value(measurement_unit.total_bytes));
1189 used_space = mp_set_pd_min_value(used_space, mp_create_pd_value(0));
1190 used_space.uom = "B";
1191 used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
1192 freespace_bytes_sc = mp_set_subcheck_state(freespace_bytes_sc, mp_get_pd_status(used_space));
1193
1194 // special case for absolute space thresholds here:
1195 // if absolute values are not set, compute the thresholds from percentage thresholds
1196 mp_thresholds temp_thlds = measurement_unit.freespace_bytes_thresholds;
1197 if (!temp_thlds.critical_is_set &&
1198 measurement_unit.freespace_percent_thresholds.critical_is_set) {
1199 mp_range tmp_range = measurement_unit.freespace_percent_thresholds.critical;
1200
1201 if (!tmp_range.end_infinity) {
1202 tmp_range.end = mp_create_pd_value(mp_get_pd_value(tmp_range.end) / 100 *
1203 measurement_unit.total_bytes);
1204 }
1205
1206 if (!tmp_range.start_infinity) {
1207 tmp_range.start = mp_create_pd_value(mp_get_pd_value(tmp_range.start) / 100 *
1208 measurement_unit.total_bytes);
1209 }
1210 measurement_unit.freespace_bytes_thresholds =
1211 mp_thresholds_set_crit(measurement_unit.freespace_bytes_thresholds, tmp_range);
1212 used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
1213 }
1214
1215 if (!temp_thlds.warning_is_set &&
1216 measurement_unit.freespace_percent_thresholds.warning_is_set) {
1217 mp_range tmp_range = measurement_unit.freespace_percent_thresholds.warning;
1218 if (!tmp_range.end_infinity) {
1219 tmp_range.end = mp_create_pd_value(mp_get_pd_value(tmp_range.end) / 100 *
1220 measurement_unit.total_bytes);
1221 }
1222 if (!tmp_range.start_infinity) {
1223 tmp_range.start = mp_create_pd_value(mp_get_pd_value(tmp_range.start) / 100 *
1224 measurement_unit.total_bytes);
1225 }
1226 measurement_unit.freespace_bytes_thresholds =
1227 mp_thresholds_set_warn(measurement_unit.freespace_bytes_thresholds, tmp_range);
1228 used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
1229 }
1230
1231 mp_add_perfdata_to_subcheck(&freespace_bytes_sc, used_space);
1232 mp_add_subcheck_to_subcheck(&result, freespace_bytes_sc);
1233
1234 // ==========================
1235 // Free space percentage test
1236 mp_subcheck freespace_percent_sc = mp_subcheck_init();
1237 freespace_percent_sc = mp_set_subcheck_default_state(freespace_percent_sc, STATE_OK);
1238
1239 double free_percentage =
1240 calculate_percent(measurement_unit.free_bytes, measurement_unit.total_bytes);
1241 xasprintf(&freespace_percent_sc.output, "Free space percentage: %g%%", free_percentage);
1242
1243 // Using perfdata here just to get to the test result
1244 mp_perfdata free_space_percent_pd = perfdata_init();
1245 free_space_percent_pd.value = mp_create_pd_value(free_percentage);
1246 free_space_percent_pd =
1247 mp_pd_set_thresholds(free_space_percent_pd, measurement_unit.freespace_percent_thresholds);
1248
1249 freespace_percent_sc =
1250 mp_set_subcheck_state(freespace_percent_sc, mp_get_pd_status(free_space_percent_pd));
1251 mp_add_subcheck_to_subcheck(&result, freespace_percent_sc);
1252
1253 // ================
1254 // Free inodes test
1255 // Only ever useful if the number of inodes is static (e.g. ext4),
1256 // not when it is dynamic (e.g btrfs)
1257 // Assumption: if the total number of inodes == 0, we have such a case and just skip the test
1258 if (measurement_unit.inodes_total > 0) {
1259 mp_subcheck freeindodes_percent_sc = mp_subcheck_init();
1260 freeindodes_percent_sc = mp_set_subcheck_default_state(freeindodes_percent_sc, STATE_OK);
1261
1262 double free_inode_percentage =
1263 calculate_percent(measurement_unit.inodes_free, measurement_unit.inodes_total);
1264
1265 if (verbose > 0) {
1266 printf("free inode percentage computed: %g\n", free_inode_percentage);
1267 }
1268
1269 xasprintf(&freeindodes_percent_sc.output, "Inodes free: %g%% (%ju of %ju)",
1270 free_inode_percentage, measurement_unit.inodes_free,
1271 measurement_unit.inodes_total);
1272
1273 mp_perfdata inodes_pd = perfdata_init();
1274 xasprintf(&inodes_pd.label, "%s (inodes)", measurement_unit.name);
1275 inodes_pd = mp_set_pd_value(inodes_pd, measurement_unit.inodes_used);
1276 inodes_pd =
1277 mp_set_pd_max_value(inodes_pd, mp_create_pd_value(measurement_unit.inodes_total));
1278 inodes_pd = mp_set_pd_min_value(inodes_pd, mp_create_pd_value(0));
1279
1280 mp_thresholds absolut_inode_thresholds = measurement_unit.freeinodes_percent_thresholds;
1281
1282 if (absolut_inode_thresholds.critical_is_set) {
1283 absolut_inode_thresholds.critical =
1284 mp_range_multiply(absolut_inode_thresholds.critical,
1285 mp_create_pd_value(measurement_unit.inodes_total / 100));
1286 }
1287 if (absolut_inode_thresholds.warning_is_set) {
1288 absolut_inode_thresholds.warning =
1289 mp_range_multiply(absolut_inode_thresholds.warning,
1290 mp_create_pd_value(measurement_unit.inodes_total / 100));
1291 }
1292
1293 inodes_pd = mp_pd_set_thresholds(inodes_pd, absolut_inode_thresholds);
1294
1295 freeindodes_percent_sc =
1296 mp_set_subcheck_state(freeindodes_percent_sc, mp_get_pd_status(inodes_pd));
1297 if (display_inodes_perfdata) {
1298 mp_add_perfdata_to_subcheck(&freeindodes_percent_sc, inodes_pd);
1299 }
1300 mp_add_subcheck_to_subcheck(&result, freeindodes_percent_sc);
1301 }
1302
1303 return result;
1161} 1304}
diff --git a/plugins/check_disk.d/utils_disk.c b/plugins/check_disk.d/utils_disk.c
new file mode 100644
index 00000000..0b89018d
--- /dev/null
+++ b/plugins/check_disk.d/utils_disk.c
@@ -0,0 +1,528 @@
1/*****************************************************************************
2 *
3 * Library for check_disk
4 *
5 * License: GPL
6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7 *
8 * Description:
9 *
10 * This file contains utilities for check_disk. These are tested by libtap
11 *
12 *
13 * This program is free software: you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation, either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 *
26 *
27 *****************************************************************************/
28
29#include "../common.h"
30#include "utils_disk.h"
31#include "../../gl/fsusage.h"
32#include "../../lib/thresholds.h"
33#include "../../lib/states.h"
34#include <stdint.h>
35#include <stdio.h>
36#include <string.h>
37#include <assert.h>
38
39void np_add_name(struct name_list **list, const char *name) {
40 struct name_list *new_entry;
41 new_entry = (struct name_list *)malloc(sizeof *new_entry);
42 new_entry->name = (char *)name;
43 new_entry->next = *list;
44 *list = new_entry;
45}
46
47/* @brief Initialises a new regex at the begin of list via regcomp(3)
48 *
49 * @details if the regex fails to compile the error code of regcomp(3) is returned
50 * and list is not modified, otherwise list is modified to point to the new
51 * element
52 * @param list Pointer to a linked list of regex_list elements
53 * @param regex the string containing the regex which should be inserted into the list
54 * @param clags the cflags parameter for regcomp(3)
55 */
56int np_add_regex(struct regex_list **list, const char *regex, int cflags) {
57 struct regex_list *new_entry = (struct regex_list *)malloc(sizeof *new_entry);
58
59 if (new_entry == NULL) {
60 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
61 }
62
63 int regcomp_result = regcomp(&new_entry->regex, regex, cflags);
64
65 if (!regcomp_result) {
66 // regcomp succeeded
67 new_entry->next = *list;
68 *list = new_entry;
69
70 return 0;
71 }
72 // regcomp failed
73 free(new_entry);
74
75 return regcomp_result;
76}
77
78parameter_list_elem parameter_list_init(const char *name) {
79 parameter_list_elem result = {
80 .name = strdup(name),
81 .best_match = NULL,
82
83 .freespace_units = mp_thresholds_init(),
84 .freespace_percent = mp_thresholds_init(),
85 .freeinodes_percent = mp_thresholds_init(),
86
87 .group = NULL,
88
89 .inodes_total = 0,
90 .inodes_free = 0,
91 .inodes_free_to_root = 0,
92 .inodes_used = 0,
93
94 .used_bytes = 0,
95 .free_bytes = 0,
96 .total_bytes = 0,
97
98 .next = NULL,
99 .prev = NULL,
100 };
101 return result;
102}
103
104/* Returns true if name is in list */
105bool np_find_name(struct name_list *list, const char *name) {
106 if (list == NULL || name == NULL) {
107 return false;
108 }
109 for (struct name_list *iterator = list; iterator; iterator = iterator->next) {
110 if (!strcmp(name, iterator->name)) {
111 return true;
112 }
113 }
114 return false;
115}
116
117/* Returns true if name is in list */
118bool np_find_regmatch(struct regex_list *list, const char *name) {
119 if (name == NULL) {
120 return false;
121 }
122
123 size_t len = strlen(name);
124
125 for (; list; list = list->next) {
126 /* Emulate a full match as if surrounded with ^( )$
127 by checking whether the match spans the whole name */
128 regmatch_t dummy_match;
129 if (!regexec(&list->regex, name, 1, &dummy_match, 0) && dummy_match.rm_so == 0 &&
130 dummy_match.rm_eo == len) {
131 return true;
132 }
133 }
134
135 return false;
136}
137
138bool np_seen_name(struct name_list *list, const char *name) {
139 for (struct name_list *iterator = list; iterator; iterator = iterator->next) {
140 if (!strcmp(iterator->name, name)) {
141 return true;
142 }
143 }
144 return false;
145}
146
147bool np_regex_match_mount_entry(struct mount_entry *me, regex_t *re) {
148 return ((regexec(re, me->me_devname, (size_t)0, NULL, 0) == 0) ||
149 (regexec(re, me->me_mountdir, (size_t)0, NULL, 0) == 0));
150}
151
152check_disk_config check_disk_config_init() {
153 check_disk_config tmp = {
154 .erronly = false,
155 .display_mntp = false,
156 .show_local_fs = false,
157 .stat_remote_fs = false,
158 .display_inodes_perfdata = false,
159
160 .exact_match = false,
161 .freespace_ignore_reserved = false,
162
163 .ignore_missing = false,
164 .path_ignored = false,
165
166 // FS Filters
167 .fs_exclude_list = NULL,
168 .fs_include_list = NULL,
169 .device_path_exclude_list = NULL,
170
171 // Actual filesystems paths to investigate
172 .path_select_list = filesystem_list_init(),
173
174 .mount_list = NULL,
175 .seen = NULL,
176
177 .display_unit = Humanized,
178 // .unit = MebiBytes,
179
180 .output_format_is_set = false,
181 };
182 return tmp;
183}
184
185char *get_unit_string(byte_unit_enum unit) {
186 switch (unit) {
187 case Bytes:
188 return "Bytes";
189 case KibiBytes:
190 return "KiB";
191 case MebiBytes:
192 return "MiB";
193 case GibiBytes:
194 return "GiB";
195 case TebiBytes:
196 return "TiB";
197 case PebiBytes:
198 return "PiB";
199 case ExbiBytes:
200 return "EiB";
201 case KiloBytes:
202 return "KB";
203 case MegaBytes:
204 return "MB";
205 case GigaBytes:
206 return "GB";
207 case TeraBytes:
208 return "TB";
209 case PetaBytes:
210 return "PB";
211 case ExaBytes:
212 return "EB";
213 default:
214 assert(false);
215 }
216}
217
218measurement_unit measurement_unit_init() {
219 measurement_unit tmp = {
220 .name = NULL,
221 .filesystem_type = NULL,
222 .is_group = false,
223
224 .freeinodes_percent_thresholds = mp_thresholds_init(),
225 .freespace_percent_thresholds = mp_thresholds_init(),
226 .freespace_bytes_thresholds = mp_thresholds_init(),
227
228 .free_bytes = 0,
229 .used_bytes = 0,
230 .total_bytes = 0,
231
232 .inodes_total = 0,
233 .inodes_free = 0,
234 .inodes_free_to_root = 0,
235 .inodes_used = 0,
236 };
237 return tmp;
238}
239
240// Add a given element to the list, memory for the new element is freshly allocated
241// Returns a pointer to new element
242measurement_unit_list *add_measurement_list(measurement_unit_list *list, measurement_unit elem) {
243 // find last element
244 measurement_unit_list *new = NULL;
245 if (list == NULL) {
246 new = calloc(1, sizeof(measurement_unit_list));
247 if (new == NULL) {
248 die(STATE_UNKNOWN, _("allocation failed"));
249 }
250 } else {
251 measurement_unit_list *list_elem = list;
252 while (list_elem->next != NULL) {
253 list_elem = list_elem->next;
254 }
255
256 new = calloc(1, sizeof(measurement_unit_list));
257 if (new == NULL) {
258 die(STATE_UNKNOWN, _("allocation failed"));
259 }
260
261 list_elem->next = new;
262 }
263
264 new->unit = elem;
265 new->next = NULL;
266 return new;
267}
268
269measurement_unit add_filesystem_to_measurement_unit(measurement_unit unit,
270 parameter_list_elem filesystem) {
271
272 unit.free_bytes += filesystem.free_bytes;
273 unit.used_bytes += filesystem.used_bytes;
274 unit.total_bytes += filesystem.total_bytes;
275
276 unit.inodes_total += filesystem.inodes_total;
277 unit.inodes_free += filesystem.inodes_free;
278 unit.inodes_free_to_root += filesystem.inodes_free_to_root;
279 unit.inodes_used += filesystem.inodes_used;
280 return unit;
281}
282
283measurement_unit create_measurement_unit_from_filesystem(parameter_list_elem filesystem,
284 bool display_mntp) {
285 measurement_unit result = measurement_unit_init();
286 if (!display_mntp) {
287 result.name = strdup(filesystem.best_match->me_mountdir);
288 } else {
289 result.name = strdup(filesystem.best_match->me_devname);
290 }
291
292 if (filesystem.group) {
293 result.is_group = true;
294 } else {
295 result.is_group = false;
296 if (filesystem.best_match) {
297 result.filesystem_type = filesystem.best_match->me_type;
298 }
299 }
300
301 result.freeinodes_percent_thresholds = filesystem.freeinodes_percent;
302 result.freespace_percent_thresholds = filesystem.freespace_percent;
303 result.freespace_bytes_thresholds = filesystem.freespace_units;
304 result.free_bytes = filesystem.free_bytes;
305 result.total_bytes = filesystem.total_bytes;
306 result.used_bytes = filesystem.used_bytes;
307 result.inodes_total = filesystem.inodes_total;
308 result.inodes_used = filesystem.inodes_used;
309 result.inodes_free = filesystem.inodes_free;
310 result.inodes_free_to_root = filesystem.inodes_free_to_root;
311 return result;
312}
313
314#define RANDOM_STRING_LENGTH 64
315
316char *humanize_byte_value(unsigned long long value, bool use_si_units) {
317 // Idea: A reasonable output should have at most 3 orders of magnitude
318 // before the decimal separator
319 // 353GiB is ok, 2444 GiB should be 2.386 TiB
320 char *result = calloc(RANDOM_STRING_LENGTH, sizeof(char));
321 if (result == NULL) {
322 die(STATE_UNKNOWN, _("allocation failed"));
323 }
324 const byte_unit KibiBytes_factor = 1024;
325 const byte_unit MebiBytes_factor = 1048576;
326 const byte_unit GibiBytes_factor = 1073741824;
327 const byte_unit TebiBytes_factor = 1099511627776;
328 const byte_unit PebiBytes_factor = 1125899906842624;
329 const byte_unit ExbiBytes_factor = 1152921504606846976;
330 const byte_unit KiloBytes_factor = 1000;
331 const byte_unit MegaBytes_factor = 1000000;
332 const byte_unit GigaBytes_factor = 1000000000;
333 const byte_unit TeraBytes_factor = 1000000000000;
334 const byte_unit PetaBytes_factor = 1000000000000000;
335 const byte_unit ExaBytes_factor = 1000000000000000000;
336
337 if (use_si_units) {
338 // SI units, powers of 10
339 if (value < KiloBytes_factor) {
340 snprintf(result, RANDOM_STRING_LENGTH, "%llu B", value);
341 } else if (value < MegaBytes_factor) {
342 snprintf(result, RANDOM_STRING_LENGTH, "%llu KB", value / KiloBytes_factor);
343 } else if (value < GigaBytes_factor) {
344 snprintf(result, RANDOM_STRING_LENGTH, "%llu MB", value / MegaBytes_factor);
345 } else if (value < TeraBytes_factor) {
346 snprintf(result, RANDOM_STRING_LENGTH, "%llu GB", value / GigaBytes_factor);
347 } else if (value < PetaBytes_factor) {
348 snprintf(result, RANDOM_STRING_LENGTH, "%llu TB", value / TeraBytes_factor);
349 } else if (value < ExaBytes_factor) {
350 snprintf(result, RANDOM_STRING_LENGTH, "%llu PB", value / PetaBytes_factor);
351 } else {
352 snprintf(result, RANDOM_STRING_LENGTH, "%llu EB", value / ExaBytes_factor);
353 }
354 } else {
355 // IEC units, powers of 2 ^ 10
356 if (value < KibiBytes_factor) {
357 snprintf(result, RANDOM_STRING_LENGTH, "%llu B", value);
358 } else if (value < MebiBytes_factor) {
359 snprintf(result, RANDOM_STRING_LENGTH, "%llu KiB", value / KibiBytes_factor);
360 } else if (value < GibiBytes_factor) {
361 snprintf(result, RANDOM_STRING_LENGTH, "%llu MiB", value / MebiBytes_factor);
362 } else if (value < TebiBytes_factor) {
363 snprintf(result, RANDOM_STRING_LENGTH, "%llu GiB", value / GibiBytes_factor);
364 } else if (value < PebiBytes_factor) {
365 snprintf(result, RANDOM_STRING_LENGTH, "%llu TiB", value / TebiBytes_factor);
366 } else if (value < ExbiBytes_factor) {
367 snprintf(result, RANDOM_STRING_LENGTH, "%llu PiB", value / PebiBytes_factor);
368 } else {
369 snprintf(result, RANDOM_STRING_LENGTH, "%llu EiB", value / ExbiBytes_factor);
370 }
371 }
372
373 return result;
374}
375
376filesystem_list filesystem_list_init() {
377 filesystem_list tmp = {
378 .length = 0,
379 .first = NULL,
380 };
381 return tmp;
382}
383
384parameter_list_elem *mp_int_fs_list_append(filesystem_list *list, const char *name) {
385 parameter_list_elem *current = list->first;
386 parameter_list_elem *new_path = (struct parameter_list *)malloc(sizeof *new_path);
387 *new_path = parameter_list_init(name);
388
389 if (current == NULL) {
390 list->first = new_path;
391 new_path->prev = NULL;
392 list->length = 1;
393 } else {
394 while (current->next) {
395 current = current->next;
396 }
397 current->next = new_path;
398 new_path->prev = current;
399 list->length++;
400 }
401 return new_path;
402}
403
404parameter_list_elem *mp_int_fs_list_find(filesystem_list list, const char *name) {
405 if (list.length == 0) {
406 return NULL;
407 }
408
409 for (parameter_list_elem *temp_list = list.first; temp_list; temp_list = temp_list->next) {
410 if (!strcmp(temp_list->name, name)) {
411 return temp_list;
412 }
413 }
414
415 return NULL;
416}
417
418parameter_list_elem *mp_int_fs_list_del(filesystem_list *list, parameter_list_elem *item) {
419 if (list->length == 0) {
420 return NULL;
421 }
422
423 if (item == NULL) {
424 // Got NULL for item, interpret this as "delete first element"
425 // as a kind of compatibility to the old function
426 item = list->first;
427 }
428
429 if (list->first == item) {
430 list->length--;
431
432 list->first = item->next;
433 if (list->first) {
434 list->first->prev = NULL;
435 }
436 return list->first;
437 }
438
439 // Was not the first element, continue
440 parameter_list_elem *prev = list->first;
441 parameter_list_elem *current = list->first->next;
442
443 while (current != item && current != NULL) {
444 prev = current;
445 current = current->next;
446 }
447
448 if (current == NULL) {
449 // didn't find that element ....
450 return NULL;
451 }
452
453 // remove the element
454 parameter_list_elem *next = current->next;
455 prev->next = next;
456 list->length--;
457 if (next) {
458 next->prev = prev;
459 }
460
461 if (item->name) {
462 free(item->name);
463 }
464 free(item);
465
466 return next;
467}
468
469parameter_list_elem *mp_int_fs_list_get_next(parameter_list_elem *current) {
470 if (!current) {
471 return NULL;
472 }
473 return current->next;
474}
475
476void mp_int_fs_list_set_best_match(filesystem_list list, struct mount_entry *mount_list,
477 bool exact) {
478 for (parameter_list_elem *elem = list.first; elem; elem = mp_int_fs_list_get_next(elem)) {
479 if (!elem->best_match) {
480 size_t name_len = strlen(elem->name);
481 struct mount_entry *best_match = NULL;
482
483 /* set best match if path name exactly matches a mounted device name */
484 for (struct mount_entry *mount_entry = mount_list; mount_entry;
485 mount_entry = mount_entry->me_next) {
486 if (strcmp(mount_entry->me_devname, elem->name) == 0) {
487 struct fs_usage fsp;
488 if (get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp) >=
489 0) {
490 best_match = mount_entry;
491 }
492 }
493 }
494
495 /* set best match by directory name if no match was found by devname */
496 if (!best_match) {
497 size_t best_match_len = 0;
498 for (struct mount_entry *mount_entry = mount_list; mount_entry;
499 mount_entry = mount_entry->me_next) {
500 size_t len = strlen(mount_entry->me_mountdir);
501
502 if ((!exact &&
503 (best_match_len <= len && len <= name_len &&
504 (len == 1 || strncmp(mount_entry->me_mountdir, elem->name, len) == 0))) ||
505 (exact && strcmp(mount_entry->me_mountdir, elem->name) == 0)) {
506 struct fs_usage fsp;
507
508 if (get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp) >=
509 0) {
510 best_match = mount_entry;
511 best_match_len = len;
512 }
513 }
514 }
515 }
516
517 if (best_match) {
518 elem->best_match = best_match;
519 } else {
520 elem->best_match =
521 NULL; /* Not sure why this is needed as it should be null on initialisation */
522 }
523
524 // No filesystem without a mount_entry!
525 // assert(elem->best_match != NULL);
526 }
527 }
528}
diff --git a/plugins/check_disk.d/utils_disk.h b/plugins/check_disk.d/utils_disk.h
new file mode 100644
index 00000000..c96d4296
--- /dev/null
+++ b/plugins/check_disk.d/utils_disk.h
@@ -0,0 +1,160 @@
1#pragma once
2/* Header file for utils_disk */
3
4#include "../../config.h"
5#include "../../gl/mountlist.h"
6#include "../../lib/utils_base.h"
7#include "../../lib/output.h"
8#include "regex.h"
9#include <stdint.h>
10
11typedef unsigned long long byte_unit;
12
13typedef enum {
14 Humanized,
15 Bytes,
16 KibiBytes,
17 MebiBytes,
18 GibiBytes,
19 TebiBytes,
20 PebiBytes,
21 ExbiBytes,
22 KiloBytes,
23 MegaBytes,
24 GigaBytes,
25 TeraBytes,
26 PetaBytes,
27 ExaBytes,
28} byte_unit_enum;
29
30typedef struct name_list string_list;
31struct name_list {
32 char *name;
33 string_list *next;
34};
35
36struct regex_list {
37 regex_t regex;
38 struct regex_list *next;
39};
40
41typedef struct parameter_list parameter_list_elem;
42struct parameter_list {
43 char *name;
44 char *group;
45
46 mp_thresholds freespace_units;
47 mp_thresholds freespace_percent;
48 mp_thresholds freeinodes_percent;
49
50 struct mount_entry *best_match;
51
52 uintmax_t inodes_free_to_root;
53 uintmax_t inodes_free;
54 uintmax_t inodes_used;
55 uintmax_t inodes_total;
56
57 uint64_t used_bytes;
58 uint64_t free_bytes;
59 uint64_t total_bytes;
60
61 parameter_list_elem *next;
62 parameter_list_elem *prev;
63};
64
65typedef struct {
66 size_t length;
67 parameter_list_elem *first;
68} filesystem_list;
69
70filesystem_list filesystem_list_init();
71
72typedef struct {
73 char *name;
74 char *filesystem_type;
75 bool is_group;
76
77 mp_thresholds freespace_bytes_thresholds;
78 mp_thresholds freespace_percent_thresholds;
79 mp_thresholds freeinodes_percent_thresholds;
80
81 uintmax_t inodes_free_to_root;
82 uintmax_t inodes_free;
83 uintmax_t inodes_used;
84 uintmax_t inodes_total;
85
86 uintmax_t used_bytes;
87 uintmax_t free_bytes;
88 uintmax_t total_bytes;
89} measurement_unit;
90
91typedef struct measurement_unit_list measurement_unit_list;
92struct measurement_unit_list {
93 measurement_unit unit;
94 measurement_unit_list *next;
95};
96
97typedef struct {
98 // Output options
99 bool erronly;
100 bool display_mntp;
101 /* show only local filesystems. */
102 bool show_local_fs;
103 /* show only local filesystems but call stat() on remote ones. */
104 bool stat_remote_fs;
105 bool display_inodes_perfdata;
106
107 bool exact_match;
108 bool freespace_ignore_reserved;
109
110 bool ignore_missing;
111 bool path_ignored;
112
113 /* Linked list of filesystem types to omit.
114 If the list is empty, don't exclude any types. */
115 struct regex_list *fs_exclude_list;
116 /* Linked list of filesystem types to check.
117 If the list is empty, include all types. */
118 struct regex_list *fs_include_list;
119 struct name_list *device_path_exclude_list;
120 filesystem_list path_select_list;
121 /* Linked list of mounted filesystems. */
122 struct mount_entry *mount_list;
123 struct name_list *seen;
124
125 byte_unit_enum display_unit;
126 // byte_unit unit;
127
128 bool output_format_is_set;
129 mp_output_format output_format;
130} check_disk_config;
131
132void np_add_name(struct name_list **list, const char *name);
133bool np_find_name(struct name_list *list, const char *name);
134bool np_seen_name(struct name_list *list, const char *name);
135int np_add_regex(struct regex_list **list, const char *regex, int cflags);
136bool np_find_regmatch(struct regex_list *list, const char *name);
137
138parameter_list_elem parameter_list_init(const char *);
139
140parameter_list_elem *mp_int_fs_list_append(filesystem_list *list, const char *name);
141parameter_list_elem *mp_int_fs_list_find(filesystem_list list, const char *name);
142parameter_list_elem *mp_int_fs_list_del(filesystem_list *list, parameter_list_elem *item);
143parameter_list_elem *mp_int_fs_list_get_next(parameter_list_elem *current);
144void mp_int_fs_list_set_best_match(filesystem_list list, struct mount_entry *mount_list,
145 bool exact);
146
147measurement_unit measurement_unit_init();
148measurement_unit_list *add_measurement_list(measurement_unit_list *list, measurement_unit elem);
149measurement_unit add_filesystem_to_measurement_unit(measurement_unit unit,
150 parameter_list_elem filesystem);
151measurement_unit create_measurement_unit_from_filesystem(parameter_list_elem filesystem,
152 bool display_mntp);
153
154int search_parameter_list(parameter_list_elem *list, const char *name);
155bool np_regex_match_mount_entry(struct mount_entry *, regex_t *);
156
157char *get_unit_string(byte_unit_enum);
158check_disk_config check_disk_config_init();
159
160char *humanize_byte_value(unsigned long long value, bool use_si_units);
diff --git a/plugins/check_dns.c b/plugins/check_dns.c
index 468bc958..56f91dae 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,634 @@ 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*/,
52char dns_server[ADDRESS_LENGTH] = ""; 52 const char /*dns_server*/[ADDRESS_LENGTH]);
53char ptr_server[ADDRESS_LENGTH] = ""; 53static bool ip_match_cidr(const char * /*addr*/, const char * /*cidr_ro*/);
54bool verbose = false; 54static unsigned long ip2long(const char * /*src*/);
55char **expected_address = NULL; 55static void print_help(void);
56int expected_address_cnt = 0; 56void print_usage(void);
57bool expect_nxdomain = false; 57
58 58static bool verbose = false;
59bool expect_authority = false; 59
60bool all_match = false; 60static int qstrcmp(const void *p1, const void *p2) {
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 61 /* The actual arguments to this function are "pointers to
67 pointers to char", but strcmp() arguments are "pointers 62 pointers to char", but strcmp() arguments are "pointers
68 to char", hence the following cast plus dereference */ 63 to char", hence the following cast plus dereference */
69 return strcmp(* (char * const *) p1, * (char * const *) p2); 64 return strcmp(*(char *const *)p1, *(char *const *)p2);
70} 65}
71 66
67int main(int argc, char **argv) {
68 setlocale(LC_ALL, "");
69 bindtextdomain(PACKAGE, LOCALEDIR);
70 textdomain(PACKAGE);
72 71
73int 72 /* Set signal handling and alarm */
74main (int argc, char **argv) 73 if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
75{ 74 usage_va(_("Cannot catch SIGALRM"));
76 char *command_line = NULL; 75 }
77 char input_buffer[MAX_INPUT_BUFFER]; 76
78 char *address = NULL; /* comma separated str with addrs/ptrs (sorted) */ 77 /* Parse extra opts if any */
79 char **addresses = NULL; 78 argv = np_extra_opts(&argc, argv, progname);
80 int n_addresses = 0; 79
81 char *msg = NULL; 80 check_dns_config_wrapper tmp = process_arguments(argc, argv);
82 char *temp_buffer = NULL; 81
83 bool non_authoritative = false; 82 if (tmp.errorcode == ERROR) {
84 int result = STATE_UNKNOWN; 83 usage_va(_("Could not parse arguments"));
85 double elapsed_time; 84 }
86 long microsec; 85
87 struct timeval tv; 86 const check_dns_config config = tmp.config;
88 bool parse_address = false; /* This flag scans for Address: but only after Name: */ 87
89 output chld_out, chld_err; 88 char *command_line = NULL;
90 bool is_nxdomain = false; 89 /* get the command to run */
91 90 xasprintf(&command_line, "%s %s %s", NSLOOKUP_COMMAND, config.query_address, config.dns_server);
92 setlocale (LC_ALL, ""); 91
93 bindtextdomain (PACKAGE, LOCALEDIR); 92 struct timeval tv;
94 textdomain (PACKAGE); 93 alarm(timeout_interval);
95 94 gettimeofday(&tv, NULL);
96 /* Set signal handling and alarm */ 95
97 if (signal (SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) { 96 if (verbose) {
98 usage_va(_("Cannot catch SIGALRM")); 97 printf("%s\n", command_line);
99 } 98 }
100 99
101 /* Parse extra opts if any */ 100 output chld_out;
102 argv=np_extra_opts (&argc, argv, progname); 101 output chld_err;
103 102 char *msg = NULL;
104 if (process_arguments (argc, argv) == ERROR) { 103 mp_state_enum result = STATE_UNKNOWN;
105 usage_va(_("Could not parse arguments")); 104 /* run the command */
106 } 105 if ((np_runcmd(command_line, &chld_out, &chld_err, 0)) != 0) {
107 106 msg = (char *)_("nslookup returned an error status");
108 /* get the command to run */ 107 result = STATE_WARNING;
109 xasprintf (&command_line, "%s %s %s", NSLOOKUP_COMMAND, query_address, dns_server); 108 }
110 109
111 alarm (timeout_interval); 110 /* =====
112 gettimeofday (&tv, NULL); 111 * scan stdout, main results get retrieved here
113 112 * =====
114 if (verbose) 113 */
115 printf ("%s\n", command_line); 114 char *address = NULL; /* comma separated str with addrs/ptrs (sorted) */
116 115 char **addresses = NULL; // All addresses parsed from stdout
117 /* run the command */ 116 size_t n_addresses = 0; // counter for retrieved addresses
118 if((np_runcmd(command_line, &chld_out, &chld_err, 0)) != 0) { 117 bool non_authoritative = false;
119 msg = (char *)_("nslookup returned an error status"); 118 bool is_nxdomain = false;
120 result = STATE_WARNING; 119 bool parse_address = false; /* This flag scans for Address: but only after Name: */
121 } 120 for (size_t i = 0; i < chld_out.lines; i++) {
122 121 if (addresses == NULL) {
123 /* scan stdout */ 122 addresses = malloc(sizeof(*addresses) * 10);
124 for(size_t i = 0; i < chld_out.lines; i++) { 123 } else if (!(n_addresses % 10)) {
125 if (addresses == NULL) 124 addresses = realloc(addresses, sizeof(*addresses) * (n_addresses + 10));
126 addresses = malloc(sizeof(*addresses)*10); 125 }
127 else if (!(n_addresses % 10)) 126
128 addresses = realloc(addresses,sizeof(*addresses) * (n_addresses + 10)); 127 if (verbose) {
129 128 puts(chld_out.line[i]);
130 if (verbose) 129 }
131 puts(chld_out.line[i]); 130
132 131 if (strcasestr(chld_out.line[i], ".in-addr.arpa") ||
133 if (strcasestr (chld_out.line[i], ".in-addr.arpa") || strcasestr (chld_out.line[i], ".ip6.arpa")) { 132 strcasestr(chld_out.line[i], ".ip6.arpa")) {
134 if ((temp_buffer = strstr (chld_out.line[i], "name = "))) 133 if ((strstr(chld_out.line[i], "canonical name = ") != NULL)) {
135 addresses[n_addresses++] = strdup (temp_buffer + 7); 134 continue;
136 else { 135 }
137 msg = (char *)_("Warning plugin error"); 136 char *temp_buffer = NULL;
138 result = STATE_WARNING; 137 if ((temp_buffer = strstr(chld_out.line[i], "name = "))) {
139 } 138 addresses[n_addresses++] = strdup(temp_buffer + 7);
140 } 139 } else {
141 140 msg = (char *)_("Warning plugin error");
142 /* bug ID: 2946553 - Older versions of bind will use all available dns 141 result = STATE_WARNING;
143 servers, we have to match the one specified */ 142 }
144 if (strstr (chld_out.line[i], "Server:") && strlen(dns_server) > 0) { 143 }
145 temp_buffer = strchr (chld_out.line[i], ':'); 144
146 temp_buffer++; 145 /* bug ID: 2946553 - Older versions of bind will use all available dns
147 146 servers, we have to match the one specified */
148 /* Strip leading tabs */ 147 if (strstr(chld_out.line[i], "Server:") && strlen(config.dns_server) > 0) {
149 for (; *temp_buffer != '\0' && *temp_buffer == '\t'; temp_buffer++) 148 char *temp_buffer = strchr(chld_out.line[i], ':');
150 /* NOOP */; 149 if (temp_buffer == NULL) {
151 150 die(STATE_UNKNOWN, _("'%s' returned a weirdly formatted Server line\n"),
152 strip(temp_buffer); 151 NSLOOKUP_COMMAND);
153 if (temp_buffer==NULL || strlen(temp_buffer)==0) { 152 }
154 die (STATE_CRITICAL, 153
155 _("DNS CRITICAL - '%s' returned empty server string\n"), 154 temp_buffer++;
156 NSLOOKUP_COMMAND); 155
157 } 156 /* Strip leading tabs */
158 157 for (; *temp_buffer != '\0' && *temp_buffer == '\t'; temp_buffer++) {
159 if (strcmp(temp_buffer, dns_server) != 0) { 158 /* NOOP */;
160 die (STATE_CRITICAL, _("DNS CRITICAL - No response from DNS %s\n"), dns_server); 159 }
161 } 160
162 } 161 strip(temp_buffer);
163 162 if (strlen(temp_buffer) == 0) {
164 /* the server is responding, we just got the host name... */ 163 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty server string\n"),
165 if (strstr (chld_out.line[i], "Name:")) 164 NSLOOKUP_COMMAND);
166 parse_address = true; 165 }
167 else if (parse_address && (strstr (chld_out.line[i], "Address:") || 166
168 strstr (chld_out.line[i], "Addresses:"))) { 167 if (strcmp(temp_buffer, config.dns_server) != 0) {
169 temp_buffer = index (chld_out.line[i], ':'); 168 die(STATE_CRITICAL, _("DNS CRITICAL - No response from DNS %s\n"),
170 temp_buffer++; 169 config.dns_server);
171 170 }
172 /* Strip leading spaces */ 171 }
173 while (*temp_buffer == ' ') 172
174 temp_buffer++; 173 /* the server is responding, we just got the host name... */
175 174 if (strstr(chld_out.line[i], "Name:")) {
176 strip(temp_buffer); 175 parse_address = true;
177 if (temp_buffer==NULL || strlen(temp_buffer)==0) { 176 } else if (parse_address && (strstr(chld_out.line[i], "Address:") ||
178 die (STATE_CRITICAL, 177 strstr(chld_out.line[i], "Addresses:"))) {
179 _("DNS CRITICAL - '%s' returned empty host name string\n"), 178 char *temp_buffer = strchr(chld_out.line[i], ':');
180 NSLOOKUP_COMMAND); 179 if (temp_buffer == NULL) {
181 } 180 die(STATE_UNKNOWN, _("'%s' returned a weirdly formatted Address line\n"),
182 181 NSLOOKUP_COMMAND);
183 addresses[n_addresses++] = strdup(temp_buffer); 182 }
184 } 183
185 else if (strstr (chld_out.line[i], _("Non-authoritative answer:"))) { 184 temp_buffer++;
186 non_authoritative = true; 185
187 } 186 /* Strip leading spaces */
188 187 while (*temp_buffer == ' ') {
189 188 temp_buffer++;
190 result = error_scan (chld_out.line[i], &is_nxdomain); 189 }
191 if (result != STATE_OK) { 190
192 msg = strchr (chld_out.line[i], ':'); 191 strip(temp_buffer);
193 if(msg) msg++; 192 if (strlen(temp_buffer) == 0) {
194 break; 193 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty host name string\n"),
195 } 194 NSLOOKUP_COMMAND);
196 } 195 }
197 196
198 /* scan stderr */ 197 addresses[n_addresses++] = strdup(temp_buffer);
199 for(size_t i = 0; i < chld_err.lines; i++) { 198 } else if (strstr(chld_out.line[i], _("Non-authoritative answer:"))) {
200 if (verbose) 199 non_authoritative = true;
201 puts(chld_err.line[i]); 200 }
202 201
203 if (error_scan (chld_err.line[i], &is_nxdomain) != STATE_OK) { 202 result = error_scan(chld_out.line[i], &is_nxdomain, config.dns_server);
204 result = max_state (result, error_scan (chld_err.line[i], &is_nxdomain)); 203 if (result != STATE_OK) {
205 msg = strchr(input_buffer, ':'); 204 msg = strchr(chld_out.line[i], ':');
206 if(msg) 205 if (msg) {
207 msg++; 206 msg++;
208 else 207 }
209 msg = input_buffer; 208 break;
210 } 209 }
211 } 210 }
212 211
213 if (is_nxdomain && !expect_nxdomain) { 212 char input_buffer[MAX_INPUT_BUFFER];
214 die (STATE_CRITICAL, _("Domain '%s' was not found by the server\n"), query_address); 213 /* scan stderr */
215 } 214 for (size_t i = 0; i < chld_err.lines; i++) {
216 215 if (verbose) {
217 if (addresses) { 216 puts(chld_err.line[i]);
218 int i,slen; 217 }
219 char *adrp; 218
220 qsort(addresses, n_addresses, sizeof(*addresses), qstrcmp); 219 if (error_scan(chld_err.line[i], &is_nxdomain, config.dns_server) != STATE_OK) {
221 for(i=0, slen=1; i < n_addresses; i++) { 220 result =
222 slen += strlen(addresses[i])+1; 221 max_state(result, error_scan(chld_err.line[i], &is_nxdomain, config.dns_server));
223 } 222 msg = strchr(input_buffer, ':');
224 adrp = address = malloc(slen); 223 if (msg) {
225 for(i=0; i < n_addresses; i++) { 224 msg++;
226 if (i) *adrp++ = ','; 225 } else {
227 strcpy(adrp, addresses[i]); 226 msg = input_buffer;
228 adrp += strlen(addresses[i]); 227 }
229 } 228 }
230 *adrp = 0; 229 }
231 } else 230
232 die (STATE_CRITICAL, 231 if (is_nxdomain && !config.expect_nxdomain) {
233 _("DNS CRITICAL - '%s' msg parsing exited with no address\n"), 232 die(STATE_CRITICAL, _("Domain '%s' was not found by the server\n"), config.query_address);
234 NSLOOKUP_COMMAND); 233 }
235 234
236 /* compare to expected address */ 235 if (addresses) {
237 if (result == STATE_OK && expected_address_cnt > 0) { 236 size_t slen = 1;
238 result = STATE_CRITICAL; 237 char *adrp = NULL;
239 temp_buffer = ""; 238 qsort(addresses, n_addresses, sizeof(*addresses), qstrcmp);
240 unsigned long expect_match = (1 << expected_address_cnt) - 1; 239 for (size_t i = 0; i < n_addresses; i++) {
241 unsigned long addr_match = (1 << n_addresses) - 1; 240 slen += strlen(addresses[i]) + 1;
242 241 }
243 for (int i=0; i<expected_address_cnt; i++) { 242
244 int j; 243 // Temporary pointer adrp gets moved, address stays on the beginning
245 /* check if we get a match on 'raw' ip or cidr */ 244 adrp = address = malloc(slen);
246 for (j=0; j<n_addresses; j++) { 245 for (size_t i = 0; i < n_addresses; i++) {
247 if ( strcmp(addresses[j], expected_address[i]) == 0 246 if (i) {
248 || ip_match_cidr(addresses[j], expected_address[i]) ) { 247 *adrp++ = ',';
249 result = STATE_OK; 248 }
250 addr_match &= ~(1 << j); 249 strcpy(adrp, addresses[i]);
251 expect_match &= ~(1 << i); 250 adrp += strlen(addresses[i]);
252 } 251 }
253 } 252 *adrp = 0;
254 253 } else {
255 /* prepare an error string */ 254 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' msg parsing exited with no address\n"),
256 xasprintf(&temp_buffer, "%s%s; ", temp_buffer, expected_address[i]); 255 NSLOOKUP_COMMAND);
257 } 256 }
258 /* check if expected_address must cover all in addresses and none may be missing */ 257
259 if (all_match && (expect_match != 0 || addr_match != 0)) 258 /* compare to expected address */
260 result = STATE_CRITICAL; 259 if (result == STATE_OK && config.expected_address_cnt > 0) {
261 if (result == STATE_CRITICAL) { 260 result = STATE_CRITICAL;
262 /* Strip off last semicolon... */ 261 char *temp_buffer = "";
263 temp_buffer[strlen(temp_buffer)-2] = '\0'; 262 unsigned long expect_match = (1 << config.expected_address_cnt) - 1;
264 xasprintf(&msg, _("expected '%s' but got '%s'"), temp_buffer, address); 263 unsigned long addr_match = (1 << n_addresses) - 1;
265 } 264
266 } 265 for (size_t i = 0; i < config.expected_address_cnt; i++) {
267 266 /* check if we get a match on 'raw' ip or cidr */
268 if (expect_nxdomain) { 267 for (size_t j = 0; j < n_addresses; j++) {
269 if (!is_nxdomain) { 268 if (strcmp(addresses[j], config.expected_address[i]) == 0 ||
270 result = STATE_CRITICAL; 269 ip_match_cidr(addresses[j], config.expected_address[i])) {
271 xasprintf(&msg, _("Domain '%s' was found by the server: '%s'\n"), query_address, address); 270 result = STATE_OK;
272 } else { 271 addr_match &= ~(1 << j);
273 if (address != NULL) free(address); 272 expect_match &= ~(1 << i);
274 address = "NXDOMAIN"; 273 }
275 } 274 }
276 } 275
277 276 /* prepare an error string */
278 /* check if authoritative */ 277 xasprintf(&temp_buffer, "%s%s; ", temp_buffer, config.expected_address[i]);
279 if (result == STATE_OK && expect_authority && non_authoritative) { 278 }
280 result = STATE_CRITICAL; 279 /* check if expected_address must cover all in addresses and none may be missing */
281 xasprintf(&msg, _("server %s is not authoritative for %s"), dns_server, query_address); 280 if (config.all_match && (expect_match != 0 || addr_match != 0)) {
282 } 281 result = STATE_CRITICAL;
283 282 }
284 microsec = deltime (tv); 283 if (result == STATE_CRITICAL) {
285 elapsed_time = (double)microsec / 1.0e6; 284 /* Strip off last semicolon... */
286 285 temp_buffer[strlen(temp_buffer) - 2] = '\0';
287 if (result == STATE_OK) { 286 xasprintf(&msg, _("expected '%s' but got '%s'"), temp_buffer, address);
288 result = get_status(elapsed_time, time_thresholds); 287 }
289 if (result == STATE_OK) { 288 }
290 printf ("DNS %s: ", _("OK")); 289
291 } else if (result == STATE_WARNING) { 290 if (config.expect_nxdomain) {
292 printf ("DNS %s: ", _("WARNING")); 291 if (!is_nxdomain) {
293 } else if (result == STATE_CRITICAL) { 292 result = STATE_CRITICAL;
294 printf ("DNS %s: ", _("CRITICAL")); 293 xasprintf(&msg, _("Domain '%s' was found by the server: '%s'\n"), config.query_address,
295 } 294 address);
296 printf (ngettext("%.3f second response time", "%.3f seconds response time", elapsed_time), elapsed_time); 295 } else {
297 printf (_(". %s returns %s"), query_address, address); 296 if (address != NULL) {
298 if ((time_thresholds->warning != NULL) && (time_thresholds->critical != NULL)) { 297 free(address);
299 printf ("|%s\n", fperfdata ("time", elapsed_time, "s", 298 }
300 true, time_thresholds->warning->end, 299 address = "NXDOMAIN";
301 true, time_thresholds->critical->end, 300 }
302 true, 0, false, 0)); 301 }
303 } else if ((time_thresholds->warning == NULL) && (time_thresholds->critical != NULL)) { 302
304 printf ("|%s\n", fperfdata ("time", elapsed_time, "s", 303 /* check if authoritative */
305 false, 0, 304 if (result == STATE_OK && config.expect_authority && non_authoritative) {
306 true, time_thresholds->critical->end, 305 result = STATE_CRITICAL;
307 true, 0, false, 0)); 306 xasprintf(&msg, _("server %s is not authoritative for %s"), config.dns_server,
308 } else if ((time_thresholds->warning != NULL) && (time_thresholds->critical == NULL)) { 307 config.query_address);
309 printf ("|%s\n", fperfdata ("time", elapsed_time, "s", 308 }
310 true, time_thresholds->warning->end, 309
311 false, 0, 310 long microsec = deltime(tv);
312 true, 0, false, 0)); 311 double elapsed_time = (double)microsec / 1.0e6;
313 } else 312
314 printf ("|%s\n", fperfdata ("time", elapsed_time, "s", false, 0, false, 0, true, 0, false, 0)); 313 if (result == STATE_OK) {
315 } 314 result = get_status(elapsed_time, config.time_thresholds);
316 else if (result == STATE_WARNING) 315 if (result == STATE_OK) {
317 printf (_("DNS WARNING - %s\n"), 316 printf("DNS %s: ", _("OK"));
318 !strcmp (msg, "") ? _(" Probably a non-existent host/domain") : msg); 317 } else if (result == STATE_WARNING) {
319 else if (result == STATE_CRITICAL) 318 printf("DNS %s: ", _("WARNING"));
320 printf (_("DNS CRITICAL - %s\n"), 319 } else if (result == STATE_CRITICAL) {
321 !strcmp (msg, "") ? _(" Probably a non-existent host/domain") : msg); 320 printf("DNS %s: ", _("CRITICAL"));
322 else 321 }
323 printf (_("DNS UNKNOWN - %s\n"), 322 printf(ngettext("%.3f second response time", "%.3f seconds response time", elapsed_time),
324 !strcmp (msg, "") ? _(" Probably a non-existent host/domain") : msg); 323 elapsed_time);
325 324 printf(_(". %s returns %s"), config.query_address, address);
326 return result; 325 if ((config.time_thresholds->warning != NULL) &&
326 (config.time_thresholds->critical != NULL)) {
327 printf("|%s\n",
328 fperfdata("time", elapsed_time, "s", true, config.time_thresholds->warning->end,
329 true, config.time_thresholds->critical->end, true, 0, false, 0));
330 } else if ((config.time_thresholds->warning == NULL) &&
331 (config.time_thresholds->critical != NULL)) {
332 printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, true,
333 config.time_thresholds->critical->end, true, 0, false, 0));
334 } else if ((config.time_thresholds->warning != NULL) &&
335 (config.time_thresholds->critical == NULL)) {
336 printf("|%s\n",
337 fperfdata("time", elapsed_time, "s", true, config.time_thresholds->warning->end,
338 false, 0, true, 0, false, 0));
339 } else {
340 printf("|%s\n",
341 fperfdata("time", elapsed_time, "s", false, 0, false, 0, true, 0, false, 0));
342 }
343 } else if (result == STATE_WARNING) {
344 printf(_("DNS WARNING - %s\n"),
345 !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
346 } else if (result == STATE_CRITICAL) {
347 printf(_("DNS CRITICAL - %s\n"),
348 !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
349 } else {
350 printf(_("DNS UNKNOWN - %s\n"),
351 !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
352 }
353
354 exit(result);
327} 355}
328 356
329bool ip_match_cidr(const char *addr, const char *cidr_ro) { 357bool ip_match_cidr(const char *addr, const char *cidr_ro) {
330 char *subnet, *mask_c, *cidr = strdup(cidr_ro); 358 char *subnet;
331 int mask; 359 char *mask_c;
332 subnet = strtok(cidr, "/"); 360 char *cidr = strdup(cidr_ro);
333 mask_c = strtok(NULL, "\0"); 361 int mask;
334 if (!subnet || !mask_c) { 362 subnet = strtok(cidr, "/");
335 return false; 363 mask_c = strtok(NULL, "\0");
364 if (!subnet || !mask_c) {
365 return false;
336 } 366 }
337 mask = atoi(mask_c); 367 mask = atoi(mask_c);
338 368
339 /* https://www.cryptobells.com/verifying-ips-in-a-subnet-in-php/ */ 369 /* 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); 370 return (ip2long(addr) & ~((1 << (32 - mask)) - 1)) == (ip2long(subnet) >> (32 - mask))
371 << (32 - mask);
341} 372}
342 373
343unsigned long 374unsigned long ip2long(const char *src) {
344ip2long(const char* src) { 375 unsigned long ip[4];
345 unsigned long ip[4]; 376 /* http://computer-programming-forum.com/47-c-language/1376ffb92a12c471.htm */
346 /* http://computer-programming-forum.com/47-c-language/1376ffb92a12c471.htm */ 377 return (sscanf(src, "%3lu.%3lu.%3lu.%3lu", &ip[0], &ip[1], &ip[2], &ip[3]) == 4 &&
347 return (sscanf(src, "%3lu.%3lu.%3lu.%3lu", 378 ip[0] < 256 && ip[1] < 256 && ip[2] < 256 && ip[3] < 256)
348 &ip[0], &ip[1], &ip[2], &ip[3]) == 4 && 379 ? ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3]
349 ip[0] < 256 && ip[1] < 256 && 380 : 0;
350 ip[2] < 256 && ip[3] < 256)
351 ? ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3]
352 : 0;
353} 381}
354 382
355int 383mp_state_enum error_scan(char *input_buffer, bool *is_nxdomain,
356error_scan (char *input_buffer, bool *is_nxdomain) 384 const char dns_server[ADDRESS_LENGTH]) {
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 385
412} 386 const int nxdomain = strstr(input_buffer, "Non-existent") ||
387 strstr(input_buffer, "** server can't find") ||
388 strstr(input_buffer, "** Can't find") || strstr(input_buffer, "NXDOMAIN");
389 if (nxdomain) {
390 *is_nxdomain = true;
391 }
413 392
393 /* the DNS lookup timed out */
394 if (strstr(input_buffer,
395 _("Note: nslookup is deprecated and may be removed from future releases.")) ||
396 strstr(input_buffer,
397 _("Consider using the `dig' or `host' programs instead. Run nslookup with")) ||
398 strstr(input_buffer, _("the `-sil[ent]' option to prevent this message from appearing."))) {
399 return STATE_OK;
400 }
414 401
415/* process command-line arguments */ 402 /* DNS server is not running... */
416int 403 else if (strstr(input_buffer, "No response from server")) {
417process_arguments (int argc, char **argv) 404 die(STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
418{ 405 } else if (strstr(input_buffer, "no servers could be reached")) {
419 int c; 406 die(STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
420 char *warning = NULL; 407 }
421 char *critical = NULL; 408
422 409 /* Host name is valid, but server doesn't have records... */
423 int opt_index = 0; 410 else if (strstr(input_buffer, "No records")) {
424 static struct option long_opts[] = { 411 die(STATE_CRITICAL, _("DNS %s has no records\n"), dns_server);
425 {"help", no_argument, 0, 'h'}, 412 }
426 {"version", no_argument, 0, 'V'}, 413
427 {"verbose", no_argument, 0, 'v'}, 414 /* Connection was refused */
428 {"timeout", required_argument, 0, 't'}, 415 else if (strstr(input_buffer, "Connection refused") ||
429 {"hostname", required_argument, 0, 'H'}, 416 strstr(input_buffer, "Couldn't find server") || strstr(input_buffer, "Refused") ||
430 {"server", required_argument, 0, 's'}, 417 (strstr(input_buffer, "** server can't find") && strstr(input_buffer, ": REFUSED"))) {
431 {"reverse-server", required_argument, 0, 'r'}, 418 die(STATE_CRITICAL, _("Connection to DNS %s was refused\n"), dns_server);
432 {"expected-address", required_argument, 0, 'a'}, 419 }
433 {"expect-nxdomain", no_argument, 0, 'n'}, 420
434 {"expect-authority", no_argument, 0, 'A'}, 421 /* Query refused (usually by an ACL in the namserver) */
435 {"all", no_argument, 0, 'L'}, 422 else if (strstr(input_buffer, "Query refused")) {
436 {"warning", required_argument, 0, 'w'}, 423 die(STATE_CRITICAL, _("Query was refused by DNS server at %s\n"), dns_server);
437 {"critical", required_argument, 0, 'c'}, 424 }
438 {0, 0, 0, 0} 425
439 }; 426 /* No information (e.g. nameserver IP has two PTR records) */
440 427 else if (strstr(input_buffer, "No information")) {
441 if (argc < 2) 428 die(STATE_CRITICAL, _("No information returned by DNS server at %s\n"), dns_server);
442 return ERROR; 429 }
443 430
444 for (c = 1; c < argc; c++) 431 /* Network is unreachable */
445 if (strcmp ("-to", argv[c]) == 0) 432 else if (strstr(input_buffer, "Network is unreachable")) {
446 strcpy (argv[c], "-t"); 433 die(STATE_CRITICAL, _("Network is unreachable\n"));
447 434 }
448 while (1) { 435
449 c = getopt_long (argc, argv, "hVvALnt:H:s:r:a:w:c:", long_opts, &opt_index); 436 /* Internal server failure */
450 437 else if (strstr(input_buffer, "Server failure")) {
451 if (c == -1 || c == EOF) 438 die(STATE_CRITICAL, _("DNS failure for %s\n"), dns_server);
452 break; 439 }
453 440
454 switch (c) { 441 /* Request error or the DNS lookup timed out */
455 case 'h': /* help */ 442 else if (strstr(input_buffer, "Format error") || strstr(input_buffer, "Timed out")) {
456 print_help (); 443 return STATE_WARNING;
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 } 444 }
499 expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**)); 445
500 expected_address[expected_address_cnt] = strdup(optarg); 446 return STATE_OK;
501 expected_address_cnt++;
502 } else {
503 expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**));
504 expected_address[expected_address_cnt] = strdup(optarg);
505 expected_address_cnt++;
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} 447}
547 448
449/* process command-line arguments */
450check_dns_config_wrapper process_arguments(int argc, char **argv) {
451 static struct option long_opts[] = {{"help", no_argument, 0, 'h'},
452 {"version", no_argument, 0, 'V'},
453 {"verbose", no_argument, 0, 'v'},
454 {"timeout", required_argument, 0, 't'},
455 {"hostname", required_argument, 0, 'H'},
456 {"server", required_argument, 0, 's'},
457 {"reverse-server", required_argument, 0, 'r'},
458 {"expected-address", required_argument, 0, 'a'},
459 {"expect-nxdomain", no_argument, 0, 'n'},
460 {"expect-authority", no_argument, 0, 'A'},
461 {"all", no_argument, 0, 'L'},
462 {"warning", required_argument, 0, 'w'},
463 {"critical", required_argument, 0, 'c'},
464 {0, 0, 0, 0}};
465
466 check_dns_config_wrapper result = {
467 .config = check_dns_config_init(),
468 .errorcode = OK,
469 };
470
471 if (argc < 2) {
472 result.errorcode = ERROR;
473 return result;
474 }
475
476 for (int index = 1; index < argc; index++) {
477 if (strcmp("-to", argv[index]) == 0) {
478 strcpy(argv[index], "-t");
479 }
480 }
548 481
549int 482 char *warning = NULL;
550validate_arguments () 483 char *critical = NULL;
551{ 484 int opt_index = 0;
552 if (query_address[0] == 0) { 485 int index = 0;
553 printf ("missing --host argument\n"); 486 while (true) {
554 return ERROR; 487 index = getopt_long(argc, argv, "hVvALnt:H:s:r:a:w:c:", long_opts, &opt_index);
555 } 488
489 if (index == -1 || index == EOF) {
490 break;
491 }
492
493 switch (index) {
494 case 'h': /* help */
495 print_help();
496 exit(STATE_UNKNOWN);
497 case 'V': /* version */
498 print_revision(progname, NP_VERSION);
499 exit(STATE_UNKNOWN);
500 case 'v': /* version */
501 verbose = true;
502 break;
503 case 't': /* timeout period */
504 timeout_interval = atoi(optarg);
505 break;
506 case 'H': /* hostname */
507 if (strlen(optarg) >= ADDRESS_LENGTH) {
508 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
509 }
510 strcpy(result.config.query_address, optarg);
511 break;
512 case 's': /* server name */
513 /* TODO: this host_or_die check is probably unnecessary.
514 * Better to confirm nslookup response matches */
515 host_or_die(optarg);
516 if (strlen(optarg) >= ADDRESS_LENGTH) {
517 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
518 }
519 strcpy(result.config.dns_server, optarg);
520 break;
521 case 'r': /* reverse server name */
522 /* TODO: Is this host_or_die necessary? */
523 // TODO This does not do anything!!! 2025-03-08 rincewind
524 host_or_die(optarg);
525 if (strlen(optarg) >= ADDRESS_LENGTH) {
526 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
527 }
528 static char ptr_server[ADDRESS_LENGTH] = "";
529 strcpy(ptr_server, optarg);
530 break;
531 case 'a': /* expected address */
532 if (strlen(optarg) >= ADDRESS_LENGTH) {
533 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
534 }
535 if (strchr(optarg, ',') != NULL) {
536 char *comma = strchr(optarg, ',');
537 while (comma != NULL) {
538 result.config.expected_address = (char **)realloc(
539 result.config.expected_address,
540 (result.config.expected_address_cnt + 1) * sizeof(char **));
541 result.config.expected_address[result.config.expected_address_cnt] =
542 strndup(optarg, comma - optarg);
543 result.config.expected_address_cnt++;
544 optarg = comma + 1;
545 comma = strchr(optarg, ',');
546 }
547 result.config.expected_address =
548 (char **)realloc(result.config.expected_address,
549 (result.config.expected_address_cnt + 1) * sizeof(char **));
550 result.config.expected_address[result.config.expected_address_cnt] = strdup(optarg);
551 result.config.expected_address_cnt++;
552 } else {
553 result.config.expected_address =
554 (char **)realloc(result.config.expected_address,
555 (result.config.expected_address_cnt + 1) * sizeof(char **));
556 result.config.expected_address[result.config.expected_address_cnt] = strdup(optarg);
557 result.config.expected_address_cnt++;
558 }
559 break;
560 case 'n': /* expect NXDOMAIN */
561 result.config.expect_nxdomain = true;
562 break;
563 case 'A': /* expect authority */
564 result.config.expect_authority = true;
565 break;
566 case 'L': /* all must match */
567 result.config.all_match = true;
568 break;
569 case 'w':
570 warning = optarg;
571 break;
572 case 'c':
573 critical = optarg;
574 break;
575 default: /* args not parsable */
576 usage5();
577 }
578 }
556 579
557 if (expected_address_cnt > 0 && expect_nxdomain) { 580 index = optind;
558 printf ("--expected-address and --expect-nxdomain cannot be combined\n"); 581 if (strlen(result.config.query_address) == 0 && index < argc) {
559 return ERROR; 582 if (strlen(argv[index]) >= ADDRESS_LENGTH) {
560 } 583 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
584 }
585 strcpy(result.config.query_address, argv[index++]);
586 }
561 587
562 return OK; 588 if (strlen(result.config.dns_server) == 0 && index < argc) {
589 /* TODO: See -s option */
590 host_or_die(argv[index]);
591 if (strlen(argv[index]) >= ADDRESS_LENGTH) {
592 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
593 }
594 strcpy(result.config.dns_server, argv[index++]);
595 }
596
597 set_thresholds(&result.config.time_thresholds, warning, critical);
598
599 return validate_arguments(result);
563} 600}
564 601
602check_dns_config_wrapper validate_arguments(check_dns_config_wrapper config_wrapper) {
603 if (config_wrapper.config.query_address[0] == 0) {
604 printf("missing --host argument\n");
605 config_wrapper.errorcode = ERROR;
606 return config_wrapper;
607 }
565 608
566void 609 if (config_wrapper.config.expected_address_cnt > 0 && config_wrapper.config.expect_nxdomain) {
567print_help (void) 610 printf("--expected-address and --expect-nxdomain cannot be combined\n");
568{ 611 config_wrapper.errorcode = ERROR;
569 print_revision (progname, NP_VERSION); 612 return config_wrapper;
570 613 }
571 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 614
572 printf (COPYRIGHT, copyright, email); 615 return config_wrapper;
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} 616}
610 617
618void print_help(void) {
619 print_revision(progname, NP_VERSION);
620
621 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
622 printf(COPYRIGHT, copyright, email);
623
624 printf("%s\n", _("This plugin uses the nslookup program to obtain the IP address for the given "
625 "host/domain query."));
626 printf("%s\n", _("An optional DNS server to use may be specified."));
627 printf("%s\n", _("If no DNS server is specified, the default server(s) specified in "
628 "/etc/resolv.conf will be used."));
629
630 printf("\n\n");
631
632 print_usage();
633
634 printf(UT_HELP_VRSN);
635 printf(UT_EXTRA_OPTS);
636
637 printf(" -H, --hostname=HOST\n");
638 printf(" %s\n", _("The name or address you want to query"));
639 printf(" -s, --server=HOST\n");
640 printf(" %s\n", _("Optional DNS server you want to use for the lookup"));
641 printf(" -a, --expected-address=IP-ADDRESS|CIDR|HOST\n");
642 printf(" %s\n",
643 _("Optional IP-ADDRESS/CIDR you expect the DNS server to return. HOST must end"));
644 printf(" %s\n",
645 _("with a dot (.). This option can be repeated multiple times (Returns OK if any"));
646 printf(" %s\n", _("value matches)."));
647 printf(" -n, --expect-nxdomain\n");
648 printf(" %s\n",
649 _("Expect the DNS server to return NXDOMAIN (i.e. the domain was not found)"));
650 printf(" %s\n", _("Cannot be used together with -a"));
651 printf(" -A, --expect-authority\n");
652 printf(" %s\n", _("Optionally expect the DNS server to be authoritative for the lookup"));
653 printf(" -w, --warning=seconds\n");
654 printf(" %s\n", _("Return warning if elapsed time exceeds value. Default off"));
655 printf(" -c, --critical=seconds\n");
656 printf(" %s\n", _("Return critical if elapsed time exceeds value. Default off"));
657 printf(" -L, --all\n");
658 printf(" %s\n",
659 _("Return critical if the list of expected addresses does not match all addresses"));
660 printf(" %s\n", _("returned. Default off"));
661
662 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
663
664 printf(UT_SUPPORT);
665}
611 666
612void 667void print_usage(void) {
613print_usage (void) 668 printf("%s\n", _("Usage:"));
614{ 669 printf("%s -H host [-s server] [-a expected-address] [-n] [-A] [-t timeout] [-w warn] [-c "
615 printf ("%s\n", _("Usage:")); 670 "crit] [-L]\n",
616 printf ("%s -H host [-s server] [-a expected-address] [-n] [-A] [-t timeout] [-w warn] [-c crit] [-L]\n", progname); 671 progname);
617} 672}
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..602d5868 100644
--- a/plugins/check_dummy.c
+++ b/plugins/check_dummy.c
@@ -1,124 +1,114 @@
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
62 usage4 (_("Arguments to check_dummy must be an integer")); 62 switch (result) {
63 else 63 case STATE_OK:
64 result = atoi (argv[1]); 64 printf(_("OK"));
65 65 break;
66 switch (result) { 66 case STATE_WARNING:
67 case STATE_OK: 67 printf(_("WARNING"));
68 printf (_("OK")); 68 break;
69 break; 69 case STATE_CRITICAL:
70 case STATE_WARNING: 70 printf(_("CRITICAL"));
71 printf (_("WARNING")); 71 break;
72 break; 72 case STATE_UNKNOWN:
73 case STATE_CRITICAL: 73 printf(_("UNKNOWN"));
74 printf (_("CRITICAL")); 74 break;
75 break; 75 default:
76 case STATE_UNKNOWN: 76 printf(_("UNKNOWN"));
77 printf (_("UNKNOWN")); 77 printf(": ");
78 break; 78 printf(_("Status %d is not a supported error state\n"), result);
79 default: 79 return STATE_UNKNOWN;
80 printf (_("UNKNOWN")); 80 }
81 printf (": "); 81
82 printf (_("Status %d is not a supported error state\n"), result); 82 if (argc >= 3) {
83 return STATE_UNKNOWN; 83 printf(": %s", argv[2]);
84 } 84 }
85 85
86 if (argc >= 3) 86 printf("\n");
87 printf (": %s", argv[2]); 87
88 88 return result;
89 printf("\n");
90
91 return result;
92} 89}
93 90
91void print_help(void) {
92 print_revision(progname, NP_VERSION);
94 93
94 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
95 printf(COPYRIGHT, copyright, email);
95 96
96void 97 printf("%s\n",
97print_help (void) 98 _("This plugin will simply return the state corresponding to the numeric value"));
98{
99 print_revision (progname, NP_VERSION);
100 99
101 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 100 printf("%s\n", _("of the <state> argument with optional text"));
102 printf (COPYRIGHT, copyright, email);
103 101
104 printf ("%s\n", _("This plugin will simply return the state corresponding to the numeric value")); 102 printf("\n\n");
105 103
106 printf ("%s\n", _("of the <state> argument with optional text")); 104 print_usage();
107 105
108 printf ("\n\n"); 106 printf(UT_HELP_VRSN);
109 107
110 print_usage (); 108 printf(UT_SUPPORT);
111
112 printf (UT_HELP_VRSN);
113
114 printf (UT_SUPPORT);
115} 109}
116 110
117 111void print_usage(void) {
118 112 printf("%s\n", _("Usage:"));
119void 113 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} 114}
diff --git a/plugins/check_fping.c b/plugins/check_fping.c
index 70d6f9fc..6160c2cb 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,560 @@ 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*/,
50int process_arguments (int, char **); 50 double /*crta*/, bool /*wrta_p*/, double /*wrta*/, bool /*cpl_p*/,
51int get_threshold (char *arg, char *rv[2]); 51 int /*cpl*/, bool /*wpl_p*/, int /*wpl*/, bool /*alive_p*/);
52void print_help (void); 52
53void print_usage (void); 53typedef struct {
54 54 int errorcode;
55char *server_name = NULL; 55 check_fping_config config;
56char *sourceip = NULL; 56} check_fping_config_wrapper;
57char *sourceif = NULL; 57static check_fping_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
58int packet_size = PACKET_SIZE; 58static int get_threshold(char *arg, char *rv[2]);
59int packet_count = PACKET_COUNT; 59static void print_help(void);
60int target_timeout = 0; 60void print_usage(void);
61int packet_interval = 0; 61
62bool verbose = false; 62static bool verbose = false;
63int cpl; 63
64int wpl; 64int main(int argc, char **argv) {
65double crta; 65 setlocale(LC_ALL, "");
66double wrta; 66 bindtextdomain(PACKAGE, LOCALEDIR);
67bool cpl_p = false; 67 textdomain(PACKAGE);
68bool wpl_p = false; 68
69bool alive_p = false; 69 /* Parse extra opts if any */
70bool crta_p = false; 70 argv = np_extra_opts(&argc, argv, progname);
71bool wrta_p = false; 71
72 72 check_fping_config_wrapper tmp_config = process_arguments(argc, argv);
73int 73 if (tmp_config.errorcode == ERROR) {
74main (int argc, char **argv) 74 usage4(_("Could not parse arguments"));
75{ 75 }
76/* normally should be int result = STATE_UNKNOWN; */ 76
77 77 const check_fping_config config = tmp_config.config;
78 int status = STATE_UNKNOWN; 78
79 int result = 0; 79 char *server = NULL;
80 char *fping_prog = NULL; 80 server = strscpy(server, config.server_name);
81 char *server = NULL; 81
82 char *command_line = NULL; 82 char *option_string = "";
83 char *input_buffer = NULL; 83 char *fping_prog = NULL;
84 char *option_string = ""; 84
85 input_buffer = malloc (MAX_INPUT_BUFFER); 85 /* First determine if the target is dualstack or ipv6 only. */
86 86 bool server_is_inet6_addr = is_inet6_addr(server);
87 setlocale (LC_ALL, ""); 87
88 bindtextdomain (PACKAGE, LOCALEDIR); 88 /*
89 textdomain (PACKAGE); 89 * If the user requested -6 OR the user made no assertion and the address is v6 or dualstack
90 90 * -> we use ipv6
91 /* Parse extra opts if any */ 91 * If the user requested -4 OR the user made no assertion and the address is v4 ONLY
92 argv=np_extra_opts (&argc, argv, progname); 92 * -> we use ipv4
93 93 */
94 if (process_arguments (argc, argv) == ERROR) 94 if (address_family == AF_INET6 || (address_family == AF_UNSPEC && server_is_inet6_addr)) {
95 usage4 (_("Could not parse arguments")); 95 xasprintf(&option_string, "%s-6 ", option_string);
96 96 } else {
97 server = strscpy (server, server_name); 97 xasprintf(&option_string, "%s-4 ", option_string);
98 98 }
99 /* compose the command */ 99 fping_prog = strdup(PATH_TO_FPING);
100 if (target_timeout) 100
101 xasprintf(&option_string, "%s-t %d ", option_string, target_timeout); 101 /* compose the command */
102 if (packet_interval) 102 if (config.target_timeout) {
103 xasprintf(&option_string, "%s-p %d ", option_string, packet_interval); 103 xasprintf(&option_string, "%s-t %d ", option_string, config.target_timeout);
104 if (sourceip) 104 }
105 xasprintf(&option_string, "%s-S %s ", option_string, sourceip); 105 if (config.packet_interval) {
106 if (sourceif) 106 xasprintf(&option_string, "%s-p %d ", option_string, config.packet_interval);
107 xasprintf(&option_string, "%s-I %s ", option_string, sourceif); 107 }
108 108 if (config.sourceip) {
109#ifdef PATH_TO_FPING6 109 xasprintf(&option_string, "%s-S %s ", option_string, config.sourceip);
110 if (address_family != AF_INET && is_inet6_addr(server)) 110 }
111 fping_prog = strdup(PATH_TO_FPING6); 111 if (config.sourceif) {
112 else 112 xasprintf(&option_string, "%s-I %s ", option_string, config.sourceif);
113 fping_prog = strdup(PATH_TO_FPING); 113 }
114#else 114 if (config.dontfrag) {
115 fping_prog = strdup(PATH_TO_FPING); 115 xasprintf(&option_string, "%s-M ", option_string);
116#endif 116 }
117 117 if (config.randomize_packet_data) {
118 xasprintf (&command_line, "%s %s-b %d -c %d %s", fping_prog, 118 xasprintf(&option_string, "%s-R ", option_string);
119 option_string, packet_size, packet_count, server); 119 }
120 120
121 if (verbose) 121 if (config.fwmark_set) {
122 printf ("%s\n", command_line); 122 xasprintf(&option_string, "%s--fwmark %u ", option_string, config.fwmark);
123 123 }
124 /* run the command */ 124
125 child_process = spopen (command_line); 125 if (config.icmp_timestamp) {
126 if (child_process == NULL) { 126 xasprintf(&option_string, "%s--icmp-timestamp ", option_string);
127 printf (_("Could not open pipe: %s\n"), command_line); 127 }
128 return STATE_UNKNOWN; 128
129 } 129 if (config.check_source) {
130 130 xasprintf(&option_string, "%s--check-source ", option_string);
131 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); 131 }
132 if (child_stderr == NULL) { 132
133 printf (_("Could not open stderr for %s\n"), command_line); 133 char *command_line = NULL;
134 } 134
135 135 if (config.icmp_timestamp) {
136 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) { 136 // no packet size settable for ICMP timestamp
137 if (verbose) 137 xasprintf(&command_line, "%s %s -c %d %s", fping_prog, option_string, config.packet_count,
138 printf ("%s", input_buffer); 138 server);
139 status = max_state (status, textscan (input_buffer)); 139 } else {
140 } 140 xasprintf(&command_line, "%s %s-b %d -c %d %s", fping_prog, option_string,
141 141 config.packet_size, config.packet_count, server);
142 /* If we get anything on STDERR, at least set warning */ 142 }
143 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) { 143
144 status = max_state (status, STATE_WARNING); 144 if (verbose) {
145 if (verbose) 145 printf("%s\n", command_line);
146 printf ("%s", input_buffer); 146 }
147 status = max_state (status, textscan (input_buffer)); 147
148 } 148 /* run the command */
149 (void) fclose (child_stderr); 149 child_process = spopen(command_line);
150 150 if (child_process == NULL) {
151 /* close the pipe */ 151 printf(_("Could not open pipe: %s\n"), command_line);
152 result = spclose (child_process); 152 return STATE_UNKNOWN;
153 if (result) { 153 }
154 /* need to use max_state not max */ 154
155 status = max_state (status, STATE_WARNING); 155 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
156 } 156 if (child_stderr == NULL) {
157 157 printf(_("Could not open stderr for %s\n"), command_line);
158 if (result > 1 ) { 158 }
159 status = max_state (status, STATE_UNKNOWN); 159
160 if (result == 2) { 160 char *input_buffer = malloc(MAX_INPUT_BUFFER);
161 die (STATE_UNKNOWN, _("FPING UNKNOWN - IP address not found\n")); 161 mp_state_enum status = STATE_UNKNOWN;
162 } 162 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
163 if (result == 3) { 163 if (verbose) {
164 die (STATE_UNKNOWN, _("FPING UNKNOWN - invalid commandline argument\n")); 164 printf("%s", input_buffer);
165 } 165 }
166 if (result == 4) { 166 status = max_state(status, textscan(input_buffer, config.server_name, config.crta_p,
167 die (STATE_UNKNOWN, _("FPING UNKNOWN - failed system call\n")); 167 config.crta, config.wrta_p, config.wrta, config.cpl_p,
168 } 168 config.cpl, config.wpl_p, config.wpl, config.alive_p));
169 169 }
170 } 170
171 171 /* If we get anything on STDERR, at least set warning */
172 printf ("FPING %s - %s\n", state_text (status), server_name); 172 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
173 173 status = max_state(status, STATE_WARNING);
174 return status; 174 if (verbose) {
175 printf("%s", input_buffer);
176 }
177 status = max_state(status, textscan(input_buffer, config.server_name, config.crta_p,
178 config.crta, config.wrta_p, config.wrta, config.cpl_p,
179 config.cpl, config.wpl_p, config.wpl, config.alive_p));
180 }
181 (void)fclose(child_stderr);
182
183 /* close the pipe */
184 int result = spclose(child_process);
185 if (result) {
186 /* need to use max_state not max */
187 status = max_state(status, STATE_WARNING);
188 }
189
190 if (result > 1) {
191 status = max_state(status, STATE_UNKNOWN);
192 if (result == 2) {
193 die(STATE_UNKNOWN, _("FPING UNKNOWN - IP address not found\n"));
194 }
195 if (result == 3) {
196 die(STATE_UNKNOWN, _("FPING UNKNOWN - invalid commandline argument\n"));
197 }
198 if (result == 4) {
199 die(STATE_UNKNOWN, _("FPING UNKNOWN - failed system call\n"));
200 }
201 }
202
203 printf("FPING %s - %s\n", state_text(status), config.server_name);
204
205 return status;
175} 206}
176 207
177 208mp_state_enum textscan(char *buf, const char *server_name, bool crta_p, double crta, bool wrta_p,
178int textscan (char *buf) { 209 double wrta, bool cpl_p, int cpl, bool wpl_p, int wpl, bool alive_p) {
179 char *rtastr = NULL; 210 /* stops testing after the first successful reply. */
180 char *losstr = NULL; 211 double rta;
181 char *xmtstr = NULL; 212 double loss;
182 double loss; 213 char *rtastr = NULL;
183 double rta; 214 if (alive_p && strstr(buf, "avg, 0% loss)")) {
184 double xmt; 215 rtastr = strstr(buf, "ms (");
185 int status = STATE_UNKNOWN; 216 rtastr = 1 + index(rtastr, '(');
186 217 rta = strtod(rtastr, NULL);
187 /* stops testing after the first successful reply. */ 218 loss = strtod("0", NULL);
188 if (alive_p && strstr(buf, "avg, 0% loss)")) { 219 die(STATE_OK, _("FPING %s - %s (rta=%f ms)|%s\n"), state_text(STATE_OK), server_name, rta,
189 rtastr = strstr (buf, "ms ("); 220 /* No loss since we only waited for the first reply
190 rtastr = 1 + index(rtastr, '('); 221 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100), */
191 rta = strtod(rtastr, NULL); 222 fperfdata("rta", rta / 1.0e3, "s", wrta_p, wrta / 1.0e3, crta_p, crta / 1.0e3, true, 0,
192 loss=strtod("0",NULL); 223 false, 0));
193 die (STATE_OK, 224 }
194 _("FPING %s - %s (rta=%f ms)|%s\n"), 225
195 state_text (STATE_OK), server_name,rta, 226 mp_state_enum status = STATE_UNKNOWN;
196 /* No loss since we only waited for the first reply 227 char *xmtstr = NULL;
197 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100), */ 228 double xmt;
198 fperfdata ("rta", rta/1.0e3, "s", wrta_p, wrta/1.0e3, crta_p, crta/1.0e3, true, 0, false, 0)); 229 char *losstr = NULL;
199 } 230 if (strstr(buf, "not found")) {
200 231 die(STATE_CRITICAL, _("FPING UNKNOWN - %s not found\n"), server_name);
201 if (strstr (buf, "not found")) { 232
202 die (STATE_CRITICAL, _("FPING UNKNOWN - %s not found\n"), server_name); 233 } else if (strstr(buf, "is unreachable") || strstr(buf, "Unreachable")) {
203 234 die(STATE_CRITICAL, _("FPING CRITICAL - %s is unreachable\n"), "host");
204 } 235
205 else if (strstr (buf, "is unreachable") || strstr (buf, "Unreachable")) { 236 } else if (strstr(buf, "Operation not permitted") || strstr(buf, "No such device")) {
206 die (STATE_CRITICAL, _("FPING CRITICAL - %s is unreachable\n"), 237 die(STATE_UNKNOWN, _("FPING UNKNOWN - %s parameter error\n"), "host");
207 "host"); 238 } else if (strstr(buf, "is down")) {
208 239 die(STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name);
209 } 240
210 else if (strstr (buf, "Operation not permitted") || strstr (buf, "No such device") ) { 241 } else if (strstr(buf, "is alive")) {
211 die (STATE_UNKNOWN, _("FPING UNKNOWN - %s parameter error\n"), 242 status = STATE_OK;
212 "host"); 243
213 } 244 } else if (strstr(buf, "xmt/rcv/%loss") && strstr(buf, "min/avg/max")) {
214 else if (strstr (buf, "is down")) { 245 losstr = strstr(buf, "=");
215 die (STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name); 246 losstr = 1 + strstr(losstr, "/");
216 247 losstr = 1 + strstr(losstr, "/");
217 } 248 rtastr = strstr(buf, "min/avg/max");
218 else if (strstr (buf, "is alive")) { 249 rtastr = strstr(rtastr, "=");
219 status = STATE_OK; 250 rtastr = 1 + index(rtastr, '/');
220 251 loss = strtod(losstr, NULL);
221 } 252 rta = strtod(rtastr, NULL);
222 else if (strstr (buf, "xmt/rcv/%loss") && strstr (buf, "min/avg/max")) { 253 if (cpl_p && loss > cpl) {
223 losstr = strstr (buf, "="); 254 status = STATE_CRITICAL;
224 losstr = 1 + strstr (losstr, "/"); 255 } else if (crta_p && rta > crta) {
225 losstr = 1 + strstr (losstr, "/"); 256 status = STATE_CRITICAL;
226 rtastr = strstr (buf, "min/avg/max"); 257 } else if (wpl_p && loss > wpl) {
227 rtastr = strstr (rtastr, "="); 258 status = STATE_WARNING;
228 rtastr = 1 + index (rtastr, '/'); 259 } else if (wrta_p && rta > wrta) {
229 loss = strtod (losstr, NULL); 260 status = STATE_WARNING;
230 rta = strtod (rtastr, NULL); 261 } else {
231 if (cpl_p && loss > cpl) 262 status = STATE_OK;
232 status = STATE_CRITICAL; 263 }
233 else if (crta_p && rta > crta) 264 die(status, _("FPING %s - %s (loss=%.0f%%, rta=%f ms)|%s %s\n"), state_text(status),
234 status = STATE_CRITICAL; 265 server_name, loss, rta,
235 else if (wpl_p && loss > wpl) 266 perfdata("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, false, 0, false, 0),
236 status = STATE_WARNING; 267 fperfdata("rta", rta / 1.0e3, "s", wrta_p, wrta / 1.0e3, crta_p, crta / 1.0e3, true, 0,
237 else if (wrta_p && rta > wrta) 268 false, 0));
238 status = STATE_WARNING; 269
239 else 270 } else if (strstr(buf, "xmt/rcv/%loss")) {
240 status = STATE_OK; 271 /* no min/max/avg if host was unreachable in fping v2.2.b1 */
241 die (status, 272 /* in v2.4b2: 10.99.0.1 : xmt/rcv/%loss = 0/0/0% */
242 _("FPING %s - %s (loss=%.0f%%, rta=%f ms)|%s %s\n"), 273 losstr = strstr(buf, "=");
243 state_text (status), server_name, loss, rta, 274 xmtstr = 1 + losstr;
244 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100), 275 xmt = strtod(xmtstr, NULL);
245 fperfdata ("rta", rta/1.0e3, "s", wrta_p, wrta/1.0e3, crta_p, crta/1.0e3, true, 0, false, 0)); 276 if (xmt == 0) {
246 277 die(STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name);
247 } 278 }
248 else if(strstr (buf, "xmt/rcv/%loss") ) { 279 losstr = 1 + strstr(losstr, "/");
249 /* no min/max/avg if host was unreachable in fping v2.2.b1 */ 280 losstr = 1 + strstr(losstr, "/");
250 /* in v2.4b2: 10.99.0.1 : xmt/rcv/%loss = 0/0/0% */ 281 loss = strtod(losstr, NULL);
251 losstr = strstr (buf, "="); 282 if (atoi(losstr) == 100) {
252 xmtstr = 1 + losstr; 283 status = STATE_CRITICAL;
253 xmt = strtod (xmtstr, NULL); 284 } else if (cpl_p && loss > cpl) {
254 if(xmt == 0) 285 status = STATE_CRITICAL;
255 die (STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name); 286 } else if (wpl_p && loss > wpl) {
256 losstr = 1 + strstr (losstr, "/"); 287 status = STATE_WARNING;
257 losstr = 1 + strstr (losstr, "/"); 288 } else {
258 loss = strtod (losstr, NULL); 289 status = STATE_OK;
259 if (atoi(losstr) == 100) 290 }
260 status = STATE_CRITICAL; 291 /* loss=%.0f%%;%d;%d;0;100 */
261 else if (cpl_p && loss > cpl) 292 die(status, _("FPING %s - %s (loss=%.0f%% )|%s\n"), state_text(status), server_name, loss,
262 status = STATE_CRITICAL; 293 perfdata("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, false, 0, false, 0));
263 else if (wpl_p && loss > wpl) 294
264 status = STATE_WARNING; 295 } else {
265 else 296 status = max_state(status, STATE_WARNING);
266 status = STATE_OK; 297 }
267 /* loss=%.0f%%;%d;%d;0;100 */ 298
268 die (status, _("FPING %s - %s (loss=%.0f%% )|%s\n"), 299 return status;
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} 300}
279 301
280
281
282/* process command-line arguments */ 302/* process command-line arguments */
283int 303check_fping_config_wrapper process_arguments(int argc, char **argv) {
284process_arguments (int argc, char **argv) 304 enum {
285{ 305 FWMARK_OPT = CHAR_MAX + 1,
286 int c; 306 ICMP_TIMESTAMP_OPT,
287 char *rv[2]; 307 CHECK_SOURCE_OPT,
288 308 };
289 int option = 0; 309 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
290 static struct option longopts[] = { 310 {"sourceip", required_argument, 0, 'S'},
291 {"hostname", required_argument, 0, 'H'}, 311 {"sourceif", required_argument, 0, 'I'},
292 {"sourceip", required_argument, 0, 'S'}, 312 {"critical", required_argument, 0, 'c'},
293 {"sourceif", required_argument, 0, 'I'}, 313 {"warning", required_argument, 0, 'w'},
294 {"critical", required_argument, 0, 'c'}, 314 {"alive", no_argument, 0, 'a'},
295 {"warning", required_argument, 0, 'w'}, 315 {"bytes", required_argument, 0, 'b'},
296 {"alive", no_argument, 0, 'a'}, 316 {"number", required_argument, 0, 'n'},
297 {"bytes", required_argument, 0, 'b'}, 317 {"target-timeout", required_argument, 0, 'T'},
298 {"number", required_argument, 0, 'n'}, 318 {"interval", required_argument, 0, 'i'},
299 {"target-timeout", required_argument, 0, 'T'}, 319 {"verbose", no_argument, 0, 'v'},
300 {"interval", required_argument, 0, 'i'}, 320 {"version", no_argument, 0, 'V'},
301 {"verbose", no_argument, 0, 'v'}, 321 {"help", no_argument, 0, 'h'},
302 {"version", no_argument, 0, 'V'}, 322 {"use-ipv4", no_argument, 0, '4'},
303 {"help", no_argument, 0, 'h'}, 323 {"use-ipv6", no_argument, 0, '6'},
304 {"use-ipv4", no_argument, 0, '4'}, 324 {"dontfrag", no_argument, 0, 'M'},
305 {"use-ipv6", no_argument, 0, '6'}, 325 {"random", no_argument, 0, 'R'},
306 {0, 0, 0, 0} 326#ifdef FPING_VERSION_5_2_OR_HIGHER
307 }; 327 // only available with fping version >= 5.2
308 328 {"fwmark", required_argument, NULL, FWMARK_OPT},
309 rv[PL] = NULL; 329# ifdef FPING_VERSION_5_3_OR_HIGHER
310 rv[RTA] = NULL; 330 // only available with fping version >= 5.3
311 331 {"icmp-timestamp", no_argument, NULL, ICMP_TIMESTAMP_OPT},
312 if (argc < 2) 332 {"check-source", no_argument, NULL, CHECK_SOURCE_OPT},
313 return ERROR; 333# 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 334#endif
367 break; 335 {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 336
428int 337 char *rv[2];
429get_threshold (char *arg, char *rv[2]) 338 rv[PL] = NULL;
430{ 339 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 340
341 int option = 0;
468 342
469void print_help (void) { 343 check_fping_config_wrapper result = {
344 .errorcode = OK,
345 .config = check_fping_config_init(),
346 };
470 347
471 print_revision (progname, NP_VERSION); 348 if (argc < 2) {
349 result.errorcode = ERROR;
350 return result;
351 }
472 352
473 printf ("Copyright (c) 1999 Didi Rieder <adrieder@sbox.tu-graz.ac.at>\n"); 353 if (!is_option(argv[1])) {
474 printf (COPYRIGHT, copyright, email); 354 result.config.server_name = argv[1];
355 argv[1] = argv[0];
356 argv = &argv[1];
357 argc--;
358 }
475 359
476 printf ("%s\n", _("This plugin will use the fping command to ping the specified host for a fast check")); 360 while (true) {
361 int option_index =
362 getopt_long(argc, argv, "+hVvaH:S:c:w:b:n:T:i:I:M:R:46", longopts, &option);
477 363
478 printf ("%s\n", _("Note that it is necessary to set the suid flag on fping.")); 364 if (option_index == -1 || option_index == EOF || option_index == 1) {
365 break;
366 }
479 367
480 printf ("\n\n"); 368 switch (option_index) {
369 case '?': /* print short usage statement if args not parsable */
370 usage5();
371 case 'a': /* host alive mode */
372 result.config.alive_p = true;
373 break;
374 case 'h': /* help */
375 print_help();
376 exit(STATE_UNKNOWN);
377 case 'V': /* version */
378 print_revision(progname, NP_VERSION);
379 exit(STATE_UNKNOWN);
380 case 'v': /* verbose mode */
381 verbose = true;
382 break;
383 case 'H': /* hostname */
384 if (!is_host(optarg)) {
385 usage2(_("Invalid hostname/address"), optarg);
386 }
387 result.config.server_name = optarg;
388 break;
389 case 'S': /* sourceip */
390 if (!is_host(optarg)) {
391 usage2(_("Invalid hostname/address"), optarg);
392 }
393 result.config.sourceip = optarg;
394 break;
395 case 'I': /* sourceip */
396 result.config.sourceif = optarg;
397 break;
398 case '4': /* IPv4 only */
399 address_family = AF_INET;
400 break;
401 case '6': /* IPv6 only */
402 address_family = AF_INET6;
403 break;
404 case 'c':
405 get_threshold(optarg, rv);
406 if (rv[RTA]) {
407 result.config.crta = strtod(rv[RTA], NULL);
408 result.config.crta_p = true;
409 rv[RTA] = NULL;
410 }
411 if (rv[PL]) {
412 result.config.cpl = atoi(rv[PL]);
413 result.config.cpl_p = true;
414 rv[PL] = NULL;
415 }
416 break;
417 case 'w':
418 get_threshold(optarg, rv);
419 if (rv[RTA]) {
420 result.config.wrta = strtod(rv[RTA], NULL);
421 result.config.wrta_p = true;
422 rv[RTA] = NULL;
423 }
424 if (rv[PL]) {
425 result.config.wpl = atoi(rv[PL]);
426 result.config.wpl_p = true;
427 rv[PL] = NULL;
428 }
429 break;
430 case 'b': /* bytes per packet */
431 if (is_intpos(optarg)) {
432 result.config.packet_size = atoi(optarg);
433 } else {
434 usage(_("Packet size must be a positive integer"));
435 }
436 break;
437 case 'n': /* number of packets */
438 if (is_intpos(optarg)) {
439 result.config.packet_count = atoi(optarg);
440 } else {
441 usage(_("Packet count must be a positive integer"));
442 }
443 break;
444 case 'T': /* timeout in msec */
445 if (is_intpos(optarg)) {
446 result.config.target_timeout = atoi(optarg);
447 } else {
448 usage(_("Target timeout must be a positive integer"));
449 }
450 break;
451 case 'i': /* interval in msec */
452 if (is_intpos(optarg)) {
453 result.config.packet_interval = atoi(optarg);
454 } else {
455 usage(_("Interval must be a positive integer"));
456 }
457 break;
458 case 'R':
459 result.config.randomize_packet_data = true;
460 break;
461 case 'M':
462 result.config.dontfrag = true;
463 break;
464 case FWMARK_OPT:
465 if (is_intpos(optarg)) {
466 result.config.fwmark = (unsigned int)atol(optarg);
467 result.config.fwmark_set = true;
468 } else {
469 usage(_("fwmark must be a positive integer"));
470 }
471 break;
472 case ICMP_TIMESTAMP_OPT:
473 result.config.icmp_timestamp = true;
474 break;
475 case CHECK_SOURCE_OPT:
476 result.config.check_source = true;
477 break;
478 }
479 }
481 480
482 print_usage (); 481 if (result.config.server_name == NULL) {
482 usage4(_("Hostname was not supplied"));
483 }
483 484
484 printf (UT_HELP_VRSN); 485 return result;
485 printf (UT_EXTRA_OPTS); 486}
486 487
487 printf (UT_IPv46); 488int get_threshold(char *arg, char *rv[2]) {
489 char *arg2 = NULL;
490
491 char *arg1 = strdup(arg);
492 if (strpbrk(arg1, ",:")) {
493 arg2 = 1 + strpbrk(arg1, ",:");
494 }
495
496 if (arg2) {
497 arg1[strcspn(arg1, ",:")] = 0;
498 if (strstr(arg1, "%") && strstr(arg2, "%")) {
499 die(STATE_UNKNOWN, _("%s: Only one threshold may be packet loss (%s)\n"), progname,
500 arg);
501 }
502 if (!strstr(arg1, "%") && !strstr(arg2, "%")) {
503 die(STATE_UNKNOWN, _("%s: Only one threshold must be packet loss (%s)\n"), progname,
504 arg);
505 }
506 }
507
508 if (arg2 && strstr(arg2, "%")) {
509 rv[PL] = arg2;
510 rv[RTA] = arg1;
511 } else if (arg2) {
512 rv[PL] = arg1;
513 rv[RTA] = arg2;
514 } else if (strstr(arg1, "%")) {
515 rv[PL] = arg1;
516 } else {
517 rv[RTA] = arg1;
518 }
519
520 return OK;
521}
488 522
489 printf (" %s\n", "-H, --hostname=HOST"); 523void print_help(void) {
490 printf (" %s\n", _("name or IP Address of host to ping (IP Address bypasses name lookup, reducing system load)")); 524
491 printf (" %s\n", "-w, --warning=THRESHOLD"); 525 print_revision(progname, NP_VERSION);
492 printf (" %s\n", _("warning threshold pair")); 526
493 printf (" %s\n", "-c, --critical=THRESHOLD"); 527 printf("Copyright (c) 1999 Didi Rieder <adrieder@sbox.tu-graz.ac.at>\n");
494 printf (" %s\n", _("critical threshold pair")); 528 printf(COPYRIGHT, copyright, email);
495 printf (" %s\n", "-a, --alive"); 529
496 printf (" %s\n", _("Return OK after first successful reply")); 530 printf("%s\n",
497 printf (" %s\n", "-b, --bytes=INTEGER"); 531 _("This plugin will use the fping command to ping the specified host for a fast check"));
498 printf (" %s (default: %d)\n", _("size of ICMP packet"),PACKET_SIZE); 532
499 printf (" %s\n", "-n, --number=INTEGER"); 533 printf("%s\n", _("Note that it is necessary to set the suid flag on fping."));
500 printf (" %s (default: %d)\n", _("number of ICMP packets to send"),PACKET_COUNT); 534
501 printf (" %s\n", "-T, --target-timeout=INTEGER"); 535 printf("\n\n");
502 printf (" %s (default: fping's default for -t)\n", _("Target timeout (ms)")); 536
503 printf (" %s\n", "-i, --interval=INTEGER"); 537 print_usage();
504 printf (" %s (default: fping's default for -p)\n", _("Interval (ms) between sending packets")); 538
505 printf (" %s\n", "-S, --sourceip=HOST"); 539 printf(UT_HELP_VRSN);
506 printf (" %s\n", _("name or IP Address of sourceip")); 540 printf(UT_EXTRA_OPTS);
507 printf (" %s\n", "-I, --sourceif=IF"); 541
508 printf (" %s\n", _("source interface name")); 542 printf(UT_IPv46);
509 printf (UT_VERBOSE); 543
510 printf ("\n"); 544 printf(" %s\n", "-H, --hostname=HOST");
511 printf (" %s\n", _("THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel time (ms)")); 545 printf(" %s\n", _("name or IP Address of host to ping (IP Address bypasses name lookup, "
512 printf (" %s\n", _("which triggers a WARNING or CRITICAL state, and <pl> is the percentage of")); 546 "reducing system load)"));
513 printf (" %s\n", _("packet loss to trigger an alarm state.")); 547 printf(" %s\n", "-w, --warning=THRESHOLD");
548 printf(" %s\n", _("warning threshold pair"));
549 printf(" %s\n", "-c, --critical=THRESHOLD");
550 printf(" %s\n", _("critical threshold pair"));
551 printf(" %s\n", "-a, --alive");
552 printf(" %s\n", _("Return OK after first successful reply"));
553 printf(" %s\n", "-b, --bytes=INTEGER");
554 printf(" %s (default: %d)\n", _("size of ICMP packet"), PACKET_SIZE);
555 printf(" %s\n", "-n, --number=INTEGER");
556 printf(" %s (default: %d)\n", _("number of ICMP packets to send"), PACKET_COUNT);
557 printf(" %s\n", "-T, --target-timeout=INTEGER");
558 printf(" %s (default: fping's default for -t)\n", _("Target timeout (ms)"));
559 printf(" %s\n", "-i, --interval=INTEGER");
560 printf(" %s (default: fping's default for -p)\n",
561 _("Interval (ms) between sending packets"));
562 printf(" %s\n", "-S, --sourceip=HOST");
563 printf(" %s\n", _("name or IP Address of sourceip"));
564 printf(" %s\n", "-I, --sourceif=IF");
565 printf(" %s\n", _("source interface name"));
566 printf(" %s\n", "-M, --dontfrag");
567 printf(" %s\n", _("set the Don't Fragment flag"));
568 printf(" %s\n", "-R, --random");
569 printf(" %s\n", _("random packet data (to foil link data compression)"));
570#ifdef FPING_VERSION_5_2_OR_HIGHER
571 printf(" %s\n", "--fwmark=INTEGER");
572 printf(" %s\n", _("set the routing mark to INTEGER (fping option)"));
573# ifdef FPING_VERSION_5_3_OR_HIGHER
574 printf(" %s\n", "--icmp-timestamp");
575 printf(" %s\n", _("use ICMP Timestamp instead of ICMP Echo (fping option)"));
576 printf(" %s\n", "--check-source");
577 printf(" %s\n", _("discard replies not from target address (fping option)"));
578# endif
579#endif
580 printf(UT_VERBOSE);
581 printf("\n");
582 printf(" %s\n",
583 _("THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel time (ms)"));
584 printf(" %s\n", _("which triggers a WARNING or CRITICAL state, and <pl> is the percentage of"));
585 printf(" %s\n", _("packet loss to trigger an alarm state."));
514 586
515 printf ("\n"); 587 printf("\n");
516 printf (" %s\n", _("IPv4 is used by default. Specify -6 to use IPv6.")); 588 printf(" %s\n", _("IPv4 is used by default. Specify -6 to use IPv6."));
517 589
518 printf (UT_SUPPORT); 590 printf(UT_SUPPORT);
519} 591}
520 592
521 593void print_usage(void) {
522void 594 printf("%s\n", _("Usage:"));
523print_usage (void) 595 printf(" %s <host_address> -w limit -c limit [-b size] [-n number] [-T number] [-i number]\n",
524{ 596 progname);
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} 597}
diff --git a/plugins/check_fping.d/config.h b/plugins/check_fping.d/config.h
new file mode 100644
index 00000000..d3e50565
--- /dev/null
+++ b/plugins/check_fping.d/config.h
@@ -0,0 +1,81 @@
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 // only available with fping version >= 5.3
40 // Setting icmp_timestamp tells fping to use ICMP Timestamp (ICMP type 13) instead
41 // of ICMP Echo
42 bool icmp_timestamp;
43
44 // Setting check_source lets fping discard replies which are not from the target address
45 bool check_source;
46} check_fping_config;
47
48check_fping_config check_fping_config_init() {
49 check_fping_config tmp = {
50 .server_name = NULL,
51 .sourceip = NULL,
52 .sourceif = NULL,
53 .packet_size = PACKET_SIZE,
54 .packet_count = PACKET_COUNT,
55 .target_timeout = 0,
56 .packet_interval = 0,
57 .randomize_packet_data = false,
58 .dontfrag = false,
59 .alive_p = false,
60
61 .crta = 0,
62 .crta_p = false,
63 .wrta = 0,
64 .wrta_p = false,
65
66 .cpl = 0,
67 .cpl_p = false,
68 .wpl = 0,
69 .wpl_p = false,
70
71 // only available with fping version >= 5.2
72 .fwmark = 0,
73 .fwmark_set = false, // just to be deterministic
74
75 // only available with fping version >= 5.3
76 .icmp_timestamp = false,
77 .check_source = false,
78
79 };
80 return tmp;
81}
diff --git a/plugins/check_game.c b/plugins/check_game.c
index ca126973..974a7253 100644
--- a/plugins/check_game.c
+++ b/plugins/check_game.c
@@ -1,335 +1,329 @@
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,
179 return ERROR; 81 config.game_type, config.server_ip);
180 82
181 for (c = 1; c < argc; c++) { 83 if (config.port) {
182 if (strcmp ("-mf", argv[c]) == 0) 84 xasprintf(&command_line, "%s:%-d", command_line, config.port);
183 strcpy (argv[c], "-m"); 85 }
184 else if (strcmp ("-pf", argv[c]) == 0) 86
185 strcpy (argv[c], "-p"); 87 if (verbose) {
186 else if (strcmp ("-gf", argv[c]) == 0) 88 printf("%s\n", command_line);
187 strcpy (argv[c], "-g"); 89 }
188 } 90
189 91 /* run the command. historically, this plugin ignores output on stderr,
190 while (1) { 92 * as well as return status of the qstat program */
191 c = getopt_long (argc, argv, "hVvt:H:P:G:g:p:m:", long_opts, &opt_index); 93 output chld_out = {};
192 94 (void)np_runcmd(command_line, &chld_out, NULL, 0);
193 if (c == -1 || c == EOF) 95
194 break; 96 /* sanity check */
195 97 /* was thinking about running qstat without any options, capturing the
196 switch (c) { 98 -default line, parsing it & making an array of all know server types
197 case 'h': /* help */ 99 but thought this would be too much hassle considering this is a tool
198 print_help (); 100 for intelligent sysadmins (ha). Could put a static array of known
199 exit (STATE_UNKNOWN); 101 server types in a header file but then we'd be limiting ourselves
200 case 'V': /* version */ 102
201 print_revision (progname, NP_VERSION); 103 In the end, I figured I'd simply let an error occur & then trap it
202 exit (STATE_UNKNOWN); 104 */
203 case 'v': /* version */ 105
204 verbose = true; 106 if (!strncmp(chld_out.line[0], "unknown option", strlen("unknown option"))) {
205 break; 107 printf(_("CRITICAL - Host type parameter incorrect!\n"));
206 case 't': /* timeout period */ 108 result = STATE_CRITICAL;
207 timeout_interval = atoi (optarg); 109 exit(result);
208 break; 110 }
209 case 'H': /* hostname */ 111
210 if (strlen (optarg) >= MAX_HOST_ADDRESS_LENGTH) 112 char *ret[QSTAT_MAX_RETURN_ARGS];
211 die (STATE_UNKNOWN, _("Input buffer overflow\n")); 113 size_t i = 0;
212 server_ip = optarg; 114 char *sequence = strtok(chld_out.line[0], QSTAT_DATA_DELIMITER);
213 break; 115 while (sequence != NULL) {
214 case 'P': /* port */ 116 ret[i] = sequence;
215 port = atoi (optarg); 117 sequence = strtok(NULL, QSTAT_DATA_DELIMITER);
216 break; 118 i++;
217 case 'G': /* hostname */ 119 if (i >= QSTAT_MAX_RETURN_ARGS) {
218 if (strlen (optarg) >= MAX_INPUT_BUFFER) 120 break;
219 die (STATE_UNKNOWN, _("Input buffer overflow\n")); 121 }
220 game_type = optarg; 122 }
221 break; 123
222 case 'p': /* index of ping field */ 124 if (strstr(ret[2], QSTAT_HOST_ERROR)) {
223 qstat_ping_field = atoi (optarg); 125 printf(_("CRITICAL - Host not found\n"));
224 if (qstat_ping_field < 0 || qstat_ping_field > QSTAT_MAX_RETURN_ARGS) 126 result = STATE_CRITICAL;
225 return ERROR; 127 } else if (strstr(ret[2], QSTAT_HOST_DOWN)) {
226 break; 128 printf(_("CRITICAL - Game server down or unavailable\n"));
227 case 'm': /* index on map field */ 129 result = STATE_CRITICAL;
228 qstat_map_field = atoi (optarg); 130 } else if (strstr(ret[2], QSTAT_HOST_TIMEOUT)) {
229 if (qstat_map_field < 0 || qstat_map_field > QSTAT_MAX_RETURN_ARGS) 131 printf(_("CRITICAL - Game server timeout\n"));
230 return ERROR; 132 result = STATE_CRITICAL;
231 break; 133 } else {
232 case 'g': /* index of game field */ 134 printf("OK: %s/%s %s (%s), Ping: %s ms|%s %s\n", ret[config.qstat_game_players],
233 qstat_game_field = atoi (optarg); 135 ret[config.qstat_game_players_max], ret[config.qstat_game_field],
234 if (qstat_game_field < 0 || qstat_game_field > QSTAT_MAX_RETURN_ARGS) 136 ret[config.qstat_map_field], ret[config.qstat_ping_field],
235 return ERROR; 137 perfdata("players", atol(ret[config.qstat_game_players]), "", false, 0, false, 0,
236 break; 138 true, 0, true, atol(ret[config.qstat_game_players_max])),
237 case 129: /* index of player count field */ 139 fperfdata("ping", strtod(ret[config.qstat_ping_field], NULL), "", false, 0, false, 0,
238 qstat_game_players = atoi (optarg); 140 true, 0, false, 0));
239 if (qstat_game_players_max == 0) 141 }
240 qstat_game_players_max = qstat_game_players - 1; 142
241 if (qstat_game_players < 0 || qstat_game_players > QSTAT_MAX_RETURN_ARGS) 143 exit(result);
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} 144}
265 145
266 146#define players_field_index 129
267int 147#define max_players_field_index 130
268validate_arguments (void) 148
269{ 149check_game_config_wrapper process_arguments(int argc, char **argv) {
270 if (qstat_game_players_max < 0) 150 static struct option long_opts[] = {
271 qstat_game_players_max = 4; 151 {"help", no_argument, 0, 'h'},
272 152 {"version", no_argument, 0, 'V'},
273 if (qstat_game_players < 0) 153 {"verbose", no_argument, 0, 'v'},
274 qstat_game_players = 5; 154 {"timeout", required_argument, 0, 't'},
275 155 {"hostname", required_argument, 0, 'H'},
276 if (qstat_game_field < 0) 156 {"port", required_argument, 0, 'P'},
277 qstat_game_field = 2; 157 {"game-type", required_argument, 0, 'G'},
278 158 {"map-field", required_argument, 0, 'm'},
279 if (qstat_map_field < 0) 159 {"ping-field", required_argument, 0, 'p'},
280 qstat_map_field = 3; 160 {"game-field", required_argument, 0, 'g'},
281 161 {"players-field", required_argument, 0, players_field_index},
282 if (qstat_ping_field < 0) 162 {"max-players-field", required_argument, 0, max_players_field_index},
283 qstat_ping_field = 5; 163 {0, 0, 0, 0}};
284 164
285 return OK; 165 check_game_config_wrapper result = {
166 .config = check_game_config_init(),
167 .errorcode = OK,
168 };
169
170 if (argc < 2) {
171 result.errorcode = ERROR;
172 return result;
173 }
174
175 for (int option_counter = 1; option_counter < argc; option_counter++) {
176 if (strcmp("-mf", argv[option_counter]) == 0) {
177 strcpy(argv[option_counter], "-m");
178 } else if (strcmp("-pf", argv[option_counter]) == 0) {
179 strcpy(argv[option_counter], "-p");
180 } else if (strcmp("-gf", argv[option_counter]) == 0) {
181 strcpy(argv[option_counter], "-g");
182 }
183 }
184
185 int opt_index = 0;
186 while (true) {
187 int option_index = getopt_long(argc, argv, "hVvt:H:P:G:g:p:m:", long_opts, &opt_index);
188
189 if (option_index == -1 || option_index == EOF) {
190 break;
191 }
192
193 switch (option_index) {
194 case 'h': /* help */
195 print_help();
196 exit(STATE_UNKNOWN);
197 case 'V': /* version */
198 print_revision(progname, NP_VERSION);
199 exit(STATE_UNKNOWN);
200 case 'v': /* version */
201 verbose = true;
202 break;
203 case 't': /* timeout period */
204 timeout_interval = atoi(optarg);
205 break;
206 case 'H': /* hostname */
207 if (strlen(optarg) >= MAX_HOST_ADDRESS_LENGTH) {
208 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
209 }
210 result.config.server_ip = optarg;
211 break;
212 case 'P': /* port */
213 result.config.port = atoi(optarg);
214 break;
215 case 'G': /* hostname */
216 if (strlen(optarg) >= MAX_INPUT_BUFFER) {
217 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
218 }
219 result.config.game_type = optarg;
220 break;
221 case 'p': /* index of ping field */
222 result.config.qstat_ping_field = atoi(optarg);
223 if (result.config.qstat_ping_field < 0 ||
224 result.config.qstat_ping_field > QSTAT_MAX_RETURN_ARGS) {
225 result.errorcode = ERROR;
226 return result;
227 }
228 break;
229 case 'm': /* index on map field */
230 result.config.qstat_map_field = atoi(optarg);
231 if (result.config.qstat_map_field < 0 ||
232 result.config.qstat_map_field > QSTAT_MAX_RETURN_ARGS) {
233 result.errorcode = ERROR;
234 return result;
235 }
236 break;
237 case 'g': /* index of game field */
238 result.config.qstat_game_field = atoi(optarg);
239 if (result.config.qstat_game_field < 0 ||
240 result.config.qstat_game_field > QSTAT_MAX_RETURN_ARGS) {
241 result.errorcode = ERROR;
242 return result;
243 }
244 break;
245 case players_field_index: /* index of player count field */
246 result.config.qstat_game_players = atoi(optarg);
247 if (result.config.qstat_game_players_max == 0) {
248 result.config.qstat_game_players_max = result.config.qstat_game_players - 1;
249 }
250 if (result.config.qstat_game_players < 0 ||
251 result.config.qstat_game_players > QSTAT_MAX_RETURN_ARGS) {
252 result.errorcode = ERROR;
253 return result;
254 }
255 break;
256 case max_players_field_index: /* index of max players field */
257 result.config.qstat_game_players_max = atoi(optarg);
258 if (result.config.qstat_game_players_max < 0 ||
259 result.config.qstat_game_players_max > QSTAT_MAX_RETURN_ARGS) {
260 result.errorcode = ERROR;
261 return result;
262 }
263 break;
264 default: /* args not parsable */
265 usage5();
266 }
267 }
268
269 int option_counter = optind;
270 /* first option is the game type */
271 if (!result.config.game_type && option_counter < argc) {
272 result.config.game_type = strdup(argv[option_counter++]);
273 }
274
275 /* Second option is the server name */
276 if (!result.config.server_ip && option_counter < argc) {
277 result.config.server_ip = strdup(argv[option_counter++]);
278 }
279
280 return result;
286} 281}
287 282
283void print_help(void) {
284 print_revision(progname, NP_VERSION);
288 285
289void 286 printf("Copyright (c) 1999 Ian Cass, Knowledge Matters Limited\n");
290print_help (void) 287 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 288
297 printf (_("This plugin tests game server connections with the specified host.")); 289 printf(_("This plugin tests game server connections with the specified host."));
298 290
299 printf ("\n\n"); 291 printf("\n\n");
300 292
301 print_usage (); 293 print_usage();
302 294
303 printf (UT_HELP_VRSN); 295 printf(UT_HELP_VRSN);
304 printf (UT_EXTRA_OPTS); 296 printf(UT_EXTRA_OPTS);
297 printf(" -H, --hostname=ADDRESS\n"
298 " Host name, IP Address, or unix socket (must be an absolute path)\n");
299 printf(" %s\n", "-P");
300 printf(" %s\n", _("Optional port to connect to"));
301 printf(" %s\n", "-g");
302 printf(" %s\n", _("Field number in raw qstat output that contains game name"));
303 printf(" %s\n", "-m");
304 printf(" %s\n", _("Field number in raw qstat output that contains map name"));
305 printf(" %s\n", "-p");
306 printf(" %s\n", _("Field number in raw qstat output that contains ping time"));
305 307
306 printf (" %s\n", "-p"); 308 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 309
315 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 310 printf("\n");
311 printf("%s\n", _("Notes:"));
312 printf(" %s\n",
313 _("This plugin uses the 'qstat' command, the popular game server status query tool."));
314 printf(" %s\n",
315 _("If you don't have the package installed, you will need to download it from"));
316 printf(" %s\n", _("https://github.com/multiplay/qstat before you can use this plugin."));
316 317
317 printf ("\n"); 318 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} 319}
325 320
326 321void print_usage(void) {
327 322 printf("%s\n", _("Usage:"));
328void 323 printf(" %s [-hvV] [-P port] [-t timeout] [-g game_field] [-m map_field] [-p ping_field] [-G "
329print_usage (void) 324 "game-time] [-H hostname] <game> "
330{ 325 "<ip_address>\n",
331 printf ("%s\n", _("Usage:")); 326 progname);
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} 327}
334 328
335/****************************************************************************** 329/******************************************************************************
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..9907abc5 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,165 @@ 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",
110 (query_string, 89 HPJD_LINE_STATUS, HPJD_PAPER_STATUS, HPJD_INTERVENTION_REQUIRED,
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_PERIPHERAL_ERROR, HPJD_GD_PAPER_JAM, HPJD_GD_PAPER_OUT, HPJD_GD_TONER_LOW,
112 HPJD_LINE_STATUS, 91 HPJD_GD_PAGE_PUNT, HPJD_GD_MEMORY_OUT, HPJD_GD_DOOR_OPEN, HPJD_GD_PAPER_OUTPUT,
113 HPJD_PAPER_STATUS, 92 HPJD_GD_STATUS_DISPLAY);
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 93
123 /* get the command to run */ 94 /* get the command to run */
124 sprintf (command_line, "%s -OQa -m : -v 1 -c %s %s:%u %s", 95 char command_line[1024];
125 PATH_TO_SNMPGET, 96 sprintf(command_line, "%s -OQa -m : -v 1 -c %s %s:%u %s", PATH_TO_SNMPGET, config.community,
126 community, 97 config.address, config.port, query_string);
127 address,
128 port,
129 query_string);
130 98
131 /* run the command */ 99 /* run the command */
132 child_process = spopen (command_line); 100 child_process = spopen(command_line);
133 if (child_process == NULL) { 101 if (child_process == NULL) {
134 printf (_("Could not open pipe: %s\n"), command_line); 102 printf(_("Could not open pipe: %s\n"), command_line);
135 return STATE_UNKNOWN; 103 return STATE_UNKNOWN;
136 } 104 }
137 105
138 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); 106 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
139 if (child_stderr == NULL) { 107 if (child_stderr == NULL) {
140 printf (_("Could not open stderr for %s\n"), command_line); 108 printf(_("Could not open stderr for %s\n"), command_line);
141 } 109 }
142 110
143 result = STATE_OK; 111 mp_state_enum result = STATE_OK;
144 112
145 line = 0; 113 int line_status = ONLINE;
146 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) { 114 int paper_status = 0;
115 int intervention_required = 0;
116 int peripheral_error = 0;
117 int paper_jam = 0;
118 int paper_out = 0;
119 int toner_low = 0;
120 int page_punt = 0;
121 int memory_out = 0;
122 int door_open = 0;
123 int paper_output = 0;
124 char display_message[MAX_INPUT_BUFFER];
125
126 char input_buffer[MAX_INPUT_BUFFER];
127 char *errmsg = malloc(MAX_INPUT_BUFFER);
128 int line = 0;
147 129
130 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
148 /* strip the newline character from the end of the input */ 131 /* strip the newline character from the end of the input */
149 if (input_buffer[strlen (input_buffer) - 1] == '\n') 132 if (input_buffer[strlen(input_buffer) - 1] == '\n') {
150 input_buffer[strlen (input_buffer) - 1] = 0; 133 input_buffer[strlen(input_buffer) - 1] = 0;
134 }
151 135
152 line++; 136 line++;
153 137
154 temp_buffer = strtok (input_buffer, "="); 138 char *temp_buffer = strtok(input_buffer, "=");
155 temp_buffer = strtok (NULL, "="); 139 temp_buffer = strtok(NULL, "=");
156 140
157 if (temp_buffer == NULL && line < 13) { 141 if (temp_buffer == NULL && line < 13) {
158 142 result = STATE_UNKNOWN;
159 result = STATE_UNKNOWN; 143 strcpy(errmsg, input_buffer);
160 strcpy (errmsg, input_buffer);
161
162 } else { 144 } else {
163
164 switch (line) { 145 switch (line) {
165 146 case 1: /* 1st line should contain the line status */
166 case 1: /* 1st line should contain the line status */ 147 line_status = atoi(temp_buffer);
167 line_status = atoi (temp_buffer);
168 break; 148 break;
169 case 2: /* 2nd line should contain the paper status */ 149 case 2: /* 2nd line should contain the paper status */
170 paper_status = atoi (temp_buffer); 150 paper_status = atoi(temp_buffer);
171 break; 151 break;
172 case 3: /* 3rd line should be intervention required */ 152 case 3: /* 3rd line should be intervention required */
173 intervention_required = atoi (temp_buffer); 153 intervention_required = atoi(temp_buffer);
174 break; 154 break;
175 case 4: /* 4th line should be peripheral error */ 155 case 4: /* 4th line should be peripheral error */
176 peripheral_error = atoi (temp_buffer); 156 peripheral_error = atoi(temp_buffer);
177 break; 157 break;
178 case 5: /* 5th line should contain the paper jam status */ 158 case 5: /* 5th line should contain the paper jam status */
179 paper_jam = atoi (temp_buffer); 159 paper_jam = atoi(temp_buffer);
180 break; 160 break;
181 case 6: /* 6th line should contain the paper out status */ 161 case 6: /* 6th line should contain the paper out status */
182 paper_out = atoi (temp_buffer); 162 paper_out = atoi(temp_buffer);
183 break; 163 break;
184 case 7: /* 7th line should contain the toner low status */ 164 case 7: /* 7th line should contain the toner low status */
185 toner_low = atoi (temp_buffer); 165 toner_low = atoi(temp_buffer);
186 break; 166 break;
187 case 8: /* did data come too slow for engine */ 167 case 8: /* did data come too slow for engine */
188 page_punt = atoi (temp_buffer); 168 page_punt = atoi(temp_buffer);
189 break; 169 break;
190 case 9: /* did we run out of memory */ 170 case 9: /* did we run out of memory */
191 memory_out = atoi (temp_buffer); 171 memory_out = atoi(temp_buffer);
192 break; 172 break;
193 case 10: /* is there a door open */ 173 case 10: /* is there a door open */
194 door_open = atoi (temp_buffer); 174 door_open = atoi(temp_buffer);
195 break; 175 break;
196 case 11: /* is output tray full */ 176 case 11: /* is output tray full */
197 paper_output = atoi (temp_buffer); 177 paper_output = atoi(temp_buffer);
198 break; 178 break;
199 case 12: /* display panel message */ 179 case 12: /* display panel message */
200 strcpy (display_message, temp_buffer + 1); 180 strcpy(display_message, temp_buffer + 1);
201 break; 181 break;
202 default: /* fold multiline message */ 182 default: /* fold multiline message */
203 strncat (display_message, input_buffer, 183 strncat(display_message, input_buffer,
204 sizeof (display_message) - strlen (display_message) - 1); 184 sizeof(display_message) - strlen(display_message) - 1);
205 } 185 }
206
207 } 186 }
208 187
209 /* break out of the read loop if we encounter an error */ 188 /* break out of the read loop if we encounter an error */
210 if (result != STATE_OK) 189 if (result != STATE_OK) {
211 break; 190 break;
191 }
212 } 192 }
213 193
214 /* WARNING if output found on stderr */ 194 /* WARNING if output found on stderr */
215 if (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) { 195 if (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
216 result = max_state (result, STATE_WARNING); 196 result = max_state(result, STATE_WARNING);
217 /* remove CRLF */ 197 /* remove CRLF */
218 if (input_buffer[strlen (input_buffer) - 1] == '\n') 198 if (input_buffer[strlen(input_buffer) - 1] == '\n') {
219 input_buffer[strlen (input_buffer) - 1] = 0; 199 input_buffer[strlen(input_buffer) - 1] = 0;
220 sprintf (errmsg, "%s", input_buffer ); 200 }
221 201 sprintf(errmsg, "%s", input_buffer);
222 } 202 }
223 203
224 /* close stderr */ 204 /* close stderr */
225 (void) fclose (child_stderr); 205 (void)fclose(child_stderr);
226 206
227 /* close the pipe */ 207 /* close the pipe */
228 if (spclose (child_process)) 208 if (spclose(child_process)) {
229 result = max_state (result, STATE_WARNING); 209 result = max_state(result, STATE_WARNING);
210 }
230 211
231 /* if there wasn't any output, display an error */ 212 /* if there wasn't any output, display an error */
232 if (line == 0) { 213 if (line == 0) {
233
234 /* might not be the problem, but most likely is. */ 214 /* might not be the problem, but most likely is. */
235 result = STATE_UNKNOWN ; 215 result = STATE_UNKNOWN;
236 xasprintf (&errmsg, "%s : Timeout from host %s\n", errmsg, address ); 216 xasprintf(&errmsg, "%s : Timeout from host %s\n", errmsg, config.address);
237
238 } 217 }
239 218
240 /* if we had no read errors, check the printer status results... */ 219 /* if we had no read errors, check the printer status results... */
@@ -242,201 +221,171 @@ main (int argc, char **argv)
242 221
243 if (paper_jam) { 222 if (paper_jam) {
244 result = STATE_WARNING; 223 result = STATE_WARNING;
245 strcpy (errmsg, _("Paper Jam")); 224 strcpy(errmsg, _("Paper Jam"));
246 } 225 } else if (paper_out) {
247 else if (paper_out) { 226 if (config.check_paper_out) {
248 if (check_paper_out)
249 result = STATE_WARNING; 227 result = STATE_WARNING;
250 strcpy (errmsg, _("Out of Paper")); 228 }
251 } 229 strcpy(errmsg, _("Out of Paper"));
252 else if (line_status == OFFLINE) { 230 } else if (line_status == OFFLINE) {
253 if (strcmp (errmsg, "POWERSAVE ON") != 0) { 231 if (strcmp(errmsg, "POWERSAVE ON") != 0) {
254 result = STATE_WARNING; 232 result = STATE_WARNING;
255 strcpy (errmsg, _("Printer Offline")); 233 strcpy(errmsg, _("Printer Offline"));
256 } 234 }
257 } 235 } else if (peripheral_error) {
258 else if (peripheral_error) {
259 result = STATE_WARNING; 236 result = STATE_WARNING;
260 strcpy (errmsg, _("Peripheral Error")); 237 strcpy(errmsg, _("Peripheral Error"));
261 } 238 } else if (intervention_required) {
262 else if (intervention_required) {
263 result = STATE_WARNING; 239 result = STATE_WARNING;
264 strcpy (errmsg, _("Intervention Required")); 240 strcpy(errmsg, _("Intervention Required"));
265 } 241 } else if (toner_low) {
266 else if (toner_low) {
267 result = STATE_WARNING; 242 result = STATE_WARNING;
268 strcpy (errmsg, _("Toner Low")); 243 strcpy(errmsg, _("Toner Low"));
269 } 244 } else if (memory_out) {
270 else if (memory_out) {
271 result = STATE_WARNING; 245 result = STATE_WARNING;
272 strcpy (errmsg, _("Insufficient Memory")); 246 strcpy(errmsg, _("Insufficient Memory"));
273 } 247 } else if (door_open) {
274 else if (door_open) {
275 result = STATE_WARNING; 248 result = STATE_WARNING;
276 strcpy (errmsg, _("A Door is Open")); 249 strcpy(errmsg, _("A Door is Open"));
277 } 250 } else if (paper_output) {
278 else if (paper_output) {
279 result = STATE_WARNING; 251 result = STATE_WARNING;
280 strcpy (errmsg, _("Output Tray is Full")); 252 strcpy(errmsg, _("Output Tray is Full"));
281 } 253 } else if (page_punt) {
282 else if (page_punt) {
283 result = STATE_WARNING; 254 result = STATE_WARNING;
284 strcpy (errmsg, _("Data too Slow for Engine")); 255 strcpy(errmsg, _("Data too Slow for Engine"));
285 } 256 } else if (paper_status) {
286 else if (paper_status) {
287 result = STATE_WARNING; 257 result = STATE_WARNING;
288 strcpy (errmsg, _("Unknown Paper Error")); 258 strcpy(errmsg, _("Unknown Paper Error"));
289 } 259 }
290 } 260 }
291 261
292 if (result == STATE_OK) 262 if (result == STATE_OK) {
293 printf (_("Printer ok - (%s)\n"), display_message); 263 printf(_("Printer ok - (%s)\n"), display_message);
294 264 } else if (result == STATE_UNKNOWN) {
295 else if (result == STATE_UNKNOWN) { 265 printf("%s\n", errmsg);
296
297 printf ("%s\n", errmsg);
298
299 /* if printer could not be reached, escalate to critical */ 266 /* if printer could not be reached, escalate to critical */
300 if (strstr (errmsg, "Timeout")) 267 if (strstr(errmsg, "Timeout")) {
301 result = STATE_CRITICAL; 268 result = STATE_CRITICAL;
269 }
270 } else if (result == STATE_WARNING) {
271 printf("%s (%s)\n", errmsg, display_message);
302 } 272 }
303 273
304 else if (result == STATE_WARNING) 274 exit(result);
305 printf ("%s (%s)\n", errmsg, display_message);
306
307 return result;
308} 275}
309 276
310
311/* process command-line arguments */ 277/* process command-line arguments */
312int 278check_hpjd_config_wrapper process_arguments(int argc, char **argv) {
313process_arguments (int argc, char **argv) 279 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
314{ 280 {"community", required_argument, 0, 'C'},
315 int c; 281 /* {"critical", required_argument,0,'c'}, */
316 282 /* {"warning", required_argument,0,'w'}, */
317 int option = 0; 283 {"port", required_argument, 0, 'p'},
318 static struct option longopts[] = { 284 {"version", no_argument, 0, 'V'},
319 {"hostname", required_argument, 0, 'H'}, 285 {"help", no_argument, 0, 'h'},
320 {"community", required_argument, 0, 'C'}, 286 {0, 0, 0, 0}};
321/* {"critical", required_argument,0,'c'}, */ 287
322/* {"warning", required_argument,0,'w'}, */ 288 check_hpjd_config_wrapper result = {
323 {"port", required_argument,0,'p'}, 289 .errorcode = OK,
324 {"version", no_argument, 0, 'V'}, 290 .config = check_hpjd_config_init(),
325 {"help", no_argument, 0, 'h'},
326 {0, 0, 0, 0}
327 }; 291 };
328 292
329 if (argc < 2) 293 if (argc < 2) {
330 return ERROR; 294 result.errorcode = ERROR;
331 295 return result;
296 }
332 297
333 while (1) { 298 int option = 0;
334 c = getopt_long (argc, argv, "+hVH:C:p:D", longopts, &option); 299 while (true) {
300 int option_index = getopt_long(argc, argv, "+hVH:C:p:D", longopts, &option);
335 301
336 if (c == -1 || c == EOF || c == 1) 302 if (option_index == -1 || option_index == EOF || option_index == 1) {
337 break; 303 break;
304 }
338 305
339 switch (c) { 306 switch (option_index) {
340 case 'H': /* hostname */ 307 case 'H': /* hostname */
341 if (is_host (optarg)) { 308 if (is_host(optarg)) {
342 address = strscpy(address, optarg) ; 309 result.config.address = strscpy(result.config.address, optarg);
343 } 310 } else {
344 else { 311 usage2(_("Invalid hostname/address"), optarg);
345 usage2 (_("Invalid hostname/address"), optarg);
346 } 312 }
347 break; 313 break;
348 case 'C': /* community */ 314 case 'C': /* community */
349 community = strscpy (community, optarg); 315 result.config.community = strscpy(result.config.community, optarg);
350 break; 316 break;
351 case 'p': 317 case 'p':
352 if (!is_intpos(optarg)) 318 if (!is_intpos(optarg)) {
353 usage2 (_("Port must be a positive short integer"), optarg); 319 usage2(_("Port must be a positive short integer"), optarg);
354 else 320 } else {
355 port = atoi(optarg); 321 result.config.port = atoi(optarg);
322 }
356 break; 323 break;
357 case 'D': /* disable paper out check*/ 324 case 'D': /* disable paper out check*/
358 check_paper_out = 0; 325 result.config.check_paper_out = false;
359 break; 326 break;
360 case 'V': /* version */ 327 case 'V': /* version */
361 print_revision (progname, NP_VERSION); 328 print_revision(progname, NP_VERSION);
362 exit (STATE_UNKNOWN); 329 exit(STATE_UNKNOWN);
363 case 'h': /* help */ 330 case 'h': /* help */
364 print_help (); 331 print_help();
365 exit (STATE_UNKNOWN); 332 exit(STATE_UNKNOWN);
366 case '?': /* help */ 333 case '?': /* help */
367 usage5 (); 334 usage5();
368 } 335 }
369 } 336 }
370 337
371 c = optind; 338 int c = optind;
372 if (address == NULL) { 339 if (result.config.address == NULL) {
373 if (is_host (argv[c])) { 340 if (is_host(argv[c])) {
374 address = argv[c++]; 341 result.config.address = argv[c++];
375 } 342 } else {
376 else { 343 usage2(_("Invalid hostname/address"), argv[c]);
377 usage2 (_("Invalid hostname/address"), argv[c]);
378 } 344 }
379 } 345 }
380 346
381 if (community == NULL) { 347 if (result.config.community == NULL) {
382 if (argv[c] != NULL ) 348 if (argv[c] != NULL) {
383 community = argv[c]; 349 result.config.community = argv[c];
384 else 350 } else {
385 community = strdup (DEFAULT_COMMUNITY); 351 result.config.community = strdup(DEFAULT_COMMUNITY);
386 } 352 }
387
388 if (port == 0) {
389 port = atoi(DEFAULT_PORT);
390 } 353 }
391 354
392 return validate_arguments (); 355 return result;
393}
394
395
396int
397validate_arguments (void)
398{
399 return OK;
400} 356}
401 357
358void print_help(void) {
359 print_revision(progname, NP_VERSION);
402 360
403void 361 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
404print_help (void) 362 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 363
411 printf ("%s\n", _("This plugin tests the STATUS of an HP printer with a JetDirect card.")); 364 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.")); 365 printf("%s\n", _("Net-snmp must be installed on the computer running the plugin."));
413 366
414 printf ("\n\n"); 367 printf("\n\n");
415 368
416 print_usage (); 369 print_usage();
417 370
418 printf (UT_HELP_VRSN); 371 printf(UT_HELP_VRSN);
419 printf (UT_EXTRA_OPTS); 372 printf(UT_EXTRA_OPTS);
420 373
421 printf (" %s\n", "-C, --community=STRING"); 374 printf(" %s\n", "-C, --community=STRING");
422 printf (" %s", _("The SNMP community name ")); 375 printf(" %s", _("The SNMP community name "));
423 printf (_("(default=%s)"), DEFAULT_COMMUNITY); 376 printf(_("(default=%s)"), DEFAULT_COMMUNITY);
424 printf ("\n"); 377 printf("\n");
425 printf (" %s\n", "-p, --port=STRING"); 378 printf(" %s\n", "-p, --port=STRING");
426 printf (" %s", _("Specify the port to check ")); 379 printf(" %s", _("Specify the port to check "));
427 printf (_("(default=%s)"), DEFAULT_PORT); 380 printf(_("(default=%s)"), DEFAULT_PORT);
428 printf ("\n"); 381 printf("\n");
429 printf (" %s\n", "-D"); 382 printf(" %s\n", "-D");
430 printf (" %s", _("Disable paper check ")); 383 printf(" %s", _("Disable paper check "));
431 384
432 printf (UT_SUPPORT); 385 printf(UT_SUPPORT);
433} 386}
434 387
435 388void print_usage(void) {
436 389 printf("%s\n", _("Usage:"));
437void 390 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} 391}
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..d264b95d 100644
--- a/plugins/check_http.c
+++ b/plugins/check_http.c
@@ -1,38 +1,38 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_http plugin 3 * Monitoring check_http plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-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 the check_http plugin 10 * This file contains the check_http plugin
11* 11 *
12* This plugin tests the HTTP service on the specified host. It can test 12 * This plugin tests the HTTP service on the specified host. It can test
13* normal (http) and secure (https) servers, follow redirects, search for 13 * normal (http) and secure (https) servers, follow redirects, search for
14* strings and regular expressions, check connection times, and report on 14 * strings and regular expressions, check connection times, and report on
15* certificate expiration times. 15 * certificate expiration times.
16* 16 *
17* 17 *
18* This program is free software: you can redistribute it and/or modify 18 * This program is free software: you can redistribute it and/or modify
19* it under the terms of the GNU General Public License as published by 19 * it under the terms of the GNU General Public License as published by
20* the Free Software Foundation, either version 3 of the License, or 20 * the Free Software Foundation, either version 3 of the License, or
21* (at your option) any later version. 21 * (at your option) any later version.
22* 22 *
23* This program is distributed in the hope that it will be useful, 23 * This program is distributed in the hope that it will be useful,
24* but WITHOUT ANY WARRANTY; without even the implied warranty of 24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26* GNU General Public License for more details. 26 * GNU General Public License for more details.
27* 27 *
28* You should have received a copy of the GNU General Public License 28 * You should have received a copy of the GNU General Public License
29* along with this program. If not, see <http://www.gnu.org/licenses/>. 29 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30* 30 *
31* 31 *
32*****************************************************************************/ 32 *****************************************************************************/
33 33
34const char *progname = "check_http"; 34const char *progname = "check_http";
35const char *copyright = "1999-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
@@ -41,7 +41,6 @@ const char *email = "devel@monitoring-plugins.org";
41#include "base64.h" 41#include "base64.h"
42#include "netutils.h" 42#include "netutils.h"
43#include "utils.h" 43#include "utils.h"
44#include "base64.h"
45#include <ctype.h> 44#include <ctype.h>
46 45
47#define STICKY_NONE 0 46#define STICKY_NONE 0
@@ -50,1346 +49,1394 @@ const char *email = "devel@monitoring-plugins.org";
50 49
51#define HTTP_EXPECT "HTTP/1." 50#define HTTP_EXPECT "HTTP/1."
52enum { 51enum {
53 MAX_IPV4_HOSTLENGTH = 255, 52 MAX_IPV4_HOSTLENGTH = 255,
54 HTTP_PORT = 80, 53 HTTP_PORT = 80,
55 HTTPS_PORT = 443, 54 HTTPS_PORT = 443,
56 MAX_PORT = 65535, 55 MAX_PORT = 65535,
57 DEFAULT_MAX_REDIRS = 15 56 DEFAULT_MAX_REDIRS = 15
58}; 57};
59 58
60#ifdef HAVE_SSL 59#ifdef HAVE_SSL
61bool check_cert = false; 60static bool check_cert = false;
62bool continue_after_check_cert = false; 61static bool continue_after_check_cert = false;
63int ssl_version = 0; 62static int ssl_version = 0;
64int days_till_exp_warn, days_till_exp_crit; 63static int days_till_exp_warn, days_till_exp_crit;
65char *randbuff; 64# define my_recv(buf, len) ((use_ssl) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
66X509 *server_cert; 65# define my_send(buf, len) ((use_ssl) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
67# define my_recv(buf, len) ((use_ssl) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
68# define my_send(buf, len) ((use_ssl) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
69#else /* ifndef HAVE_SSL */ 66#else /* ifndef HAVE_SSL */
70# define my_recv(buf, len) read(sd, buf, len) 67# define my_recv(buf, len) read(sd, buf, len)
71# define my_send(buf, len) send(sd, buf, len, 0) 68# define my_send(buf, len) send(sd, buf, len, 0)
72#endif /* HAVE_SSL */ 69#endif /* HAVE_SSL */
73bool no_body = false; 70static bool no_body = false;
74int maximum_age = -1; 71static int maximum_age = -1;
75 72
76enum { 73enum {
77 REGS = 2, 74 REGS = 2,
78 MAX_RE_SIZE = 1024 75 MAX_RE_SIZE = 1024
79}; 76};
80#include "regex.h" 77#include "regex.h"
81regex_t preg; 78static regex_t preg;
82regmatch_t pmatch[REGS]; 79static regmatch_t pmatch[REGS];
83char regexp[MAX_RE_SIZE]; 80static char regexp[MAX_RE_SIZE];
84char errbuf[MAX_INPUT_BUFFER]; 81static char errbuf[MAX_INPUT_BUFFER];
85int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE; 82static int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
86int errcode; 83static int errcode;
87int invert_regex = 0; 84static int invert_regex = 0;
88int state_regex = STATE_CRITICAL; 85static int state_regex = STATE_CRITICAL;
89 86
90struct timeval tv; 87static struct timeval tv;
91struct timeval tv_temp; 88static struct timeval tv_temp;
92 89
93#define HTTP_URL "/" 90#define HTTP_URL "/"
94#define CRLF "\r\n" 91#define CRLF "\r\n"
95 92
96bool specify_port = false; 93static bool specify_port = false;
97int server_port = HTTP_PORT; 94static int server_port = HTTP_PORT;
98int virtual_port = 0; 95static int virtual_port = 0;
99char server_port_text[6] = ""; 96static char server_type[6] = "http";
100char server_type[6] = "http"; 97static char *server_address;
101char *server_address; 98static char *host_name;
102char *host_name; 99static int host_name_length;
103int host_name_length; 100static char *server_url;
104char *server_url; 101static char *user_agent;
105char *user_agent; 102static int server_url_length;
106int server_url_length; 103static int server_expect_yn = 0;
107int server_expect_yn = 0; 104static char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
108char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT; 105static char header_expect[MAX_INPUT_BUFFER] = "";
109char header_expect[MAX_INPUT_BUFFER] = ""; 106static char string_expect[MAX_INPUT_BUFFER] = "";
110char string_expect[MAX_INPUT_BUFFER] = ""; 107static char *warning_thresholds = NULL;
111char *warning_thresholds = NULL; 108static char *critical_thresholds = NULL;
112char *critical_thresholds = NULL; 109static thresholds *thlds;
113thresholds *thlds; 110static char user_auth[MAX_INPUT_BUFFER] = "";
114char user_auth[MAX_INPUT_BUFFER] = ""; 111static char proxy_auth[MAX_INPUT_BUFFER] = "";
115char proxy_auth[MAX_INPUT_BUFFER] = ""; 112static bool display_html = false;
116bool display_html = false; 113static char **http_opt_headers;
117char **http_opt_headers; 114static int http_opt_headers_count = 0;
118int http_opt_headers_count = 0; 115static int onredirect = STATE_OK;
119int onredirect = STATE_OK; 116static int followsticky = STICKY_NONE;
120int followsticky = STICKY_NONE; 117static bool use_ssl = false;
121bool use_ssl = false; 118static bool use_sni = false;
122bool use_sni = false; 119static bool verbose = false;
123bool verbose = false; 120static bool show_extended_perfdata = false;
124bool show_extended_perfdata = false; 121static bool show_body = false;
125bool show_body = false; 122static int sd;
126int sd; 123static int min_page_len = 0;
127int min_page_len = 0; 124static int max_page_len = 0;
128int max_page_len = 0; 125static int redir_depth = 0;
129int redir_depth = 0; 126static int max_depth = DEFAULT_MAX_REDIRS;
130int max_depth = DEFAULT_MAX_REDIRS; 127static char *http_method;
131char *http_method; 128static char *http_method_proxy;
132char *http_method_proxy; 129static char *http_post_data;
133char *http_post_data; 130static char *http_content_type;
134char *http_content_type; 131static char buffer[MAX_INPUT_BUFFER];
135char buffer[MAX_INPUT_BUFFER]; 132static char *client_cert = NULL;
136char *client_cert = NULL; 133static char *client_privkey = NULL;
137char *client_privkey = NULL;
138 134
139// Forward function declarations 135// Forward function declarations
140bool process_arguments (int, char **); 136static bool process_arguments(int /*argc*/, char ** /*argv*/);
141int check_http (void); 137static int check_http(void);
142void redir (char *pos, char *status_line); 138static void redir(char *pos, char *status_line);
143bool server_type_check(const char *type); 139static bool server_type_check(const char *type);
144int server_port_check(int ssl_flag); 140static int server_port_check(int ssl_flag);
145char *perfd_time (double microsec); 141static char *perfd_time(double elapsed_time);
146char *perfd_time_connect (double microsec); 142static char *perfd_time_connect(double elapsed_time_connect);
147char *perfd_time_ssl (double microsec); 143static char *perfd_time_ssl(double elapsed_time_ssl);
148char *perfd_time_firstbyte (double microsec); 144static char *perfd_time_firstbyte(double elapsed_time_firstbyte);
149char *perfd_time_headers (double microsec); 145static char *perfd_time_headers(double elapsed_time_headers);
150char *perfd_time_transfer (double microsec); 146static char *perfd_time_transfer(double elapsed_time_transfer);
151char *perfd_size (int page_len); 147static char *perfd_size(int page_len);
152void print_help (void); 148void print_help(void);
153void print_usage (void); 149void print_usage(void);
154char *unchunk_content(const char *content); 150static char *unchunk_content(const char *content);
155 151
156int 152int main(int argc, char **argv) {
157main (int argc, char **argv) 153 int result = STATE_UNKNOWN;
158{ 154
159 int result = STATE_UNKNOWN; 155 setlocale(LC_ALL, "");
160 156 bindtextdomain(PACKAGE, LOCALEDIR);
161 setlocale (LC_ALL, ""); 157 textdomain(PACKAGE);
162 bindtextdomain (PACKAGE, LOCALEDIR); 158
163 textdomain (PACKAGE); 159 /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */
164 160 server_url = strdup(HTTP_URL);
165 /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */ 161 server_url_length = strlen(server_url);
166 server_url = strdup(HTTP_URL); 162 xasprintf(&user_agent, "User-Agent: check_http/v%s (monitoring-plugins %s)", NP_VERSION,
167 server_url_length = strlen(server_url); 163 VERSION);
168 xasprintf (&user_agent, "User-Agent: check_http/v%s (monitoring-plugins %s)", 164
169 NP_VERSION, VERSION); 165 /* Parse extra opts if any */
170 166 argv = np_extra_opts(&argc, argv, progname);
171 /* Parse extra opts if any */ 167
172 argv=np_extra_opts (&argc, argv, progname); 168 if (!process_arguments(argc, argv)) {
173 169 usage4(_("Could not parse arguments"));
174 if (process_arguments (argc, argv) == false) 170 }
175 usage4 (_("Could not parse arguments")); 171
176 172 if (display_html) {
177 if (display_html == true) 173 printf("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", use_ssl ? "https" : "http",
178 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", 174 host_name ? host_name : server_address, server_port, server_url);
179 use_ssl ? "https" : "http", host_name ? host_name : server_address, 175 }
180 server_port, server_url); 176
181 177 /* initialize alarm signal handling, set socket timeout, start timer */
182 /* initialize alarm signal handling, set socket timeout, start timer */ 178 (void)signal(SIGALRM, socket_timeout_alarm_handler);
183 (void) signal (SIGALRM, socket_timeout_alarm_handler); 179 (void)alarm(socket_timeout);
184 (void) alarm (socket_timeout); 180 gettimeofday(&tv, NULL);
185 gettimeofday (&tv, NULL); 181
186 182 result = check_http();
187 result = check_http (); 183 return result;
188 return result;
189} 184}
190 185
191/* check whether a file exists */ 186/* check whether a file exists */
192void 187void test_file(char *path) {
193test_file (char *path) 188 if (access(path, R_OK) == 0) {
194{ 189 return;
195 if (access(path, R_OK) == 0) 190 }
196 return; 191 usage2(_("file does not exist or is not readable"), path);
197 usage2 (_("file does not exist or is not readable"), path);
198} 192}
199 193
200/* 194/*
201 * process command-line arguments 195 * process command-line arguments
202 * returns true on success, false otherwise 196 * returns true on success, false otherwise
203 */ 197 */
204bool process_arguments (int argc, char **argv) 198bool process_arguments(int argc, char **argv) {
205{ 199 int c = 1;
206 int c = 1; 200 char *p;
207 char *p; 201 char *temp;
208 char *temp; 202
209 203 enum {
210 enum { 204 INVERT_REGEX = CHAR_MAX + 1,
211 INVERT_REGEX = CHAR_MAX + 1, 205 SNI_OPTION,
212 SNI_OPTION, 206 MAX_REDIRS_OPTION,
213 MAX_REDIRS_OPTION, 207 CONTINUE_AFTER_CHECK_CERT,
214 CONTINUE_AFTER_CHECK_CERT, 208 STATE_REGEX
215 STATE_REGEX 209 };
216 }; 210
217 211 int option = 0;
218 int option = 0; 212 static struct option longopts[] = {
219 static struct option longopts[] = { 213 STD_LONG_OPTS,
220 STD_LONG_OPTS, 214 {"link", no_argument, 0, 'L'},
221 {"link", no_argument, 0, 'L'}, 215 {"nohtml", no_argument, 0, 'n'},
222 {"nohtml", no_argument, 0, 'n'}, 216 {"ssl", optional_argument, 0, 'S'},
223 {"ssl", optional_argument, 0, 'S'}, 217 {"sni", no_argument, 0, SNI_OPTION},
224 {"sni", no_argument, 0, SNI_OPTION}, 218 {"post", required_argument, 0, 'P'},
225 {"post", required_argument, 0, 'P'}, 219 {"method", required_argument, 0, 'j'},
226 {"method", required_argument, 0, 'j'}, 220 {"IP-address", required_argument, 0, 'I'},
227 {"IP-address", required_argument, 0, 'I'}, 221 {"url", required_argument, 0, 'u'},
228 {"url", required_argument, 0, 'u'}, 222 {"port", required_argument, 0, 'p'},
229 {"port", required_argument, 0, 'p'}, 223 {"authorization", required_argument, 0, 'a'},
230 {"authorization", required_argument, 0, 'a'}, 224 {"proxy-authorization", required_argument, 0, 'b'},
231 {"proxy-authorization", required_argument, 0, 'b'}, 225 {"header-string", required_argument, 0, 'd'},
232 {"header-string", required_argument, 0, 'd'}, 226 {"string", required_argument, 0, 's'},
233 {"string", required_argument, 0, 's'}, 227 {"expect", required_argument, 0, 'e'},
234 {"expect", required_argument, 0, 'e'}, 228 {"regex", required_argument, 0, 'r'},
235 {"regex", required_argument, 0, 'r'}, 229 {"ereg", required_argument, 0, 'r'},
236 {"ereg", required_argument, 0, 'r'}, 230 {"eregi", required_argument, 0, 'R'},
237 {"eregi", required_argument, 0, 'R'}, 231 {"linespan", no_argument, 0, 'l'},
238 {"linespan", no_argument, 0, 'l'}, 232 {"onredirect", required_argument, 0, 'f'},
239 {"onredirect", required_argument, 0, 'f'}, 233 {"certificate", required_argument, 0, 'C'},
240 {"certificate", required_argument, 0, 'C'}, 234 {"client-cert", required_argument, 0, 'J'},
241 {"client-cert", required_argument, 0, 'J'}, 235 {"private-key", required_argument, 0, 'K'},
242 {"private-key", required_argument, 0, 'K'}, 236 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT},
243 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT}, 237 {"useragent", required_argument, 0, 'A'},
244 {"useragent", required_argument, 0, 'A'}, 238 {"header", required_argument, 0, 'k'},
245 {"header", required_argument, 0, 'k'}, 239 {"no-body", no_argument, 0, 'N'},
246 {"no-body", no_argument, 0, 'N'}, 240 {"max-age", required_argument, 0, 'M'},
247 {"max-age", required_argument, 0, 'M'}, 241 {"content-type", required_argument, 0, 'T'},
248 {"content-type", required_argument, 0, 'T'}, 242 {"pagesize", required_argument, 0, 'm'},
249 {"pagesize", required_argument, 0, 'm'}, 243 {"invert-regex", no_argument, NULL, INVERT_REGEX},
250 {"invert-regex", no_argument, NULL, INVERT_REGEX}, 244 {"state-regex", required_argument, 0, STATE_REGEX},
251 {"state-regex", required_argument, 0, STATE_REGEX}, 245 {"use-ipv4", no_argument, 0, '4'},
252 {"use-ipv4", no_argument, 0, '4'}, 246 {"use-ipv6", no_argument, 0, '6'},
253 {"use-ipv6", no_argument, 0, '6'}, 247 {"extended-perfdata", no_argument, 0, 'E'},
254 {"extended-perfdata", no_argument, 0, 'E'}, 248 {"show-body", no_argument, 0, 'B'},
255 {"show-body", no_argument, 0, 'B'}, 249 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION},
256 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION}, 250 {0, 0, 0, 0}};
257 {0, 0, 0, 0} 251
258 }; 252 if (argc < 2) {
259 253 return false;
260 if (argc < 2) 254 }
261 return false; 255
262 256 for (c = 1; c < argc; c++) {
263 for (c = 1; c < argc; c++) { 257 if (strcmp("-to", argv[c]) == 0) {
264 if (strcmp ("-to", argv[c]) == 0) 258 strcpy(argv[c], "-t");
265 strcpy (argv[c], "-t"); 259 }
266 if (strcmp ("-hn", argv[c]) == 0) 260 if (strcmp("-hn", argv[c]) == 0) {
267 strcpy (argv[c], "-H"); 261 strcpy(argv[c], "-H");
268 if (strcmp ("-wt", argv[c]) == 0) 262 }
269 strcpy (argv[c], "-w"); 263 if (strcmp("-wt", argv[c]) == 0) {
270 if (strcmp ("-ct", argv[c]) == 0) 264 strcpy(argv[c], "-w");
271 strcpy (argv[c], "-c"); 265 }
272 if (strcmp ("-nohtml", argv[c]) == 0) 266 if (strcmp("-ct", argv[c]) == 0) {
273 strcpy (argv[c], "-n"); 267 strcpy(argv[c], "-c");
274 } 268 }
275 269 if (strcmp("-nohtml", argv[c]) == 0) {
276 while (1) { 270 strcpy(argv[c], "-n");
277 c = getopt_long (argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:d:e:p:s:R:r:u:f:C:J:K:nlLS::m:M:NEB", longopts, &option); 271 }
278 if (c == -1 || c == EOF) 272 }
279 break; 273
280 274 while (1) {
281 switch (c) { 275 c = getopt_long(argc, argv,
282 case '?': /* usage */ 276 "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:d:e:p:s:R:r:u:f:C:J:K:nlLS::m:M:NEB",
283 usage5 (); 277 longopts, &option);
284 break; 278 if (c == -1 || c == EOF) {
285 case 'h': /* help */ 279 break;
286 print_help (); 280 }
287 exit (STATE_UNKNOWN); 281
288 break; 282 switch (c) {
289 case 'V': /* version */ 283 case '?': /* usage */
290 print_revision (progname, NP_VERSION); 284 usage5();
291 exit (STATE_UNKNOWN); 285 break;
292 break; 286 case 'h': /* help */
293 case 't': /* timeout period */ 287 print_help();
294 if (!is_intnonneg (optarg)) 288 exit(STATE_UNKNOWN);
295 usage2 (_("Timeout interval must be a positive integer"), optarg); 289 break;
296 else 290 case 'V': /* version */
297 socket_timeout = atoi (optarg); 291 print_revision(progname, NP_VERSION);
298 break; 292 exit(STATE_UNKNOWN);
299 case 'c': /* critical time threshold */ 293 break;
300 critical_thresholds = optarg; 294 case 't': /* timeout period */
301 break; 295 if (!is_intnonneg(optarg)) {
302 case 'w': /* warning time threshold */ 296 usage2(_("Timeout interval must be a positive integer"), optarg);
303 warning_thresholds = optarg; 297 } else {
304 break; 298 socket_timeout = atoi(optarg);
305 case 'A': /* User Agent String */ 299 }
306 xasprintf (&user_agent, "User-Agent: %s", optarg); 300 break;
307 break; 301 case 'c': /* critical time threshold */
308 case 'k': /* Additional headers */ 302 critical_thresholds = optarg;
309 if (http_opt_headers_count == 0) 303 break;
310 http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count)); 304 case 'w': /* warning time threshold */
311 else 305 warning_thresholds = optarg;
312 http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count)); 306 break;
313 http_opt_headers[http_opt_headers_count - 1] = optarg; 307 case 'A': /* User Agent String */
314 /* xasprintf (&http_opt_headers, "%s", optarg); */ 308 xasprintf(&user_agent, "User-Agent: %s", optarg);
315 break; 309 break;
316 case 'L': /* show html link */ 310 case 'k': /* Additional headers */
317 display_html = true; 311 if (http_opt_headers_count == 0) {
318 break; 312 http_opt_headers = malloc(sizeof(char *) * (++http_opt_headers_count));
319 case 'n': /* do not show html link */ 313 } else {
320 display_html = false; 314 http_opt_headers =
321 break; 315 realloc(http_opt_headers, sizeof(char *) * (++http_opt_headers_count));
322 case 'C': /* Check SSL cert validity */ 316 }
317 http_opt_headers[http_opt_headers_count - 1] = optarg;
318 /* xasprintf (&http_opt_headers, "%s", optarg); */
319 break;
320 case 'L': /* show html link */
321 display_html = true;
322 break;
323 case 'n': /* do not show html link */
324 display_html = false;
325 break;
326 case 'C': /* Check SSL cert validity */
323#ifdef HAVE_SSL 327#ifdef HAVE_SSL
324 if ((temp=strchr(optarg,','))!=NULL) { 328 if ((temp = strchr(optarg, ',')) != NULL) {
325 *temp='\0'; 329 *temp = '\0';
326 if (!is_intnonneg (optarg)) 330 if (!is_intnonneg(optarg)) {
327 usage2 (_("Invalid certificate expiration period"), optarg); 331 usage2(_("Invalid certificate expiration period"), optarg);
328 days_till_exp_warn = atoi(optarg); 332 }
329 *temp=','; 333 days_till_exp_warn = atoi(optarg);
330 temp++; 334 *temp = ',';
331 if (!is_intnonneg (temp)) 335 temp++;
332 usage2 (_("Invalid certificate expiration period"), temp); 336 if (!is_intnonneg(temp)) {
333 days_till_exp_crit = atoi (temp); 337 usage2(_("Invalid certificate expiration period"), temp);
334 } 338 }
335 else { 339 days_till_exp_crit = atoi(temp);
336 days_till_exp_crit=0; 340 } else {
337 if (!is_intnonneg (optarg)) 341 days_till_exp_crit = 0;
338 usage2 (_("Invalid certificate expiration period"), optarg); 342 if (!is_intnonneg(optarg)) {
339 days_till_exp_warn = atoi (optarg); 343 usage2(_("Invalid certificate expiration period"), optarg);
340 } 344 }
341 check_cert = true; 345 days_till_exp_warn = atoi(optarg);
342 goto enable_ssl; 346 }
347 check_cert = true;
348 goto enable_ssl;
343#endif 349#endif
344 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */ 350 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
345#ifdef HAVE_SSL 351#ifdef HAVE_SSL
346 continue_after_check_cert = true; 352 continue_after_check_cert = true;
347 break; 353 break;
348#endif 354#endif
349 case 'J': /* use client certificate */ 355 case 'J': /* use client certificate */
350#ifdef HAVE_SSL 356#ifdef HAVE_SSL
351 test_file(optarg); 357 test_file(optarg);
352 client_cert = optarg; 358 client_cert = optarg;
353 goto enable_ssl; 359 goto enable_ssl;
354#endif 360#endif
355 case 'K': /* use client private key */ 361 case 'K': /* use client private key */
356#ifdef HAVE_SSL 362#ifdef HAVE_SSL
357 test_file(optarg); 363 test_file(optarg);
358 client_privkey = optarg; 364 client_privkey = optarg;
359 goto enable_ssl; 365 goto enable_ssl;
360#endif 366#endif
361 case 'S': /* use SSL */ 367 case 'S': /* use SSL */
362#ifdef HAVE_SSL 368#ifdef HAVE_SSL
363 enable_ssl: 369 enable_ssl:
364 /* ssl_version initialized to 0 as a default. Only set if it's non-zero. This helps when we include multiple 370 /* ssl_version initialized to 0 as a default. Only set if it's non-zero. This helps
365 parameters, like -S and -C combinations */ 371 when we include multiple parameters, like -S and -C combinations */
366 use_ssl = true; 372 use_ssl = true;
367 if (c=='S' && optarg != NULL) { 373 if (c == 'S' && optarg != NULL) {
368 int got_plus = strchr(optarg, '+') != NULL; 374 int got_plus = strchr(optarg, '+') != NULL;
369 375
370 if (!strncmp (optarg, "1.2", 3)) 376 if (!strncmp(optarg, "1.2", 3)) {
371 ssl_version = got_plus ? MP_TLSv1_2_OR_NEWER : MP_TLSv1_2; 377 ssl_version = got_plus ? MP_TLSv1_2_OR_NEWER : MP_TLSv1_2;
372 else if (!strncmp (optarg, "1.1", 3)) 378 } else if (!strncmp(optarg, "1.1", 3)) {
373 ssl_version = got_plus ? MP_TLSv1_1_OR_NEWER : MP_TLSv1_1; 379 ssl_version = got_plus ? MP_TLSv1_1_OR_NEWER : MP_TLSv1_1;
374 else if (optarg[0] == '1') 380 } else if (optarg[0] == '1') {
375 ssl_version = got_plus ? MP_TLSv1_OR_NEWER : MP_TLSv1; 381 ssl_version = got_plus ? MP_TLSv1_OR_NEWER : MP_TLSv1;
376 else if (optarg[0] == '3') 382 } else if (optarg[0] == '3') {
377 ssl_version = got_plus ? MP_SSLv3_OR_NEWER : MP_SSLv3; 383 ssl_version = got_plus ? MP_SSLv3_OR_NEWER : MP_SSLv3;
378 else if (optarg[0] == '2') 384 } else if (optarg[0] == '2') {
379 ssl_version = got_plus ? MP_SSLv2_OR_NEWER : MP_SSLv2; 385 ssl_version = got_plus ? MP_SSLv2_OR_NEWER : MP_SSLv2;
380 else 386 } else {
381 usage4 (_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2 (with optional '+' suffix)")); 387 usage4(_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2 (with "
382 } 388 "optional '+' suffix)"));
383 if (specify_port == false) 389 }
384 server_port = HTTPS_PORT; 390 }
391 if (!specify_port) {
392 server_port = HTTPS_PORT;
393 }
385#else 394#else
386 /* -C -J and -K fall through to here without SSL */ 395 /* -C -J and -K fall through to here without SSL */
387 usage4 (_("Invalid option - SSL is not available")); 396 usage4(_("Invalid option - SSL is not available"));
388#endif 397#endif
389 break; 398 break;
390 case SNI_OPTION: 399 case SNI_OPTION:
391 use_sni = true; 400 use_sni = true;
392 break; 401 break;
393 case MAX_REDIRS_OPTION: 402 case MAX_REDIRS_OPTION:
394 if (!is_intnonneg (optarg)) 403 if (!is_intnonneg(optarg)) {
395 usage2 (_("Invalid max_redirs count"), optarg); 404 usage2(_("Invalid max_redirs count"), optarg);
396 else { 405 } else {
397 max_depth = atoi (optarg); 406 max_depth = atoi(optarg);
398 } 407 }
399 break; 408 break;
400 case 'f': /* onredirect */ 409 case 'f': /* onredirect */
401 if (!strcmp (optarg, "stickyport")) 410 if (!strcmp(optarg, "stickyport")) {
402 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST|STICKY_PORT; 411 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST | STICKY_PORT;
403 else if (!strcmp (optarg, "sticky")) 412 } else if (!strcmp(optarg, "sticky")) {
404 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST; 413 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST;
405 else if (!strcmp (optarg, "follow")) 414 } else if (!strcmp(optarg, "follow")) {
406 onredirect = STATE_DEPENDENT, followsticky = STICKY_NONE; 415 onredirect = STATE_DEPENDENT, followsticky = STICKY_NONE;
407 else if (!strcmp (optarg, "unknown")) 416 } else if (!strcmp(optarg, "unknown")) {
408 onredirect = STATE_UNKNOWN; 417 onredirect = STATE_UNKNOWN;
409 else if (!strcmp (optarg, "ok")) 418 } else if (!strcmp(optarg, "ok")) {
410 onredirect = STATE_OK; 419 onredirect = STATE_OK;
411 else if (!strcmp (optarg, "warning")) 420 } else if (!strcmp(optarg, "warning")) {
412 onredirect = STATE_WARNING; 421 onredirect = STATE_WARNING;
413 else if (!strcmp (optarg, "critical")) 422 } else if (!strcmp(optarg, "critical")) {
414 onredirect = STATE_CRITICAL; 423 onredirect = STATE_CRITICAL;
415 else usage2 (_("Invalid onredirect option"), optarg); 424 } else {
416 if (verbose) 425 usage2(_("Invalid onredirect option"), optarg);
417 printf(_("option f:%d \n"), onredirect); 426 }
418 break; 427 if (verbose) {
419 /* Note: H, I, and u must be malloc'd or will fail on redirects */ 428 printf(_("option f:%d \n"), onredirect);
420 case 'H': /* Host Name (virtual host) */ 429 }
421 host_name = strdup (optarg); 430 break;
422 if (host_name[0] == '[') { 431 /* Note: H, I, and u must be malloc'd or will fail on redirects */
423 if ((p = strstr (host_name, "]:")) != NULL) { /* [IPv6]:port */ 432 case 'H': /* Host Name (virtual host) */
424 virtual_port = atoi (p + 2); 433 host_name = strdup(optarg);
425 /* cut off the port */ 434 if (host_name[0] == '[') {
426 host_name_length = strlen (host_name) - strlen (p) - 1; 435 if ((p = strstr(host_name, "]:")) != NULL) { /* [IPv6]:port */
427 free (host_name); 436 virtual_port = atoi(p + 2);
428 host_name = strndup (optarg, host_name_length); 437 /* cut off the port */
429 if (specify_port == false) 438 host_name_length = strlen(host_name) - strlen(p) - 1;
430 server_port = virtual_port; 439 free(host_name);
431 } 440 host_name = strndup(optarg, host_name_length);
432 } else if ((p = strchr (host_name, ':')) != NULL 441 if (!specify_port) {
433 && strchr (++p, ':') == NULL) { /* IPv4:port or host:port */ 442 server_port = virtual_port;
434 virtual_port = atoi (p); 443 }
435 /* cut off the port */ 444 }
436 host_name_length = strlen (host_name) - strlen (p) - 1; 445 } else if ((p = strchr(host_name, ':')) != NULL &&
437 free (host_name); 446 strchr(++p, ':') == NULL) { /* IPv4:port or host:port */
438 host_name = strndup (optarg, host_name_length); 447 virtual_port = atoi(p);
439 if (specify_port == false) 448 /* cut off the port */
440 server_port = virtual_port; 449 host_name_length = strlen(host_name) - strlen(p) - 1;
441 } 450 free(host_name);
442 break; 451 host_name = strndup(optarg, host_name_length);
443 case 'I': /* Server IP-address */ 452 if (!specify_port) {
444 server_address = strdup (optarg); 453 server_port = virtual_port;
445 break; 454 }
446 case 'u': /* URL path */ 455 }
447 server_url = strdup (optarg); 456 break;
448 server_url_length = strlen (server_url); 457 case 'I': /* Server IP-address */
449 break; 458 server_address = strdup(optarg);
450 case 'p': /* Server port */ 459 break;
451 if (!is_intnonneg (optarg)) 460 case 'u': /* URL path */
452 usage2 (_("Invalid port number"), optarg); 461 server_url = strdup(optarg);
453 else { 462 server_url_length = strlen(server_url);
454 server_port = atoi (optarg); 463 break;
455 specify_port = true; 464 case 'p': /* Server port */
456 } 465 if (!is_intnonneg(optarg)) {
457 break; 466 usage2(_("Invalid port number"), optarg);
458 case 'a': /* authorization info */ 467 } else {
459 strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1); 468 server_port = atoi(optarg);
460 user_auth[MAX_INPUT_BUFFER - 1] = 0; 469 specify_port = true;
461 break; 470 }
462 case 'b': /* proxy-authorization info */ 471 break;
463 strncpy (proxy_auth, optarg, MAX_INPUT_BUFFER - 1); 472 case 'a': /* authorization info */
464 proxy_auth[MAX_INPUT_BUFFER - 1] = 0; 473 strncpy(user_auth, optarg, MAX_INPUT_BUFFER - 1);
465 break; 474 user_auth[MAX_INPUT_BUFFER - 1] = 0;
466 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */ 475 break;
467 if (! http_post_data) 476 case 'b': /* proxy-authorization info */
468 http_post_data = strdup (optarg); 477 strncpy(proxy_auth, optarg, MAX_INPUT_BUFFER - 1);
469 if (! http_method) 478 proxy_auth[MAX_INPUT_BUFFER - 1] = 0;
470 http_method = strdup("POST"); 479 break;
471 break; 480 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
472 case 'j': /* Set HTTP method */ 481 if (!http_post_data) {
473 if (http_method) 482 http_post_data = strdup(optarg);
474 free(http_method); 483 }
475 http_method = strdup (optarg); 484 if (!http_method) {
476 char *tmp; 485 http_method = strdup("POST");
477 if ((tmp = strstr(http_method, ":")) != NULL) { 486 }
478 tmp[0] = '\0'; // set the ":" in the middle to 0 487 break;
479 http_method_proxy = ++tmp; // this points to the second part 488 case 'j': /* Set HTTP method */
480 } 489 if (http_method) {
481 break; 490 free(http_method);
482 case 'd': /* string or substring */ 491 }
483 strncpy (header_expect, optarg, MAX_INPUT_BUFFER - 1); 492 http_method = strdup(optarg);
484 header_expect[MAX_INPUT_BUFFER - 1] = 0; 493 char *tmp;
485 break; 494 if ((tmp = strstr(http_method, ":")) != NULL) {
486 case 's': /* string or substring */ 495 tmp[0] = '\0'; // set the ":" in the middle to 0
487 strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1); 496 http_method_proxy = ++tmp; // this points to the second part
488 string_expect[MAX_INPUT_BUFFER - 1] = 0; 497 }
489 break; 498 break;
490 case 'e': /* string or substring */ 499 case 'd': /* string or substring */
491 strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1); 500 strncpy(header_expect, optarg, MAX_INPUT_BUFFER - 1);
492 server_expect[MAX_INPUT_BUFFER - 1] = 0; 501 header_expect[MAX_INPUT_BUFFER - 1] = 0;
493 server_expect_yn = 1; 502 break;
494 break; 503 case 's': /* string or substring */
495 case 'T': /* Content-type */ 504 strncpy(string_expect, optarg, MAX_INPUT_BUFFER - 1);
496 xasprintf (&http_content_type, "%s", optarg); 505 string_expect[MAX_INPUT_BUFFER - 1] = 0;
497 break; 506 break;
498 case 'l': /* linespan */ 507 case 'e': /* string or substring */
499 cflags &= ~REG_NEWLINE; 508 strncpy(server_expect, optarg, MAX_INPUT_BUFFER - 1);
500 break; 509 server_expect[MAX_INPUT_BUFFER - 1] = 0;
501 case 'R': /* regex */ 510 server_expect_yn = 1;
502 cflags |= REG_ICASE; 511 break;
512 case 'T': /* Content-type */
513 xasprintf(&http_content_type, "%s", optarg);
514 break;
515 case 'l': /* linespan */
516 cflags &= ~REG_NEWLINE;
517 break;
518 case 'R': /* regex */
519 cflags |= REG_ICASE;
503 // fall through 520 // fall through
504 case 'r': /* regex */ 521 case 'r': /* regex */
505 strncpy (regexp, optarg, MAX_RE_SIZE - 1); 522 strncpy(regexp, optarg, MAX_RE_SIZE - 1);
506 regexp[MAX_RE_SIZE - 1] = 0; 523 regexp[MAX_RE_SIZE - 1] = 0;
507 errcode = regcomp (&preg, regexp, cflags); 524 errcode = regcomp(&preg, regexp, cflags);
508 if (errcode != 0) { 525 if (errcode != 0) {
509 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 526 (void)regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
510 printf (_("Could Not Compile Regular Expression: %s"), errbuf); 527 printf(_("Could Not Compile Regular Expression: %s"), errbuf);
511 return false; 528 return false;
512 } 529 }
513 break; 530 break;
514 case INVERT_REGEX: 531 case INVERT_REGEX:
515 invert_regex = 1; 532 invert_regex = 1;
516 break; 533 break;
517 case STATE_REGEX: 534 case STATE_REGEX:
518 if (!strcmp (optarg, "critical")) 535 if (!strcmp(optarg, "critical")) {
519 state_regex = STATE_CRITICAL; 536 state_regex = STATE_CRITICAL;
520 else if (!strcmp (optarg, "warning")) 537 } else if (!strcmp(optarg, "warning")) {
521 state_regex = STATE_WARNING; 538 state_regex = STATE_WARNING;
522 else usage2 (_("Invalid state-regex option"), optarg); 539 } else {
523 break; 540 usage2(_("Invalid state-regex option"), optarg);
524 case '4': 541 }
525 address_family = AF_INET; 542 break;
526 break; 543 case '4':
527 case '6': 544 address_family = AF_INET;
545 break;
546 case '6':
528#ifdef USE_IPV6 547#ifdef USE_IPV6
529 address_family = AF_INET6; 548 address_family = AF_INET6;
530#else 549#else
531 usage4 (_("IPv6 support not available")); 550 usage4(_("IPv6 support not available"));
532#endif 551#endif
533 break; 552 break;
534 case 'v': /* verbose */ 553 case 'v': /* verbose */
535 verbose = true; 554 verbose = true;
536 break; 555 break;
537 case 'm': /* min_page_length */ 556 case 'm': /* min_page_length */
538 { 557 {
539 char *tmp; 558 char *tmp;
540 if (strchr(optarg, ':') != (char *)NULL) { 559 if (strchr(optarg, ':') != (char *)NULL) {
541 /* range, so get two values, min:max */ 560 /* range, so get two values, min:max */
542 tmp = strtok(optarg, ":"); 561 tmp = strtok(optarg, ":");
543 if (tmp == NULL) { 562 if (tmp == NULL) {
544 printf("Bad format: try \"-m min:max\"\n"); 563 printf("Bad format: try \"-m min:max\"\n");
545 exit (STATE_WARNING); 564 exit(STATE_WARNING);
546 } else 565 } else {
547 min_page_len = atoi(tmp); 566 min_page_len = atoi(tmp);
548 567 }
549 tmp = strtok(NULL, ":"); 568
550 if (tmp == NULL) { 569 tmp = strtok(NULL, ":");
551 printf("Bad format: try \"-m min:max\"\n"); 570 if (tmp == NULL) {
552 exit (STATE_WARNING); 571 printf("Bad format: try \"-m min:max\"\n");
553 } else 572 exit(STATE_WARNING);
554 max_page_len = atoi(tmp); 573 } else {
555 } else 574 max_page_len = atoi(tmp);
556 min_page_len = atoi (optarg); 575 }
557 break; 576 } else {
558 } 577 min_page_len = atoi(optarg);
559 case 'N': /* no-body */ 578 }
560 no_body = true; 579 break;
561 break; 580 }
562 case 'M': /* max-age */ 581 case 'N': /* no-body */
563 { 582 no_body = true;
564 int L = strlen(optarg); 583 break;
565 if (L && optarg[L-1] == 'm') 584 case 'M': /* max-age */
566 maximum_age = atoi (optarg) * 60; 585 {
567 else if (L && optarg[L-1] == 'h') 586 int L = strlen(optarg);
568 maximum_age = atoi (optarg) * 60 * 60; 587 if (L && optarg[L - 1] == 'm') {
569 else if (L && optarg[L-1] == 'd') 588 maximum_age = atoi(optarg) * 60;
570 maximum_age = atoi (optarg) * 60 * 60 * 24; 589 } else if (L && optarg[L - 1] == 'h') {
571 else if (L && (optarg[L-1] == 's' || 590 maximum_age = atoi(optarg) * 60 * 60;
572 isdigit (optarg[L-1]))) 591 } else if (L && optarg[L - 1] == 'd') {
573 maximum_age = atoi (optarg); 592 maximum_age = atoi(optarg) * 60 * 60 * 24;
574 else { 593 } else if (L && (optarg[L - 1] == 's' || isdigit(optarg[L - 1]))) {
575 fprintf (stderr, "unparsable max-age: %s\n", optarg); 594 maximum_age = atoi(optarg);
576 exit (STATE_WARNING); 595 } else {
577 } 596 fprintf(stderr, "unparsable max-age: %s\n", optarg);
578 } 597 exit(STATE_WARNING);
579 break; 598 }
580 case 'E': /* show extended perfdata */ 599 } break;
581 show_extended_perfdata = true; 600 case 'E': /* show extended perfdata */
582 break; 601 show_extended_perfdata = true;
583 case 'B': /* print body content after status line */ 602 break;
584 show_body = true; 603 case 'B': /* print body content after status line */
585 break; 604 show_body = true;
586 } 605 break;
587 } 606 }
588 607 }
589 c = optind; 608
590 609 c = optind;
591 if (server_address == NULL && c < argc) 610
592 server_address = strdup (argv[c++]); 611 if (server_address == NULL && c < argc) {
593 612 server_address = strdup(argv[c++]);
594 if (host_name == NULL && c < argc) 613 }
595 host_name = strdup (argv[c++]);
596
597 if (server_address == NULL) {
598 if (host_name == NULL)
599 usage4 (_("You must specify a server address or host name"));
600 else
601 server_address = strdup (host_name);
602 }
603
604 set_thresholds(&thlds, warning_thresholds, critical_thresholds);
605
606 if (critical_thresholds && thlds->critical->end>(double)socket_timeout)
607 socket_timeout = (int)thlds->critical->end + 1;
608
609 if (http_method == NULL)
610 http_method = strdup ("GET");
611
612 if (http_method_proxy == NULL)
613 http_method_proxy = strdup ("GET");
614
615 if (client_cert && !client_privkey)
616 usage4 (_("If you use a client certificate you must also specify a private key file"));
617
618 if (virtual_port == 0)
619 virtual_port = server_port;
620
621 return true;
622}
623 614
615 if (host_name == NULL && c < argc) {
616 host_name = strdup(argv[c++]);
617 }
618
619 if (server_address == NULL) {
620 if (host_name == NULL) {
621 usage4(_("You must specify a server address or host name"));
622 } else {
623 server_address = strdup(host_name);
624 }
625 }
624 626
627 set_thresholds(&thlds, warning_thresholds, critical_thresholds);
628
629 if (critical_thresholds && thlds->critical->end > (double)socket_timeout) {
630 socket_timeout = (int)thlds->critical->end + 1;
631 }
632
633 if (http_method == NULL) {
634 http_method = strdup("GET");
635 }
636
637 if (http_method_proxy == NULL) {
638 http_method_proxy = strdup("GET");
639 }
640
641 if (client_cert && !client_privkey) {
642 usage4(_("If you use a client certificate you must also specify a private key file"));
643 }
644
645 if (virtual_port == 0) {
646 virtual_port = server_port;
647 }
648
649 return true;
650}
625 651
626/* Returns 1 if we're done processing the document body; 0 to keep going */ 652/* Returns 1 if we're done processing the document body; 0 to keep going */
627static int 653static int document_headers_done(char *full_page) {
628document_headers_done (char *full_page) 654 const char *body;
629{
630 const char *body;
631 655
632 for (body = full_page; *body; body++) { 656 for (body = full_page; *body; body++) {
633 if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3)) 657 if (!strncmp(body, "\n\n", 2) || !strncmp(body, "\n\r\n", 3)) {
634 break; 658 break;
635 } 659 }
660 }
636 661
637 if (!*body) 662 if (!*body) {
638 return 0; /* haven't read end of headers yet */ 663 return 0; /* haven't read end of headers yet */
664 }
639 665
640 full_page[body - full_page] = 0; 666 full_page[body - full_page] = 0;
641 return 1; 667 return 1;
642} 668}
643 669
644static time_t 670static time_t parse_time_string(const char *string) {
645parse_time_string (const char *string) 671 struct tm tm;
646{ 672 time_t t;
647 struct tm tm; 673 memset(&tm, 0, sizeof(tm));
648 time_t t; 674
649 memset (&tm, 0, sizeof(tm)); 675 /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
650 676
651 /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */ 677 if (isupper(string[0]) && /* Tue */
652 678 islower(string[1]) && islower(string[2]) && ',' == string[3] && ' ' == string[4] &&
653 if (isupper (string[0]) && /* Tue */ 679 (isdigit(string[5]) || string[5] == ' ') && /* 25 */
654 islower (string[1]) && 680 isdigit(string[6]) && ' ' == string[7] && isupper(string[8]) && /* Dec */
655 islower (string[2]) && 681 islower(string[9]) && islower(string[10]) && ' ' == string[11] &&
656 ',' == string[3] && 682 isdigit(string[12]) && /* 2001 */
657 ' ' == string[4] && 683 isdigit(string[13]) && isdigit(string[14]) && isdigit(string[15]) && ' ' == string[16] &&
658 (isdigit(string[5]) || string[5] == ' ') && /* 25 */ 684 isdigit(string[17]) && /* 02: */
659 isdigit (string[6]) && 685 isdigit(string[18]) && ':' == string[19] && isdigit(string[20]) && /* 59: */
660 ' ' == string[7] && 686 isdigit(string[21]) && ':' == string[22] && isdigit(string[23]) && /* 03 */
661 isupper (string[8]) && /* Dec */ 687 isdigit(string[24]) && ' ' == string[25] && 'G' == string[26] && /* GMT */
662 islower (string[9]) && 688 'M' == string[27] && /* GMT */
663 islower (string[10]) && 689 'T' == string[28]) {
664 ' ' == string[11] && 690
665 isdigit (string[12]) && /* 2001 */ 691 tm.tm_sec = 10 * (string[23] - '0') + (string[24] - '0');
666 isdigit (string[13]) && 692 tm.tm_min = 10 * (string[20] - '0') + (string[21] - '0');
667 isdigit (string[14]) && 693 tm.tm_hour = 10 * (string[17] - '0') + (string[18] - '0');
668 isdigit (string[15]) && 694 tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5] - '0') + (string[6] - '0');
669 ' ' == string[16] && 695 tm.tm_mon = (!strncmp(string + 8, "Jan", 3) ? 0
670 isdigit (string[17]) && /* 02: */ 696 : !strncmp(string + 8, "Feb", 3) ? 1
671 isdigit (string[18]) && 697 : !strncmp(string + 8, "Mar", 3) ? 2
672 ':' == string[19] && 698 : !strncmp(string + 8, "Apr", 3) ? 3
673 isdigit (string[20]) && /* 59: */ 699 : !strncmp(string + 8, "May", 3) ? 4
674 isdigit (string[21]) && 700 : !strncmp(string + 8, "Jun", 3) ? 5
675 ':' == string[22] && 701 : !strncmp(string + 8, "Jul", 3) ? 6
676 isdigit (string[23]) && /* 03 */ 702 : !strncmp(string + 8, "Aug", 3) ? 7
677 isdigit (string[24]) && 703 : !strncmp(string + 8, "Sep", 3) ? 8
678 ' ' == string[25] && 704 : !strncmp(string + 8, "Oct", 3) ? 9
679 'G' == string[26] && /* GMT */ 705 : !strncmp(string + 8, "Nov", 3) ? 10
680 'M' == string[27] && /* GMT */ 706 : !strncmp(string + 8, "Dec", 3) ? 11
681 'T' == string[28]) { 707 : -1);
682 708 tm.tm_year = ((1000 * (string[12] - '0') + 100 * (string[13] - '0') +
683 tm.tm_sec = 10 * (string[23]-'0') + (string[24]-'0'); 709 10 * (string[14] - '0') + (string[15] - '0')) -
684 tm.tm_min = 10 * (string[20]-'0') + (string[21]-'0'); 710 1900);
685 tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0'); 711
686 tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0'); 712 tm.tm_isdst = 0; /* GMT is never in DST, right? */
687 tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 : 713
688 !strncmp (string+8, "Feb", 3) ? 1 : 714 if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31) {
689 !strncmp (string+8, "Mar", 3) ? 2 : 715 return 0;
690 !strncmp (string+8, "Apr", 3) ? 3 : 716 }
691 !strncmp (string+8, "May", 3) ? 4 : 717
692 !strncmp (string+8, "Jun", 3) ? 5 : 718 /*
693 !strncmp (string+8, "Jul", 3) ? 6 : 719 This is actually wrong: we need to subtract the local timezone
694 !strncmp (string+8, "Aug", 3) ? 7 : 720 offset from GMT from this value. But, that's ok in this usage,
695 !strncmp (string+8, "Sep", 3) ? 8 : 721 because we only comparing these two GMT dates against each other,
696 !strncmp (string+8, "Oct", 3) ? 9 : 722 so it doesn't matter what time zone we parse them in.
697 !strncmp (string+8, "Nov", 3) ? 10 : 723 */
698 !strncmp (string+8, "Dec", 3) ? 11 : 724
699 -1); 725 t = mktime(&tm);
700 tm.tm_year = ((1000 * (string[12]-'0') + 726 if (t == (time_t)-1) {
701 100 * (string[13]-'0') + 727 t = 0;
702 10 * (string[14]-'0') + 728 }
703 (string[15]-'0')) 729
704 - 1900); 730 if (verbose) {
705 731 const char *s = string;
706 tm.tm_isdst = 0; /* GMT is never in DST, right? */ 732 while (*s && *s != '\r' && *s != '\n') {
707 733 fputc(*s++, stdout);
708 if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31) 734 }
709 return 0; 735 printf(" ==> %lu\n", (unsigned long)t);
710 736 }
711 /* 737
712 This is actually wrong: we need to subtract the local timezone 738 return t;
713 offset from GMT from this value. But, that's ok in this usage, 739 }
714 because we only comparing these two GMT dates against each other, 740 return 0;
715 so it doesn't matter what time zone we parse them in.
716 */
717
718 t = mktime (&tm);
719 if (t == (time_t) -1) t = 0;
720
721 if (verbose) {
722 const char *s = string;
723 while (*s && *s != '\r' && *s != '\n')
724 fputc (*s++, stdout);
725 printf (" ==> %lu\n", (unsigned long) t);
726 }
727
728 return t;
729
730 } else {
731 return 0;
732 }
733} 741}
734 742
735/* Checks if the server 'reply' is one of the expected 'statuscodes' */ 743/* Checks if the server 'reply' is one of the expected 'statuscodes' */
736static int 744static int expected_statuscode(const char *reply, const char *statuscodes) {
737expected_statuscode (const char *reply, const char *statuscodes) 745 char *expected;
738{ 746 char *code;
739 char *expected, *code; 747 int result = 0;
740 int result = 0; 748
741 749 if ((expected = strdup(statuscodes)) == NULL) {
742 if ((expected = strdup (statuscodes)) == NULL) 750 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
743 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n")); 751 }
744 752
745 for (code = strtok (expected, ","); code != NULL; code = strtok (NULL, ",")) 753 for (code = strtok(expected, ","); code != NULL; code = strtok(NULL, ",")) {
746 if (strstr (reply, code) != NULL) { 754 if (strstr(reply, code) != NULL) {
747 result = 1; 755 result = 1;
748 break; 756 break;
749 } 757 }
750 758 }
751 free (expected); 759
752 return result; 760 free(expected);
761 return result;
753} 762}
754 763
755static int 764static int check_document_dates(const char *headers, char **msg) {
756check_document_dates (const char *headers, char **msg) 765 const char *s;
757{ 766 char *server_date = 0;
758 const char *s; 767 char *document_date = 0;
759 char *server_date = 0; 768 int date_result = STATE_OK;
760 char *document_date = 0; 769
761 int date_result = STATE_OK; 770 s = headers;
762 771 while (*s) {
763 s = headers; 772 const char *field = s;
764 while (*s) { 773 const char *value = 0;
765 const char *field = s; 774
766 const char *value = 0; 775 /* Find the end of the header field */
767 776 while (*s && !isspace(*s) && *s != ':') {
768 /* Find the end of the header field */ 777 s++;
769 while (*s && !isspace(*s) && *s != ':') 778 }
770 s++; 779
771 780 /* Remember the header value, if any. */
772 /* Remember the header value, if any. */ 781 if (*s == ':') {
773 if (*s == ':') 782 value = ++s;
774 value = ++s; 783 }
775 784
776 /* Skip to the end of the header, including continuation lines. */ 785 /* Skip to the end of the header, including continuation lines. */
777 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t'))) 786 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t'))) {
778 s++; 787 s++;
779 788 }
780 /* Avoid stepping over end-of-string marker */ 789
781 if (*s) 790 /* Avoid stepping over end-of-string marker */
782 s++; 791 if (*s) {
783 792 s++;
784 /* Process this header. */ 793 }
785 if (value && value > field+2) { 794
786 char *ff = (char *) malloc (value-field); 795 /* Process this header. */
787 char *ss = ff; 796 if (value && value > field + 2) {
788 while (field < value-1) 797 char *ff = (char *)malloc(value - field);
789 *ss++ = tolower(*field++); 798 char *ss = ff;
790 *ss++ = 0; 799 while (field < value - 1) {
791 800 *ss++ = tolower(*field++);
792 if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) { 801 }
793 const char *e; 802 *ss++ = 0;
794 while (*value && isspace (*value)) 803
795 value++; 804 if (!strcmp(ff, "date") || !strcmp(ff, "last-modified")) {
796 for (e = value; *e && *e != '\r' && *e != '\n'; e++) 805 const char *e;
797 ; 806 while (*value && isspace(*value)) {
798 ss = (char *) malloc (e - value + 1); 807 value++;
799 strncpy (ss, value, e - value); 808 }
800 ss[e - value] = 0; 809 for (e = value; *e && *e != '\r' && *e != '\n'; e++) {
801 if (!strcmp (ff, "date")) { 810 ;
802 if (server_date) free (server_date); 811 }
803 server_date = ss; 812 ss = (char *)malloc(e - value + 1);
804 } else { 813 strncpy(ss, value, e - value);
805 if (document_date) free (document_date); 814 ss[e - value] = 0;
806 document_date = ss; 815 if (!strcmp(ff, "date")) {
807 } 816 if (server_date) {
808 } 817 free(server_date);
809 free (ff); 818 }
810 } 819 server_date = ss;
811 } 820 } else {
812 821 if (document_date) {
813 /* Done parsing the body. Now check the dates we (hopefully) parsed. */ 822 free(document_date);
814 if (!server_date || !*server_date) { 823 }
815 xasprintf (msg, _("%sServer date unknown, "), *msg); 824 document_date = ss;
816 date_result = max_state_alt(STATE_UNKNOWN, date_result); 825 }
817 } else if (!document_date || !*document_date) { 826 }
818 xasprintf (msg, _("%sDocument modification date unknown, "), *msg); 827 free(ff);
819 date_result = max_state_alt(STATE_CRITICAL, date_result); 828 }
820 } else { 829 }
821 time_t srv_data = parse_time_string (server_date); 830
822 time_t doc_data = parse_time_string (document_date); 831 /* Done parsing the body. Now check the dates we (hopefully) parsed. */
823 832 if (!server_date || !*server_date) {
824 if (srv_data <= 0) { 833 xasprintf(msg, _("%sServer date unknown, "), *msg);
825 xasprintf (msg, _("%sServer date \"%100s\" unparsable, "), *msg, server_date); 834 date_result = max_state_alt(STATE_UNKNOWN, date_result);
826 date_result = max_state_alt(STATE_CRITICAL, date_result); 835 } else if (!document_date || !*document_date) {
827 } else if (doc_data <= 0) { 836 xasprintf(msg, _("%sDocument modification date unknown, "), *msg);
828 xasprintf (msg, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date); 837 date_result = max_state_alt(STATE_CRITICAL, date_result);
829 date_result = max_state_alt(STATE_CRITICAL, date_result); 838 } else {
830 } else if (doc_data > srv_data + 30) { 839 time_t srv_data = parse_time_string(server_date);
831 xasprintf (msg, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data); 840 time_t doc_data = parse_time_string(document_date);
832 date_result = max_state_alt(STATE_CRITICAL, date_result); 841
833 } else if (doc_data < srv_data - maximum_age) { 842 if (srv_data <= 0) {
834 int n = (srv_data - doc_data); 843 xasprintf(msg, _("%sServer date \"%100s\" unparsable, "), *msg, server_date);
835 if (n > (60 * 60 * 24 * 2)) { 844 date_result = max_state_alt(STATE_CRITICAL, date_result);
836 xasprintf (msg, _("%sLast modified %.1f days ago, "), *msg, ((float) n) / (60 * 60 * 24)); 845 } else if (doc_data <= 0) {
837 date_result = max_state_alt(STATE_CRITICAL, date_result); 846 xasprintf(msg, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date);
838 } else { 847 date_result = max_state_alt(STATE_CRITICAL, date_result);
839 xasprintf (msg, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60); 848 } else if (doc_data > srv_data + 30) {
840 date_result = max_state_alt(STATE_CRITICAL, date_result); 849 xasprintf(msg, _("%sDocument is %d seconds in the future, "), *msg,
841 } 850 (int)doc_data - (int)srv_data);
842 } 851 date_result = max_state_alt(STATE_CRITICAL, date_result);
843 free (server_date); 852 } else if (doc_data < srv_data - maximum_age) {
844 free (document_date); 853 int n = (srv_data - doc_data);
845 } 854 if (n > (60 * 60 * 24 * 2)) {
846 return date_result; 855 xasprintf(msg, _("%sLast modified %.1f days ago, "), *msg,
856 ((float)n) / (60 * 60 * 24));
857 date_result = max_state_alt(STATE_CRITICAL, date_result);
858 } else {
859 xasprintf(msg, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60),
860 (n / 60) % 60, n % 60);
861 date_result = max_state_alt(STATE_CRITICAL, date_result);
862 }
863 }
864 free(server_date);
865 free(document_date);
866 }
867 return date_result;
847} 868}
848 869
849int 870int get_content_length(const char *headers) {
850get_content_length (const char *headers) 871 const char *s;
851{ 872 int content_length = 0;
852 const char *s; 873
853 int content_length = 0; 874 s = headers;
854 875 while (*s) {
855 s = headers; 876 const char *field = s;
856 while (*s) { 877 const char *value = 0;
857 const char *field = s; 878
858 const char *value = 0; 879 /* Find the end of the header field */
859 880 while (*s && !isspace(*s) && *s != ':') {
860 /* Find the end of the header field */ 881 s++;
861 while (*s && !isspace(*s) && *s != ':') 882 }
862 s++; 883
863 884 /* Remember the header value, if any. */
864 /* Remember the header value, if any. */ 885 if (*s == ':') {
865 if (*s == ':') 886 value = ++s;
866 value = ++s; 887 }
867 888
868 /* Skip to the end of the header, including continuation lines. */ 889 /* Skip to the end of the header, including continuation lines. */
869 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t'))) 890 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t'))) {
870 s++; 891 s++;
871 892 }
872 /* Avoid stepping over end-of-string marker */ 893
873 if (*s) 894 /* Avoid stepping over end-of-string marker */
874 s++; 895 if (*s) {
875 896 s++;
876 /* Process this header. */ 897 }
877 if (value && value > field+2) { 898
878 char *ff = (char *) malloc (value-field); 899 /* Process this header. */
879 char *ss = ff; 900 if (value && value > field + 2) {
880 while (field < value-1) 901 char *ff = (char *)malloc(value - field);
881 *ss++ = tolower(*field++); 902 char *ss = ff;
882 *ss++ = 0; 903 while (field < value - 1) {
883 904 *ss++ = tolower(*field++);
884 if (!strcmp (ff, "content-length")) { 905 }
885 const char *e; 906 *ss++ = 0;
886 while (*value && isspace (*value)) 907
887 value++; 908 if (!strcmp(ff, "content-length")) {
888 for (e = value; *e && *e != '\r' && *e != '\n'; e++) 909 const char *e;
889 ; 910 while (*value && isspace(*value)) {
890 ss = (char *) malloc (e - value + 1); 911 value++;
891 strncpy (ss, value, e - value); 912 }
892 ss[e - value] = 0; 913 for (e = value; *e && *e != '\r' && *e != '\n'; e++) {
893 content_length = atoi(ss); 914 ;
894 free (ss); 915 }
895 } 916 ss = (char *)malloc(e - value + 1);
896 free (ff); 917 strncpy(ss, value, e - value);
897 } 918 ss[e - value] = 0;
898 } 919 content_length = atoi(ss);
899 return (content_length); 920 free(ss);
921 }
922 free(ff);
923 }
924 }
925 return (content_length);
900} 926}
901 927
902char * 928char *prepend_slash(char *path) {
903prepend_slash (char *path) 929 char *newpath;
904{
905 char *newpath;
906 930
907 if (path[0] == '/') 931 if (path[0] == '/') {
908 return path; 932 return path;
933 }
909 934
910 if ((newpath = malloc (strlen(path) + 2)) == NULL) 935 if ((newpath = malloc(strlen(path) + 2)) == NULL) {
911 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n")); 936 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
912 newpath[0] = '/'; 937 }
913 strcpy (newpath + 1, path); 938 newpath[0] = '/';
914 free (path); 939 strcpy(newpath + 1, path);
915 return newpath; 940 free(path);
941 return newpath;
916} 942}
917 943
918int 944int check_http(void) {
919check_http (void) 945 char *msg;
920{ 946 char *status_line;
921 char *msg; 947 char *status_code;
922 char *status_line; 948 char *header;
923 char *status_code; 949 char *page;
924 char *header; 950 char *auth;
925 char *page; 951 int http_status;
926 char *auth; 952 int i = 0;
927 int http_status; 953 size_t pagesize = 0;
928 int i = 0; 954 char *full_page;
929 size_t pagesize = 0; 955 char *full_page_new;
930 char *full_page; 956 char *buf;
931 char *full_page_new; 957 char *pos;
932 char *buf; 958 long microsec = 0L;
933 char *pos; 959 double elapsed_time = 0.0;
934 long microsec = 0L; 960 long microsec_connect = 0L;
935 double elapsed_time = 0.0; 961 double elapsed_time_connect = 0.0;
936 long microsec_connect = 0L; 962 long microsec_ssl = 0L;
937 double elapsed_time_connect = 0.0; 963 double elapsed_time_ssl = 0.0;
938 long microsec_ssl = 0L; 964 long microsec_firstbyte = 0L;
939 double elapsed_time_ssl = 0.0; 965 double elapsed_time_firstbyte = 0.0;
940 long microsec_firstbyte = 0L; 966 long microsec_headers = 0L;
941 double elapsed_time_firstbyte = 0.0; 967 double elapsed_time_headers = 0.0;
942 long microsec_headers = 0L; 968 long microsec_transfer = 0L;
943 double elapsed_time_headers = 0.0; 969 double elapsed_time_transfer = 0.0;
944 long microsec_transfer = 0L; 970 int page_len = 0;
945 double elapsed_time_transfer = 0.0; 971 int result = STATE_OK;
946 int page_len = 0; 972 char *force_host_header = NULL;
947 int result = STATE_OK; 973
948 char *force_host_header = NULL; 974 /* try to connect to the host at the given port number */
949 975 gettimeofday(&tv_temp, NULL);
950 /* try to connect to the host at the given port number */ 976 if (my_tcp_connect(server_address, server_port, &sd) != STATE_OK) {
951 gettimeofday (&tv_temp, NULL); 977 die(STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n"));
952 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK) 978 }
953 die (STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n")); 979 microsec_connect = deltime(tv_temp);
954 microsec_connect = deltime (tv_temp); 980
955 981 /* if we are called with the -I option, the -j method is CONNECT and */
956 /* if we are called with the -I option, the -j method is CONNECT and */ 982 /* we received -S for SSL, then we tunnel the request through a proxy*/
957 /* we received -S for SSL, then we tunnel the request through a proxy*/ 983 /* @20100414, public[at]frank4dd.com, http://www.frank4dd.com/howto */
958 /* @20100414, public[at]frank4dd.com, http://www.frank4dd.com/howto */ 984
959 985 if (server_address != NULL && strcmp(http_method, "CONNECT") == 0 && host_name != NULL &&
960 if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0 986 use_ssl) {
961 && host_name != NULL && use_ssl == true) { 987
962 988 if (verbose) {
963 if (verbose) printf ("Entering CONNECT tunnel mode with proxy %s:%d to dst %s:%d\n", server_address, server_port, host_name, HTTPS_PORT); 989 printf("Entering CONNECT tunnel mode with proxy %s:%d to dst %s:%d\n", server_address,
964 asprintf (&buf, "%s %s:%d HTTP/1.1\r\n%s\r\n", http_method, host_name, HTTPS_PORT, user_agent); 990 server_port, host_name, HTTPS_PORT);
965 if (strlen(proxy_auth)) { 991 }
966 base64_encode_alloc (proxy_auth, strlen (proxy_auth), &auth); 992 asprintf(&buf, "%s %s:%d HTTP/1.1\r\n%s\r\n", http_method, host_name, HTTPS_PORT,
967 xasprintf (&buf, "%sProxy-Authorization: Basic %s\r\n", buf, auth); 993 user_agent);
968 } 994 if (strlen(proxy_auth)) {
969 /* optionally send any other header tag */ 995 base64_encode_alloc(proxy_auth, strlen(proxy_auth), &auth);
970 if (http_opt_headers_count) { 996 xasprintf(&buf, "%sProxy-Authorization: Basic %s\r\n", buf, auth);
971 for (i = 0; i < http_opt_headers_count ; i++) { 997 }
972 if (force_host_header != http_opt_headers[i]) { 998 /* optionally send any other header tag */
973 xasprintf (&buf, "%s%s\r\n", buf, http_opt_headers[i]); 999 if (http_opt_headers_count) {
974 } 1000 for (i = 0; i < http_opt_headers_count; i++) {
975 } 1001 if (force_host_header != http_opt_headers[i]) {
976 /* This cannot be free'd here because a redirection will then try to access this and segfault */ 1002 xasprintf(&buf, "%s%s\r\n", buf, http_opt_headers[i]);
977 /* Covered in a testcase in tests/check_http.t */ 1003 }
978 /* free(http_opt_headers); */ 1004 }
979 } 1005 /* This cannot be free'd here because a redirection will then try to access this and
980 asprintf (&buf, "%sProxy-Connection: keep-alive\r\n", buf); 1006 * segfault */
981 asprintf (&buf, "%sHost: %s\r\n", buf, host_name); 1007 /* Covered in a testcase in tests/check_http.t */
982 /* we finished our request, send empty line with CRLF */ 1008 /* free(http_opt_headers); */
983 asprintf (&buf, "%s%s", buf, CRLF); 1009 }
984 if (verbose) printf ("%s\n", buf); 1010 asprintf(&buf, "%sProxy-Connection: keep-alive\r\n", buf);
985 send(sd, buf, strlen (buf), 0); 1011 asprintf(&buf, "%sHost: %s\r\n", buf, host_name);
986 buf[0]='\0'; 1012 /* we finished our request, send empty line with CRLF */
987 1013 asprintf(&buf, "%s%s", buf, CRLF);
988 if (verbose) printf ("Receive response from proxy\n"); 1014 if (verbose) {
989 read (sd, buffer, MAX_INPUT_BUFFER-1); 1015 printf("%s\n", buf);
990 if (verbose) printf ("%s", buffer); 1016 }
991 /* Here we should check if we got HTTP/1.1 200 Connection established */ 1017 send(sd, buf, strlen(buf), 0);
992 } 1018 buf[0] = '\0';
1019
1020 if (verbose) {
1021 printf("Receive response from proxy\n");
1022 }
1023 read(sd, buffer, MAX_INPUT_BUFFER - 1);
1024 if (verbose) {
1025 printf("%s", buffer);
1026 }
1027 /* Here we should check if we got HTTP/1.1 200 Connection established */
1028 }
993#ifdef HAVE_SSL 1029#ifdef HAVE_SSL
994 elapsed_time_connect = (double)microsec_connect / 1.0e6; 1030 elapsed_time_connect = (double)microsec_connect / 1.0e6;
995 if (use_ssl == true) { 1031 if (use_ssl) {
996 gettimeofday (&tv_temp, NULL); 1032 gettimeofday(&tv_temp, NULL);
997 result = np_net_ssl_init_with_hostname_version_and_cert(sd, (use_sni ? host_name : NULL), ssl_version, client_cert, client_privkey); 1033 result = np_net_ssl_init_with_hostname_version_and_cert(
998 if (verbose) printf ("SSL initialized\n"); 1034 sd, (use_sni ? host_name : NULL), ssl_version, client_cert, client_privkey);
999 if (result != STATE_OK) 1035 if (verbose) {
1000 die (STATE_CRITICAL, NULL); 1036 printf("SSL initialized\n");
1001 microsec_ssl = deltime (tv_temp); 1037 }
1002 elapsed_time_ssl = (double)microsec_ssl / 1.0e6; 1038 if (result != STATE_OK) {
1003 if (check_cert == true) { 1039 die(STATE_CRITICAL, NULL);
1004 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit); 1040 }
1005 if (continue_after_check_cert == false) { 1041 microsec_ssl = deltime(tv_temp);
1006 if (sd) close(sd); 1042 elapsed_time_ssl = (double)microsec_ssl / 1.0e6;
1007 np_net_ssl_cleanup(); 1043 if (check_cert) {
1008 return result; 1044 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit);
1009 } 1045 if (!continue_after_check_cert) {
1010 } 1046 if (sd) {
1011 } 1047 close(sd);
1048 }
1049 np_net_ssl_cleanup();
1050 return result;
1051 }
1052 }
1053 }
1012#endif /* HAVE_SSL */ 1054#endif /* HAVE_SSL */
1013 1055
1014 if ( server_address != NULL && strcmp(http_method, "CONNECT") == 0 1056 if (server_address != NULL && strcmp(http_method, "CONNECT") == 0 && host_name != NULL &&
1015 && host_name != NULL && use_ssl == true) 1057 use_ssl) {
1016 asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method_proxy, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent); 1058 asprintf(&buf, "%s %s %s\r\n%s\r\n", http_method_proxy, server_url,
1017 else 1059 host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent);
1018 asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent); 1060 } else {
1019 1061 asprintf(&buf, "%s %s %s\r\n%s\r\n", http_method, server_url,
1020 /* tell HTTP/1.1 servers not to keep the connection alive */ 1062 host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent);
1021 xasprintf (&buf, "%sConnection: close\r\n", buf); 1063 }
1022 1064
1023 /* check if Host header is explicitly set in options */ 1065 /* tell HTTP/1.1 servers not to keep the connection alive */
1024 if (http_opt_headers_count) { 1066 xasprintf(&buf, "%sConnection: close\r\n", buf);
1025 for (i = 0; i < http_opt_headers_count ; i++) { 1067
1026 if (strncmp(http_opt_headers[i], "Host:", 5) == 0) { 1068 /* check if Host header is explicitly set in options */
1027 force_host_header = http_opt_headers[i]; 1069 if (http_opt_headers_count) {
1028 } 1070 for (i = 0; i < http_opt_headers_count; i++) {
1029 } 1071 if (strncmp(http_opt_headers[i], "Host:", 5) == 0) {
1030 } 1072 force_host_header = http_opt_headers[i];
1031 1073 }
1032 /* optionally send the host header info */ 1074 }
1033 if (host_name) { 1075 }
1034 if (force_host_header) { 1076
1035 xasprintf (&buf, "%s%s\r\n", buf, force_host_header); 1077 /* optionally send the host header info */
1036 } 1078 if (host_name) {
1037 else { 1079 if (force_host_header) {
1038 /* 1080 xasprintf(&buf, "%s%s\r\n", buf, force_host_header);
1039 * Specify the port only if we're using a non-default port (see RFC 2616, 1081 } else {
1040 * 14.23). Some server applications/configurations cause trouble if the 1082 /*
1041 * (default) port is explicitly specified in the "Host:" header line. 1083 * Specify the port only if we're using a non-default port (see RFC 2616,
1042 */ 1084 * 14.23). Some server applications/configurations cause trouble if the
1043 if ((use_ssl == false && virtual_port == HTTP_PORT) || 1085 * (default) port is explicitly specified in the "Host:" header line.
1044 (use_ssl == true && virtual_port == HTTPS_PORT) || 1086 */
1045 (server_address != NULL && strcmp(http_method, "CONNECT") == 0 1087 if ((!use_ssl && virtual_port == HTTP_PORT) ||
1046 && host_name != NULL && use_ssl == true)) 1088 (use_ssl && virtual_port == HTTPS_PORT) ||
1047 xasprintf (&buf, "%sHost: %s\r\n", buf, host_name); 1089 (server_address != NULL && strcmp(http_method, "CONNECT") == 0 &&
1048 else 1090 host_name != NULL && use_ssl)) {
1049 xasprintf (&buf, "%sHost: %s:%d\r\n", buf, host_name, virtual_port); 1091 xasprintf(&buf, "%sHost: %s\r\n", buf, host_name);
1050 } 1092 } else {
1051 } 1093 xasprintf(&buf, "%sHost: %s:%d\r\n", buf, host_name, virtual_port);
1052 1094 }
1053 /* optionally send any other header tag */ 1095 }
1054 if (http_opt_headers_count) { 1096 }
1055 for (i = 0; i < http_opt_headers_count ; i++) { 1097
1056 if (force_host_header != http_opt_headers[i]) { 1098 /* optionally send any other header tag */
1057 xasprintf (&buf, "%s%s\r\n", buf, http_opt_headers[i]); 1099 if (http_opt_headers_count) {
1058 } 1100 for (i = 0; i < http_opt_headers_count; i++) {
1059 } 1101 if (force_host_header != http_opt_headers[i]) {
1060 /* This cannot be free'd here because a redirection will then try to access this and segfault */ 1102 xasprintf(&buf, "%s%s\r\n", buf, http_opt_headers[i]);
1061 /* Covered in a testcase in tests/check_http.t */ 1103 }
1062 /* free(http_opt_headers); */ 1104 }
1063 } 1105 /* This cannot be free'd here because a redirection will then try to access this and
1064 1106 * segfault */
1065 /* optionally send the authentication info */ 1107 /* Covered in a testcase in tests/check_http.t */
1066 if (strlen(user_auth)) { 1108 /* free(http_opt_headers); */
1067 base64_encode_alloc (user_auth, strlen (user_auth), &auth); 1109 }
1068 xasprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth); 1110
1069 } 1111 /* optionally send the authentication info */
1070 1112 if (strlen(user_auth)) {
1071 /* optionally send the proxy authentication info */ 1113 base64_encode_alloc(user_auth, strlen(user_auth), &auth);
1072 if (strlen(proxy_auth)) { 1114 xasprintf(&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
1073 base64_encode_alloc (proxy_auth, strlen (proxy_auth), &auth); 1115 }
1074 xasprintf (&buf, "%sProxy-Authorization: Basic %s\r\n", buf, auth); 1116
1075 } 1117 /* optionally send the proxy authentication info */
1076 1118 if (strlen(proxy_auth)) {
1077 /* either send http POST data (any data, not only POST)*/ 1119 base64_encode_alloc(proxy_auth, strlen(proxy_auth), &auth);
1078 if (http_post_data) { 1120 xasprintf(&buf, "%sProxy-Authorization: Basic %s\r\n", buf, auth);
1079 if (http_content_type) { 1121 }
1080 xasprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type); 1122
1081 } else { 1123 /* either send http POST data (any data, not only POST)*/
1082 xasprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf); 1124 if (http_post_data) {
1083 } 1125 if (http_content_type) {
1084 1126 xasprintf(&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
1085 xasprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data)); 1127 } else {
1086 xasprintf (&buf, "%s%s", buf, http_post_data); 1128 xasprintf(&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
1087 } else { 1129 }
1088 /* or just a newline so the server knows we're done with the request */ 1130
1089 xasprintf (&buf, "%s%s", buf, CRLF); 1131 xasprintf(&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen(http_post_data));
1090 } 1132 xasprintf(&buf, "%s%s", buf, http_post_data);
1091 1133 } else {
1092 if (verbose) printf ("%s\n", buf); 1134 /* or just a newline so the server knows we're done with the request */
1093 gettimeofday (&tv_temp, NULL); 1135 xasprintf(&buf, "%s%s", buf, CRLF);
1094 my_send (buf, strlen (buf)); 1136 }
1095 microsec_headers = deltime (tv_temp); 1137
1096 elapsed_time_headers = (double)microsec_headers / 1.0e6; 1138 if (verbose) {
1097 1139 printf("%s\n", buf);
1098 /* fetch the page */ 1140 }
1099 full_page = strdup(""); 1141 gettimeofday(&tv_temp, NULL);
1100 gettimeofday (&tv_temp, NULL); 1142 my_send(buf, strlen(buf));
1101 while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) { 1143 microsec_headers = deltime(tv_temp);
1102 if ((i >= 1) && (elapsed_time_firstbyte <= 0.000001)) { 1144 elapsed_time_headers = (double)microsec_headers / 1.0e6;
1103 microsec_firstbyte = deltime (tv_temp); 1145
1104 elapsed_time_firstbyte = (double)microsec_firstbyte / 1.0e6; 1146 /* fetch the page */
1105 } 1147 full_page = strdup("");
1106 while ((pos = memchr(buffer, '\0', i))) { 1148 gettimeofday(&tv_temp, NULL);
1107 /* replace nul character with a blank */ 1149 while ((i = my_recv(buffer, MAX_INPUT_BUFFER - 1)) > 0) {
1108 *pos = ' '; 1150 if ((i >= 1) && (elapsed_time_firstbyte <= 0.000001)) {
1109 } 1151 microsec_firstbyte = deltime(tv_temp);
1110 buffer[i] = '\0'; 1152 elapsed_time_firstbyte = (double)microsec_firstbyte / 1.0e6;
1111 1153 }
1112 if ((full_page_new = realloc(full_page, pagesize + i + 1)) == NULL) 1154 while ((pos = memchr(buffer, '\0', i))) {
1113 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate memory for full_page\n")); 1155 /* replace nul character with a blank */
1114 1156 *pos = ' ';
1115 memmove(&full_page_new[pagesize], buffer, i + 1); 1157 }
1116 1158 buffer[i] = '\0';
1117 full_page = full_page_new; 1159
1118 1160 if ((full_page_new = realloc(full_page, pagesize + i + 1)) == NULL) {
1119 pagesize += i; 1161 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate memory for full_page\n"));
1120 1162 }
1121 if (no_body && document_headers_done (full_page)) { 1163
1122 i = 0; 1164 memmove(&full_page_new[pagesize], buffer, i + 1);
1123 break; 1165
1124 } 1166 full_page = full_page_new;
1125 } 1167
1126 microsec_transfer = deltime (tv_temp); 1168 pagesize += i;
1127 elapsed_time_transfer = (double)microsec_transfer / 1.0e6; 1169
1128 1170 if (no_body && document_headers_done(full_page)) {
1129 if (i < 0 && errno != ECONNRESET) { 1171 i = 0;
1130 die(STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n")); 1172 break;
1131 } 1173 }
1132 1174 }
1133 /* return a CRITICAL status if we couldn't read any data */ 1175 microsec_transfer = deltime(tv_temp);
1134 if (pagesize == (size_t) 0) 1176 elapsed_time_transfer = (double)microsec_transfer / 1.0e6;
1135 die (STATE_CRITICAL, _("HTTP CRITICAL - No data received from host\n")); 1177
1136 1178 if (i < 0 && errno != ECONNRESET) {
1137 /* close the connection */ 1179 die(STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
1138 if (sd) close(sd); 1180 }
1181
1182 /* return a CRITICAL status if we couldn't read any data */
1183 if (pagesize == (size_t)0) {
1184 die(STATE_CRITICAL, _("HTTP CRITICAL - No data received from host\n"));
1185 }
1186
1187 /* close the connection */
1188 if (sd) {
1189 close(sd);
1190 }
1139#ifdef HAVE_SSL 1191#ifdef HAVE_SSL
1140 np_net_ssl_cleanup(); 1192 np_net_ssl_cleanup();
1141#endif 1193#endif
1142 1194
1143 /* Save check time */ 1195 /* Save check time */
1144 microsec = deltime (tv); 1196 microsec = deltime(tv);
1145 elapsed_time = (double)microsec / 1.0e6; 1197 elapsed_time = (double)microsec / 1.0e6;
1146 1198
1147 /* leave full_page untouched so we can free it later */ 1199 /* leave full_page untouched so we can free it later */
1148 page = full_page; 1200 page = full_page;
1149 1201
1150 if (verbose) 1202 if (verbose) {
1151 printf ("%s://%s:%d%s is %d characters\n", 1203 printf("%s://%s:%d%s is %d characters\n", use_ssl ? "https" : "http", server_address,
1152 use_ssl ? "https" : "http", server_address, 1204 server_port, server_url, (int)pagesize);
1153 server_port, server_url, (int)pagesize); 1205 }
1154 1206
1155 /* find status line and null-terminate it */ 1207 /* find status line and null-terminate it */
1156 status_line = page; 1208 status_line = page;
1157 page += (size_t) strcspn (page, "\r\n"); 1209 page += (size_t)strcspn(page, "\r\n");
1158 pos = page; 1210 pos = page;
1159 page += (size_t) strspn (page, "\r\n"); 1211 page += (size_t)strspn(page, "\r\n");
1160 status_line[strcspn(status_line, "\r\n")] = 0; 1212 status_line[strcspn(status_line, "\r\n")] = 0;
1161 strip (status_line); 1213 strip(status_line);
1162 if (verbose) 1214 if (verbose) {
1163 printf ("STATUS: %s\n", status_line); 1215 printf("STATUS: %s\n", status_line);
1164 1216 }
1165 /* find header info and null-terminate it */ 1217
1166 header = page; 1218 /* find header info and null-terminate it */
1167 while (strcspn (page, "\r\n") > 0) { 1219 header = page;
1168 page += (size_t) strcspn (page, "\r\n"); 1220 while (strcspn(page, "\r\n") > 0) {
1169 pos = page; 1221 page += (size_t)strcspn(page, "\r\n");
1170 if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) || 1222 pos = page;
1171 (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2)) 1223 if ((strspn(page, "\r") == 1 && strspn(page, "\r\n") >= 2) ||
1172 page += (size_t) 2; 1224 (strspn(page, "\n") == 1 && strspn(page, "\r\n") >= 2)) {
1173 else 1225 page += (size_t)2;
1174 page += (size_t) 1; 1226 } else {
1175 } 1227 page += (size_t)1;
1176 page += (size_t) strspn (page, "\r\n"); 1228 }
1177 header[pos - header] = 0; 1229 }
1178 if (verbose) 1230 page += (size_t)strspn(page, "\r\n");
1179 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header, 1231 header[pos - header] = 0;
1180 (no_body ? " [[ skipped ]]" : page)); 1232 if (verbose) {
1181 1233 printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
1182 /* make sure the status line matches the response we are looking for */ 1234 (no_body ? " [[ skipped ]]" : page));
1183 if (!expected_statuscode (status_line, server_expect)) { 1235 }
1184 if (server_port == HTTP_PORT) 1236
1185 xasprintf (&msg, 1237 /* make sure the status line matches the response we are looking for */
1186 _("Invalid HTTP response received from host: %s\n"), 1238 if (!expected_statuscode(status_line, server_expect)) {
1187 status_line); 1239 if (server_port == HTTP_PORT) {
1188 else 1240 xasprintf(&msg, _("Invalid HTTP response received from host: %s\n"), status_line);
1189 xasprintf (&msg, 1241 } else {
1190 _("Invalid HTTP response received from host on port %d: %s\n"), 1242 xasprintf(&msg, _("Invalid HTTP response received from host on port %d: %s\n"),
1191 server_port, status_line); 1243 server_port, status_line);
1192 if (show_body) 1244 }
1193 xasprintf (&msg, _("%s\n%s"), msg, page); 1245 if (show_body) {
1194 die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg); 1246 xasprintf(&msg, _("%s\n%s"), msg, page);
1195 } 1247 }
1196 1248 die(STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
1197 /* Bypass normal status line check if server_expect was set by user and not default */ 1249 }
1198 /* NOTE: After this if/else block msg *MUST* be an asprintf-allocated string */ 1250
1199 if ( server_expect_yn ) { 1251 /* Bypass normal status line check if server_expect was set by user and not default */
1200 xasprintf (&msg, 1252 /* NOTE: After this if/else block msg *MUST* be an asprintf-allocated string */
1201 _("Status line output matched \"%s\" - "), server_expect); 1253 if (server_expect_yn) {
1202 if (verbose) 1254 xasprintf(&msg, _("Status line output matched \"%s\" - "), server_expect);
1203 printf ("%s\n",msg); 1255 if (verbose) {
1204 } 1256 printf("%s\n", msg);
1205 else { 1257 }
1206 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */ 1258 } else {
1207 /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */ 1259 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
1208 /* Status-Code = 3 DIGITS */ 1260 /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
1209 1261 /* Status-Code = 3 DIGITS */
1210 status_code = strchr (status_line, ' ') + sizeof (char); 1262
1211 if (strspn (status_code, "1234567890") != 3) 1263 status_code = strchr(status_line, ' ') + sizeof(char);
1212 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line); 1264 if (strspn(status_code, "1234567890") != 3) {
1213 1265 die(STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
1214 http_status = atoi (status_code); 1266 }
1215 1267
1216 /* check the return code */ 1268 http_status = atoi(status_code);
1217 1269
1218 if (http_status >= 600 || http_status < 100) { 1270 /* check the return code */
1219 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line); 1271
1220 } 1272 if (http_status >= 600 || http_status < 100) {
1221 /* server errors result in a critical state */ 1273 die(STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
1222 else if (http_status >= 500) { 1274 }
1223 xasprintf (&msg, _("%s - "), status_line); 1275 /* server errors result in a critical state */
1224 result = STATE_CRITICAL; 1276 else if (http_status >= 500) {
1225 } 1277 xasprintf(&msg, _("%s - "), status_line);
1226 /* client errors result in a warning state */ 1278 result = STATE_CRITICAL;
1227 else if (http_status >= 400) { 1279 }
1228 xasprintf (&msg, _("%s - "), status_line); 1280 /* client errors result in a warning state */
1229 result = max_state_alt(STATE_WARNING, result); 1281 else if (http_status >= 400) {
1230 } 1282 xasprintf(&msg, _("%s - "), status_line);
1231 /* check redirected page if specified */ 1283 result = max_state_alt(STATE_WARNING, result);
1232 else if (http_status >= 300) { 1284 }
1233 1285 /* check redirected page if specified */
1234 if (onredirect == STATE_DEPENDENT) 1286 else if (http_status >= 300) {
1235 redir (header, status_line); 1287
1236 else 1288 if (onredirect == STATE_DEPENDENT) {
1237 result = max_state_alt(onredirect, result); 1289 redir(header, status_line);
1238 xasprintf (&msg, _("%s - "), status_line); 1290 } else {
1239 } /* end if (http_status >= 300) */ 1291 result = max_state_alt(onredirect, result);
1240 else { 1292 }
1241 /* Print OK status anyway */ 1293 xasprintf(&msg, _("%s - "), status_line);
1242 xasprintf (&msg, _("%s - "), status_line); 1294 } /* end if (http_status >= 300) */
1243 } 1295 else {
1244 1296 /* Print OK status anyway */
1245 } /* end else (server_expect_yn) */ 1297 xasprintf(&msg, _("%s - "), status_line);
1246 1298 }
1247 /* reset the alarm - must be called *after* redir or we'll never die on redirects! */ 1299
1248 alarm (0); 1300 } /* end else (server_expect_yn) */
1249 1301
1250 if (maximum_age >= 0) { 1302 /* reset the alarm - must be called *after* redir or we'll never die on redirects! */
1251 result = max_state_alt(check_document_dates(header, &msg), result); 1303 alarm(0);
1252 } 1304
1253 1305 if (maximum_age >= 0) {
1254 /* Page and Header content checks go here */ 1306 result = max_state_alt(check_document_dates(header, &msg), result);
1255 if (strlen(header_expect) > 0) { 1307 }
1256 if (strstr(header, header_expect) == NULL) { 1308
1257 // We did not find the header, the rest is for building the output and setting the state 1309 /* Page and Header content checks go here */
1258 char output_header_search[30] = ""; 1310 if (strlen(header_expect) > 0) {
1259 1311 if (strstr(header, header_expect) == NULL) {
1260 strncpy(&output_header_search[0], header_expect, 1312 // We did not find the header, the rest is for building the output and setting the state
1261 sizeof(output_header_search)); 1313 char output_header_search[30] = "";
1262 1314
1263 if (output_header_search[sizeof(output_header_search) - 1] != '\0') { 1315 strncpy(&output_header_search[0], header_expect, sizeof(output_header_search));
1264 bcopy("...", 1316
1265 &output_header_search[sizeof(output_header_search) - 4], 1317 if (output_header_search[sizeof(output_header_search) - 1] != '\0') {
1266 4); 1318 bcopy("...", &output_header_search[sizeof(output_header_search) - 4], 4);
1267 } 1319 }
1268 1320
1269 xasprintf (&msg, 1321 xasprintf(&msg, _("%sheader '%s' not found on '%s://%s:%d%s', "), msg,
1270 _("%sheader '%s' not found on '%s://%s:%d%s', "), 1322 output_header_search, use_ssl ? "https" : "http",
1271 msg, 1323 host_name ? host_name : server_address, server_port, server_url);
1272 output_header_search, use_ssl ? "https" : "http", 1324
1273 host_name ? host_name : server_address, server_port, 1325 result = STATE_CRITICAL;
1274 server_url); 1326 }
1275 1327 }
1276 result = STATE_CRITICAL; 1328
1277 } 1329 // At this point we should test if the content is chunked and unchunk it, so
1278 } 1330 // it can be searched (and possibly printed)
1279 1331 const char *chunked_header_regex_string = "Transfer-Encoding: *chunked *";
1280 // At this point we should test if the content is chunked and unchunk it, so 1332 regex_t chunked_header_regex;
1281 // it can be searched (and possibly printed) 1333
1282 const char *chunked_header_regex_string = "Transfer-Encoding: *chunked *"; 1334 if (regcomp(&chunked_header_regex, chunked_header_regex_string, REG_ICASE)) {
1283 regex_t chunked_header_regex; 1335 die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN),
1284 1336 "Failed to compile chunked_header_regex regex");
1285 if (regcomp(&chunked_header_regex, chunked_header_regex_string, REG_ICASE)) { 1337 }
1286 die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN), "Failed to compile chunked_header_regex regex"); 1338
1287 } 1339 regmatch_t chre_pmatch[1]; // We actually do not care about this, since we only want to know IF
1288 1340 // it was found
1289 regmatch_t chre_pmatch[1]; // We actually do not care about this, since we only want to know IF it was found 1341
1290 1342 if (!no_body && regexec(&chunked_header_regex, header, 1, chre_pmatch, 0) == 0) {
1291 if (!no_body && regexec(&chunked_header_regex, header, 1, chre_pmatch, 0) == 0) { 1343 if (verbose) {
1292 if (verbose) { 1344 printf("Found chunked content\n");
1293 printf("Found chunked content\n"); 1345 }
1294 } 1346 // We actually found the chunked header
1295 // We actually found the chunked header 1347 char *tmp = unchunk_content(page);
1296 char *tmp = unchunk_content(page); 1348 if (tmp == NULL) {
1297 if (tmp == NULL) { 1349 die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN),
1298 die(STATE_UNKNOWN, "HTTP %s: %s\n", state_text(STATE_UNKNOWN), "Failed to unchunk message body"); 1350 "Failed to unchunk message body");
1299 } 1351 }
1300 page = tmp; 1352 page = tmp;
1301 } 1353 }
1302 1354
1303 if (strlen(string_expect) > 0) { 1355 if (strlen(string_expect) > 0) {
1304 if (!strstr(page, string_expect)) { 1356 if (!strstr(page, string_expect)) {
1305 // We found the string the body, the rest is for building the output 1357 // We found the string the body, the rest is for building the output
1306 char output_string_search[30] = ""; 1358 char output_string_search[30] = "";
1307 strncpy(&output_string_search[0], string_expect, 1359 strncpy(&output_string_search[0], string_expect, sizeof(output_string_search));
1308 sizeof(output_string_search)); 1360 if (output_string_search[sizeof(output_string_search) - 1] != '\0') {
1309 if (output_string_search[sizeof(output_string_search) - 1] != '\0') { 1361 bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 4);
1310 bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 1362 }
1311 4); 1363 xasprintf(&msg, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg,
1312 } 1364 output_string_search, use_ssl ? "https" : "http",
1313 xasprintf (&msg, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg, output_string_search, use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url); 1365 host_name ? host_name : server_address, server_port, server_url);
1314 result = STATE_CRITICAL; 1366 result = STATE_CRITICAL;
1315 } 1367 }
1316 } 1368 }
1317 1369
1318 if (strlen(regexp) > 0) { 1370 if (strlen(regexp) > 0) {
1319 errcode = regexec(&preg, page, REGS, pmatch, 0); 1371 errcode = regexec(&preg, page, REGS, pmatch, 0);
1320 if ((errcode == 0 && invert_regex == 0) || 1372 if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) {
1321 (errcode == REG_NOMATCH && invert_regex == 1)) { 1373 /* OK - No-op to avoid changing the logic around it */
1322 /* OK - No-op to avoid changing the logic around it */ 1374 result = max_state_alt(STATE_OK, result);
1323 result = max_state_alt(STATE_OK, result); 1375 } else if ((errcode == REG_NOMATCH && invert_regex == 0) ||
1324 } 1376 (errcode == 0 && invert_regex == 1)) {
1325 else if ((errcode == REG_NOMATCH && invert_regex == 0) || (errcode == 0 && invert_regex == 1)) { 1377 if (invert_regex == 0) {
1326 if (invert_regex == 0) 1378 xasprintf(&msg, _("%spattern not found, "), msg);
1327 xasprintf (&msg, _("%spattern not found, "), msg); 1379 } else {
1328 else 1380 xasprintf(&msg, _("%spattern found, "), msg);
1329 xasprintf (&msg, _("%spattern found, "), msg); 1381 }
1330 result = state_regex; 1382 result = state_regex;
1331 } 1383 } else {
1332 else { 1384 /* FIXME: Shouldn't that be UNKNOWN? */
1333 /* FIXME: Shouldn't that be UNKNOWN? */ 1385 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1334 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1386 xasprintf(&msg, _("%sExecute Error: %s, "), msg, errbuf);
1335 xasprintf (&msg, _("%sExecute Error: %s, "), msg, errbuf); 1387 result = STATE_CRITICAL;
1336 result = STATE_CRITICAL; 1388 }
1337 } 1389 }
1338 } 1390
1339 1391 /* make sure the page is of an appropriate size */
1340 /* make sure the page is of an appropriate size */ 1392 /* page_len = get_content_length(header); */
1341 /* page_len = get_content_length(header); */ 1393 /* FIXME: Will this work with -N ? IMHO we should use
1342 /* FIXME: Will this work with -N ? IMHO we should use 1394 * get_content_length(header) and always check if it's different than the
1343 * get_content_length(header) and always check if it's different than the 1395 * returned pagesize
1344 * returned pagesize 1396 */
1345 */ 1397 /* FIXME: IIRC pagesize returns headers - shouldn't we make
1346 /* FIXME: IIRC pagesize returns headers - shouldn't we make 1398 * it == get_content_length(header) ??
1347 * it == get_content_length(header) ?? 1399 */
1348 */ 1400 page_len = pagesize;
1349 page_len = pagesize; 1401 if ((max_page_len > 0) && (page_len > max_page_len)) {
1350 if ((max_page_len > 0) && (page_len > max_page_len)) { 1402 xasprintf(&msg, _("%spage size %d too large, "), msg, page_len);
1351 xasprintf (&msg, _("%spage size %d too large, "), msg, page_len); 1403 result = max_state_alt(STATE_WARNING, result);
1352 result = max_state_alt(STATE_WARNING, result); 1404 } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1353 } else if ((min_page_len > 0) && (page_len < min_page_len)) { 1405 xasprintf(&msg, _("%spage size %d too small, "), msg, page_len);
1354 xasprintf (&msg, _("%spage size %d too small, "), msg, page_len); 1406 result = max_state_alt(STATE_WARNING, result);
1355 result = max_state_alt(STATE_WARNING, result); 1407 }
1356 } 1408
1357 1409 /* Cut-off trailing characters */
1358 /* Cut-off trailing characters */ 1410 if (msg[strlen(msg) - 2] == ',') {
1359 if(msg[strlen(msg)-2] == ',') 1411 msg[strlen(msg) - 2] = '\0';
1360 msg[strlen(msg)-2] = '\0'; 1412 } else {
1361 else 1413 msg[strlen(msg) - 3] = '\0';
1362 msg[strlen(msg)-3] = '\0'; 1414 }
1363 1415
1364 /* check elapsed time */ 1416 /* check elapsed time */
1365 if (show_extended_perfdata) 1417 if (show_extended_perfdata) {
1366 xasprintf (&msg, 1418 xasprintf(
1367 _("%s - %d bytes in %.3f second response time %s|%s %s %s %s %s %s %s"), 1419 &msg, _("%s - %d bytes in %.3f second response time %s|%s %s %s %s %s %s %s"), msg,
1368 msg, page_len, elapsed_time, 1420 page_len, elapsed_time, (display_html ? "</A>" : ""), perfd_time(elapsed_time),
1369 (display_html ? "</A>" : ""), 1421 perfd_size(page_len), perfd_time_connect(elapsed_time_connect),
1370 perfd_time (elapsed_time), 1422 use_ssl ? perfd_time_ssl(elapsed_time_ssl) : "",
1371 perfd_size (page_len), 1423 perfd_time_headers(elapsed_time_headers), perfd_time_firstbyte(elapsed_time_firstbyte),
1372 perfd_time_connect (elapsed_time_connect), 1424 perfd_time_transfer(elapsed_time_transfer));
1373 use_ssl == true ? perfd_time_ssl (elapsed_time_ssl) : "", 1425 } else {
1374 perfd_time_headers (elapsed_time_headers), 1426 xasprintf(&msg, _("%s - %d bytes in %.3f second response time %s|%s %s"), msg, page_len,
1375 perfd_time_firstbyte (elapsed_time_firstbyte), 1427 elapsed_time, (display_html ? "</A>" : ""), perfd_time(elapsed_time),
1376 perfd_time_transfer (elapsed_time_transfer)); 1428 perfd_size(page_len));
1377 else 1429 }
1378 xasprintf (&msg, 1430
1379 _("%s - %d bytes in %.3f second response time %s|%s %s"), 1431 if (show_body) {
1380 msg, page_len, elapsed_time, 1432 xasprintf(&msg, _("%s\n%s"), msg, page);
1381 (display_html ? "</A>" : ""), 1433 }
1382 perfd_time (elapsed_time), 1434
1383 perfd_size (page_len)); 1435 result = max_state_alt(get_status(elapsed_time, thlds), result);
1384 1436
1385 if (show_body) 1437 die(result, "HTTP %s: %s\n", state_text(result), msg);
1386 xasprintf (&msg, _("%s\n%s"), msg, page); 1438 /* die failed? */
1387 1439 return STATE_UNKNOWN;
1388 result = max_state_alt(get_status(elapsed_time, thlds), result);
1389
1390 die (result, "HTTP %s: %s\n", state_text(result), msg);
1391 /* die failed? */
1392 return STATE_UNKNOWN;
1393} 1440}
1394 1441
1395/* Receivces a pointer to the beginning of the body of a HTTP message 1442/* Receivces a pointer to the beginning of the body of a HTTP message
@@ -1398,94 +1445,95 @@ check_http (void)
1398 * The result must be freed by the caller. 1445 * The result must be freed by the caller.
1399 */ 1446 */
1400char *unchunk_content(const char *content) { 1447char *unchunk_content(const char *content) {
1401 // https://en.wikipedia.org/wiki/Chunked_transfer_encoding 1448 // https://en.wikipedia.org/wiki/Chunked_transfer_encoding
1402 // https://www.rfc-editor.org/rfc/rfc7230#section-4.1 1449 // https://www.rfc-editor.org/rfc/rfc7230#section-4.1
1403 char *result = NULL; 1450 char *result = NULL;
1404 char *start_of_chunk; 1451 char *start_of_chunk;
1405 char* end_of_chunk; 1452 char *end_of_chunk;
1406 long size_of_chunk; 1453 long size_of_chunk;
1407 const char *pointer = content; 1454 const char *pointer = content;
1408 char *endptr; 1455 char *endptr;
1409 long length_of_chunk = 0; 1456 long length_of_chunk = 0;
1410 size_t overall_size = 0; 1457 size_t overall_size = 0;
1411 1458
1412 while (true) { 1459 while (true) {
1413 size_of_chunk = strtol(pointer, &endptr, 16); 1460 size_of_chunk = strtol(pointer, &endptr, 16);
1414 if (size_of_chunk == LONG_MIN || size_of_chunk == LONG_MAX) { 1461 if (size_of_chunk == LONG_MIN || size_of_chunk == LONG_MAX) {
1415 // Apparently underflow or overflow, should not happen 1462 // Apparently underflow or overflow, should not happen
1416 if (verbose) { 1463 if (verbose) {
1417 printf("Got an underflow or overflow from strtol at: %u\n", __LINE__); 1464 printf("Got an underflow or overflow from strtol at: %u\n", __LINE__);
1418 } 1465 }
1419 return NULL; 1466 return NULL;
1420 } 1467 }
1421 if (endptr == pointer) { 1468 if (endptr == pointer) {
1422 // Apparently this was not a number 1469 // Apparently this was not a number
1423 if (verbose) { 1470 if (verbose) {
1424 printf("Chunked content did not start with a number at all (Line: %u)\n", __LINE__); 1471 printf("Chunked content did not start with a number at all (Line: %u)\n", __LINE__);
1425 } 1472 }
1426 return NULL; 1473 return NULL;
1427 } 1474 }
1428 1475
1429 // So, we got the length of the chunk 1476 // So, we got the length of the chunk
1430 if (*endptr == ';') { 1477 if (*endptr == ';') {
1431 // Chunk extension starts here 1478 // Chunk extension starts here
1432 while (*endptr != '\r') { 1479 while (*endptr != '\r') {
1433 endptr++; 1480 endptr++;
1434 } 1481 }
1435 } 1482 }
1436 1483
1437 start_of_chunk = endptr + 2; 1484 start_of_chunk = endptr + 2;
1438 end_of_chunk = start_of_chunk + size_of_chunk; 1485 end_of_chunk = start_of_chunk + size_of_chunk;
1439 length_of_chunk = (long)(end_of_chunk - start_of_chunk); 1486 length_of_chunk = (long)(end_of_chunk - start_of_chunk);
1440 pointer = end_of_chunk + 2; //Next number should be here 1487 pointer = end_of_chunk + 2; // Next number should be here
1441 1488
1442 if (length_of_chunk == 0) { 1489 if (length_of_chunk == 0) {
1443 // Chunk length is 0, so this is the last one 1490 // Chunk length is 0, so this is the last one
1444 break; 1491 break;
1445 } 1492 }
1446 1493
1447 overall_size += length_of_chunk; 1494 overall_size += length_of_chunk;
1448 1495
1449 if (result == NULL) { 1496 if (result == NULL) {
1450 // Size of the chunk plus the ending NULL byte 1497 // Size of the chunk plus the ending NULL byte
1451 result = (char *)malloc(length_of_chunk +1); 1498 result = (char *)malloc(length_of_chunk + 1);
1452 if (result == NULL) { 1499 if (result == NULL) {
1453 if (verbose) { 1500 if (verbose) {
1454 printf("Failed to allocate memory for unchunked body\n"); 1501 printf("Failed to allocate memory for unchunked body\n");
1455 } 1502 }
1456 return NULL; 1503 return NULL;
1457 } 1504 }
1458 } else { 1505 } else {
1459 // Enlarge memory to the new size plus the ending NULL byte 1506 // Enlarge memory to the new size plus the ending NULL byte
1460 void *tmp = realloc(result, overall_size +1); 1507 void *tmp = realloc(result, overall_size + 1);
1461 if (tmp == NULL) { 1508 if (tmp == NULL) {
1462 if (verbose) { 1509 if (verbose) {
1463 printf("Failed to allocate memory for unchunked body\n"); 1510 printf("Failed to allocate memory for unchunked body\n");
1464 } 1511 }
1465 return NULL; 1512 return NULL;
1466 } else { 1513 }
1467 result = tmp; 1514 result = tmp;
1468 } 1515 }
1469 } 1516
1470 1517 memcpy(result + (overall_size - size_of_chunk), start_of_chunk, size_of_chunk);
1471 memcpy(result + (overall_size - size_of_chunk), start_of_chunk, size_of_chunk); 1518 }
1472 } 1519
1473 1520 if (overall_size == 0 && result == NULL) {
1474 if (overall_size == 0 && result == NULL) { 1521 // We might just have received the end chunk without previous content, so result is never
1475 // We might just have received the end chunk without previous content, so result is never allocated 1522 // allocated
1476 result = calloc(1, sizeof(char)); 1523 result = calloc(1, sizeof(char));
1477 // No error handling here, we can only return NULL anyway 1524 // No error handling here, we can only return NULL anyway
1478 } else { 1525 } else {
1479 result[overall_size] = '\0'; 1526 result[overall_size] = '\0';
1480 } 1527 }
1481 return result; 1528 return result;
1482} 1529}
1483 1530
1484/* per RFC 2396 */ 1531/* per RFC 2396 */
1485#define URI_HTTP "%5[HTPShtps]" 1532#define URI_HTTP "%5[HTPShtps]"
1486#define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]" 1533#define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1487#define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */ 1534#define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */
1488#define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]" 1535#define URI_PATH \
1536 "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1489#define HD1 URI_HTTP "://" URI_HOST ":" URI_PORT "/" URI_PATH 1537#define HD1 URI_HTTP "://" URI_HOST ":" URI_PORT "/" URI_PATH
1490#define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH 1538#define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH
1491#define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT 1539#define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT
@@ -1494,414 +1542,431 @@ char *unchunk_content(const char *content) {
1494#define HD5 "//" URI_HOST "/" URI_PATH 1542#define HD5 "//" URI_HOST "/" URI_PATH
1495#define HD6 URI_PATH 1543#define HD6 URI_PATH
1496 1544
1497void 1545void redir(char *pos, char *status_line) {
1498redir (char *pos, char *status_line) 1546 int i = 0;
1499{ 1547 char *x;
1500 int i = 0; 1548 char xx[2];
1501 char *x; 1549 char type[6];
1502 char xx[2]; 1550 char *addr;
1503 char type[6]; 1551 char *url;
1504 char *addr; 1552
1505 char *url; 1553 addr = malloc(MAX_IPV4_HOSTLENGTH + 1);
1506 1554 if (addr == NULL) {
1507 addr = malloc (MAX_IPV4_HOSTLENGTH + 1); 1555 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
1508 if (addr == NULL) 1556 }
1509 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n")); 1557
1510 1558 memset(addr, 0, MAX_IPV4_HOSTLENGTH);
1511 memset(addr, 0, MAX_IPV4_HOSTLENGTH); 1559 url = malloc(strcspn(pos, "\r\n"));
1512 url = malloc (strcspn (pos, "\r\n")); 1560 if (url == NULL) {
1513 if (url == NULL) 1561 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1514 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n")); 1562 }
1515 1563
1516 while (pos) { 1564 while (pos) {
1517 sscanf (pos, "%1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n", xx, &i); 1565 sscanf(pos, "%1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n", xx, &i);
1518 if (i == 0) { 1566 if (i == 0) {
1519 pos += (size_t) strcspn (pos, "\r\n"); 1567 pos += (size_t)strcspn(pos, "\r\n");
1520 pos += (size_t) strspn (pos, "\r\n"); 1568 pos += (size_t)strspn(pos, "\r\n");
1521 if (strlen(pos) == 0) 1569 if (strlen(pos) == 0) {
1522 die (STATE_UNKNOWN, 1570 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"),
1523 _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"), 1571 status_line, (display_html ? "</A>" : ""));
1524 status_line, (display_html ? "</A>" : "")); 1572 }
1525 continue; 1573 continue;
1526 } 1574 }
1527 1575
1528 pos += i; 1576 pos += i;
1529 pos += strspn (pos, " \t"); 1577 pos += strspn(pos, " \t");
1530 1578
1531 /* 1579 /*
1532 * RFC 2616 (4.2): ``Header fields can be extended over multiple lines by 1580 * RFC 2616 (4.2): ``Header fields can be extended over multiple lines by
1533 * preceding each extra line with at least one SP or HT.'' 1581 * preceding each extra line with at least one SP or HT.''
1534 */ 1582 */
1535 for (; (i = strspn (pos, "\r\n")); pos += i) { 1583 for (; (i = strspn(pos, "\r\n")); pos += i) {
1536 pos += i; 1584 pos += i;
1537 if (!(i = strspn (pos, " \t"))) { 1585 if (!(i = strspn(pos, " \t"))) {
1538 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Empty redirect location%s\n"), 1586 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Empty redirect location%s\n"),
1539 display_html ? "</A>" : ""); 1587 display_html ? "</A>" : "");
1540 } 1588 }
1541 } 1589 }
1542 1590
1543 url = realloc (url, strcspn (pos, "\r\n") + 1); 1591 url = realloc(url, strcspn(pos, "\r\n") + 1);
1544 if (url == NULL) 1592 if (url == NULL) {
1545 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n")); 1593 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1546 1594 }
1547 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */ 1595
1548 if (sscanf (pos, HD1, type, addr, &i, url) == 4) { 1596 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1549 url = prepend_slash (url); 1597 if (sscanf(pos, HD1, type, addr, &i, url) == 4) {
1550 use_ssl = server_type_check (type); 1598 url = prepend_slash(url);
1551 } 1599 use_ssl = server_type_check(type);
1552 1600 }
1553 /* URI_HTTP URI_HOST URI_PATH */ 1601
1554 else if (sscanf (pos, HD2, type, addr, url) == 3 ) { 1602 /* URI_HTTP URI_HOST URI_PATH */
1555 url = prepend_slash (url); 1603 else if (sscanf(pos, HD2, type, addr, url) == 3) {
1556 use_ssl = server_type_check (type); 1604 url = prepend_slash(url);
1557 i = server_port_check (use_ssl); 1605 use_ssl = server_type_check(type);
1558 } 1606 i = server_port_check(use_ssl);
1559 1607 }
1560 /* URI_HTTP URI_HOST URI_PORT */ 1608
1561 else if (sscanf (pos, HD3, type, addr, &i) == 3) { 1609 /* URI_HTTP URI_HOST URI_PORT */
1562 strcpy (url, HTTP_URL); 1610 else if (sscanf(pos, HD3, type, addr, &i) == 3) {
1563 use_ssl = server_type_check (type); 1611 strcpy(url, HTTP_URL);
1564 } 1612 use_ssl = server_type_check(type);
1565 1613 }
1566 /* URI_HTTP URI_HOST */ 1614
1567 else if (sscanf (pos, HD4, type, addr) == 2) { 1615 /* URI_HTTP URI_HOST */
1568 strcpy (url, HTTP_URL); 1616 else if (sscanf(pos, HD4, type, addr) == 2) {
1569 use_ssl = server_type_check (type); 1617 strcpy(url, HTTP_URL);
1570 i = server_port_check (use_ssl); 1618 use_ssl = server_type_check(type);
1571 } 1619 i = server_port_check(use_ssl);
1572 /* URI_HTTP, URI_HOST, URI_PATH */ 1620 }
1573 else if (sscanf (pos, HD5, addr, url) == 2) { 1621 /* URI_HTTP, URI_HOST, URI_PATH */
1574 if(use_ssl){ 1622 else if (sscanf(pos, HD5, addr, url) == 2) {
1575 strcpy (type,"https"); 1623 if (use_ssl) {
1576 } 1624 strcpy(type, "https");
1577 else{ 1625 } else {
1578 strcpy (type, server_type); 1626 strcpy(type, server_type);
1579 } 1627 }
1580 xasprintf (&url, "/%s", url); 1628 xasprintf(&url, "/%s", url);
1581 use_ssl = server_type_check (type); 1629 use_ssl = server_type_check(type);
1582 i = server_port_check (use_ssl); 1630 i = server_port_check(use_ssl);
1583 } 1631 }
1584 1632
1585 /* URI_PATH */ 1633 /* URI_PATH */
1586 else if (sscanf (pos, HD6, url) == 1) { 1634 else if (sscanf(pos, HD6, url) == 1) {
1587 /* relative url */ 1635 /* relative url */
1588 if ((url[0] != '/')) { 1636 if ((url[0] != '/')) {
1589 if ((x = strrchr(server_url, '/'))) 1637 if ((x = strrchr(server_url, '/'))) {
1590 *x = '\0'; 1638 *x = '\0';
1591 xasprintf (&url, "%s/%s", server_url, url); 1639 }
1592 } 1640 xasprintf(&url, "%s/%s", server_url, url);
1593 i = server_port; 1641 }
1594 strcpy (type, server_type); 1642 i = server_port;
1595 strcpy (addr, host_name ? host_name : server_address); 1643 strcpy(type, server_type);
1596 } 1644 strcpy(addr, host_name ? host_name : server_address);
1597 1645 }
1598 else { 1646
1599 die (STATE_UNKNOWN, 1647 else {
1600 _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"), 1648 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"), pos,
1601 pos, (display_html ? "</A>" : "")); 1649 (display_html ? "</A>" : ""));
1602 } 1650 }
1603 1651
1604 break; 1652 break;
1605 1653
1606 } /* end while (pos) */ 1654 } /* end while (pos) */
1607 1655
1608 if (++redir_depth > max_depth) 1656 if (++redir_depth > max_depth) {
1609 die (STATE_WARNING, 1657 die(STATE_WARNING,
1610 _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"), 1658 _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"), max_depth,
1611 max_depth, type, addr, i, url, (display_html ? "</A>" : "")); 1659 type, addr, i, url, (display_html ? "</A>" : ""));
1612 1660 }
1613 if (server_port==i && 1661
1614 !strncmp(server_address, addr, MAX_IPV4_HOSTLENGTH) && 1662 if (server_port == i && !strncmp(server_address, addr, MAX_IPV4_HOSTLENGTH) &&
1615 (host_name && !strncmp(host_name, addr, MAX_IPV4_HOSTLENGTH)) && 1663 (host_name && !strncmp(host_name, addr, MAX_IPV4_HOSTLENGTH)) && !strcmp(server_url, url)) {
1616 !strcmp(server_url, url)) 1664 die(STATE_CRITICAL,
1617 die (STATE_CRITICAL, 1665 _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"), type,
1618 _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"), 1666 addr, i, url, (display_html ? "</A>" : ""));
1619 type, addr, i, url, (display_html ? "</A>" : "")); 1667 }
1620 1668
1621 strcpy (server_type, type); 1669 strcpy(server_type, type);
1622 1670
1623 free (host_name); 1671 free(host_name);
1624 host_name = strndup (addr, MAX_IPV4_HOSTLENGTH); 1672 host_name = strndup(addr, MAX_IPV4_HOSTLENGTH);
1625 1673
1626 if (!(followsticky & STICKY_HOST)) { 1674 if (!(followsticky & STICKY_HOST)) {
1627 free (server_address); 1675 free(server_address);
1628 server_address = strndup (addr, MAX_IPV4_HOSTLENGTH); 1676 server_address = strndup(addr, MAX_IPV4_HOSTLENGTH);
1629 } 1677 }
1630 if (!(followsticky & STICKY_PORT)) { 1678 if (!(followsticky & STICKY_PORT)) {
1631 server_port = i; 1679 server_port = i;
1632 } 1680 }
1633 1681
1634 free (server_url); 1682 free(server_url);
1635 server_url = url; 1683 server_url = url;
1636 1684
1637 if (server_port > MAX_PORT) 1685 if (server_port > MAX_PORT) {
1638 die (STATE_UNKNOWN, 1686 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Redirection to port above %d - %s://%s:%d%s%s\n"),
1639 _("HTTP UNKNOWN - Redirection to port above %d - %s://%s:%d%s%s\n"), 1687 MAX_PORT, server_type, server_address, server_port, server_url,
1640 MAX_PORT, server_type, server_address, server_port, server_url, 1688 display_html ? "</A>" : "");
1641 display_html ? "</A>" : ""); 1689 }
1642
1643 /* reset virtual port */
1644 virtual_port = server_port;
1645
1646 if (verbose)
1647 printf (_("Redirection to %s://%s:%d%s\n"), server_type,
1648 host_name ? host_name : server_address, server_port, server_url);
1649
1650 free(addr);
1651 check_http ();
1652}
1653 1690
1691 /* reset virtual port */
1692 virtual_port = server_port;
1654 1693
1655bool 1694 if (verbose) {
1656server_type_check (const char *type) 1695 printf(_("Redirection to %s://%s:%d%s\n"), server_type,
1657{ 1696 host_name ? host_name : server_address, server_port, server_url);
1658 if (strcmp (type, "https")) 1697 }
1659 return false; 1698
1660 else 1699 free(addr);
1661 return true; 1700 check_http();
1662} 1701}
1663 1702
1664int 1703bool server_type_check(const char *type) { return (!(bool)strcmp(type, "https")); }
1665server_port_check (int ssl_flag) 1704
1666{ 1705int server_port_check(int ssl_flag) {
1667 if (ssl_flag) 1706 if (ssl_flag) {
1668 return HTTPS_PORT; 1707 return HTTPS_PORT;
1669 else 1708 }
1670 return HTTP_PORT; 1709 return HTTP_PORT;
1671} 1710}
1672 1711
1673char *perfd_time (double elapsed_time) 1712char *perfd_time(double elapsed_time) {
1674{ 1713 return fperfdata("time", elapsed_time, "s", thlds->warning,
1675 return fperfdata ("time", elapsed_time, "s", 1714 thlds->warning ? thlds->warning->end : 0, thlds->critical,
1676 thlds->warning?true:false, thlds->warning?thlds->warning->end:0, 1715 thlds->critical ? thlds->critical->end : 0, true, 0, true, socket_timeout);
1677 thlds->critical?true:false, thlds->critical?thlds->critical->end:0,
1678 true, 0, true, socket_timeout);
1679} 1716}
1680 1717
1681char *perfd_time_connect (double elapsed_time_connect) 1718char *perfd_time_connect(double elapsed_time_connect) {
1682{ 1719 return fperfdata("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true,
1683 return fperfdata ("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1720 socket_timeout);
1684} 1721}
1685 1722
1686char *perfd_time_ssl (double elapsed_time_ssl) 1723char *perfd_time_ssl(double elapsed_time_ssl) {
1687{ 1724 return fperfdata("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true,
1688 return fperfdata ("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1725 socket_timeout);
1689} 1726}
1690 1727
1691char *perfd_time_headers (double elapsed_time_headers) 1728char *perfd_time_headers(double elapsed_time_headers) {
1692{ 1729 return fperfdata("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true,
1693 return fperfdata ("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1730 socket_timeout);
1694} 1731}
1695 1732
1696char *perfd_time_firstbyte (double elapsed_time_firstbyte) 1733char *perfd_time_firstbyte(double elapsed_time_firstbyte) {
1697{ 1734 return fperfdata("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0,
1698 return fperfdata ("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1735 true, socket_timeout);
1699} 1736}
1700 1737
1701char *perfd_time_transfer (double elapsed_time_transfer) 1738char *perfd_time_transfer(double elapsed_time_transfer) {
1702{ 1739 return fperfdata("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0,
1703 return fperfdata ("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1740 true, socket_timeout);
1704} 1741}
1705 1742
1706char *perfd_size (int page_len) 1743char *perfd_size(int page_len) {
1707{ 1744 return perfdata("size", page_len, "B", (min_page_len > 0), min_page_len, (min_page_len > 0), 0,
1708 return perfdata ("size", page_len, "B", 1745 true, 0, false, 0);
1709 (min_page_len>0?true:false), min_page_len,
1710 (min_page_len>0?true:false), 0,
1711 true, 0, false, 0);
1712} 1746}
1713 1747
1714void 1748void print_help(void) {
1715print_help (void) 1749 print_revision(progname, NP_VERSION);
1716{
1717 print_revision (progname, NP_VERSION);
1718 1750
1719 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 1751 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1720 printf (COPYRIGHT, copyright, email); 1752 printf(COPYRIGHT, copyright, email);
1721 1753
1722 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test")); 1754 printf("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1723 printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for")); 1755 printf("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1724 printf ("%s\n", _("strings and regular expressions, check connection times, and report on")); 1756 printf("%s\n", _("strings and regular expressions, check connection times, and report on"));
1725 printf ("%s\n", _("certificate expiration times.")); 1757 printf("%s\n", _("certificate expiration times."));
1726 1758
1727 printf ("\n\n"); 1759 printf("\n");
1760 printf("%s\n", _("ATTENTION!"));
1761 printf("\n");
1762 printf("%s\n", _("THIS PLUGIN IS DEPRECATED. The functionality was reimplemented by the"));
1763 printf("%s\n", _("check_curl plugin, which can be used as a drop-in replacement. You should"));
1764 printf("%s\n", _("migrate your checks over to check_curl, because check_http is going to be"));
1765 printf("%s\n", _("removed sooner than later. Just replace check_http with check_curl in your"));
1766 printf("%s\n", _("check command definitions."));
1767 printf("%s\n",
1768 _("Report issues to: https://github.com/monitoring-plugins/monitoring-plugins/issues"));
1728 1769
1729 print_usage (); 1770 printf("\n\n");
1771
1772 print_usage();
1730 1773
1731#ifdef HAVE_SSL 1774#ifdef HAVE_SSL
1732 printf (_("In the first form, make an HTTP request.")); 1775 printf(_("In the first form, make an HTTP request."));
1733 printf (_("In the second form, connect to the server and check the TLS certificate.")); 1776 printf(_("In the second form, connect to the server and check the TLS certificate."));
1734#endif 1777#endif
1735 printf (_("NOTE: One or both of -H and -I must be specified")); 1778 printf(_("NOTE: One or both of -H and -I must be specified"));
1736 1779
1737 printf ("\n"); 1780 printf("\n");
1738 1781
1739 printf (UT_HELP_VRSN); 1782 printf(UT_HELP_VRSN);
1740 printf (UT_EXTRA_OPTS); 1783 printf(UT_EXTRA_OPTS);
1741 1784
1742 printf (" %s\n", "-H, --hostname=ADDRESS"); 1785 printf(" %s\n", "-H, --hostname=ADDRESS");
1743 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)")); 1786 printf(" %s\n", _("Host name argument for servers using host headers (virtual host)"));
1744 printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)")); 1787 printf(" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1745 printf (" %s\n", "-I, --IP-address=ADDRESS"); 1788 printf(" %s\n", "-I, --IP-address=ADDRESS");
1746 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup).")); 1789 printf(" %s\n",
1747 printf (" %s\n", "-p, --port=INTEGER"); 1790 _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1748 printf (" %s", _("Port number (default: ")); 1791 printf(" %s\n", "-p, --port=INTEGER");
1749 printf ("%d)\n", HTTP_PORT); 1792 printf(" %s", _("Port number (default: "));
1793 printf("%d)\n", HTTP_PORT);
1750 1794
1751 printf (UT_IPv46); 1795 printf(UT_IPv46);
1752 1796
1753#ifdef HAVE_SSL 1797#ifdef HAVE_SSL
1754 printf (" %s\n", "-S, --ssl=VERSION[+]"); 1798 printf(" %s\n", "-S, --ssl=VERSION[+]");
1755 printf (" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents")); 1799 printf(" %s\n",
1756 printf (" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,")); 1800 _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents"));
1757 printf (" %s\n", _("1.2 = TLSv1.2). With a '+' suffix, newer versions are also accepted.")); 1801 printf(" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,"));
1758 printf (" %s\n", "--sni"); 1802 printf(" %s\n", _("1.2 = TLSv1.2). With a '+' suffix, newer versions are also accepted."));
1759 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)")); 1803 printf(" %s\n", "--sni");
1760 printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]"); 1804 printf(" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
1761 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443")); 1805 printf(" %s\n", "-C, --certificate=INTEGER[,INTEGER]");
1762 printf (" %s\n", _("(when this option is used the URL is not checked by default. You can use")); 1806 printf(" %s\n",
1763 printf (" %s\n", _(" --continue-after-certificate to override this behavior)")); 1807 _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1764 printf (" %s\n", "--continue-after-certificate"); 1808 printf(" %s\n",
1765 printf (" %s\n", _("Allows the HTTP check to continue after performing the certificate check.")); 1809 _("(when this option is used the URL is not checked by default. You can use"));
1766 printf (" %s\n", _("Does nothing unless -C is used.")); 1810 printf(" %s\n", _(" --continue-after-certificate to override this behavior)"));
1767 printf (" %s\n", "-J, --client-cert=FILE"); 1811 printf(" %s\n", "--continue-after-certificate");
1768 printf (" %s\n", _("Name of file that contains the client certificate (PEM format)")); 1812 printf(" %s\n",
1769 printf (" %s\n", _("to be used in establishing the SSL session")); 1813 _("Allows the HTTP check to continue after performing the certificate check."));
1770 printf (" %s\n", "-K, --private-key=FILE"); 1814 printf(" %s\n", _("Does nothing unless -C is used."));
1771 printf (" %s\n", _("Name of file containing the private key (PEM format)")); 1815 printf(" %s\n", "-J, --client-cert=FILE");
1772 printf (" %s\n", _("matching the client certificate")); 1816 printf(" %s\n", _("Name of file that contains the client certificate (PEM format)"));
1817 printf(" %s\n", _("to be used in establishing the SSL session"));
1818 printf(" %s\n", "-K, --private-key=FILE");
1819 printf(" %s\n", _("Name of file containing the private key (PEM format)"));
1820 printf(" %s\n", _("matching the client certificate"));
1773#endif 1821#endif
1774 1822
1775 printf (" %s\n", "-e, --expect=STRING"); 1823 printf(" %s\n", "-e, --expect=STRING");
1776 printf (" %s\n", _("Comma-delimited list of strings, at least one of them is expected in")); 1824 printf(" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
1777 printf (" %s", _("the first (status) line of the server response (default: ")); 1825 printf(" %s", _("the first (status) line of the server response (default: "));
1778 printf ("%s)\n", HTTP_EXPECT); 1826 printf("%s)\n", HTTP_EXPECT);
1779 printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)")); 1827 printf(" %s\n",
1780 printf (" %s\n", "-d, --header-string=STRING"); 1828 _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1781 printf (" %s\n", _("String to expect in the response headers")); 1829 printf(" %s\n", "-d, --header-string=STRING");
1782 printf (" %s\n", "-s, --string=STRING"); 1830 printf(" %s\n", _("String to expect in the response headers"));
1783 printf (" %s\n", _("String to expect in the content")); 1831 printf(" %s\n", "-s, --string=STRING");
1784 printf (" %s\n", "-u, --url=PATH"); 1832 printf(" %s\n", _("String to expect in the content"));
1785 printf (" %s\n", _("URL to GET or POST (default: /)")); 1833 printf(" %s\n", "-u, --url=PATH");
1786 printf (" %s\n", "-P, --post=STRING"); 1834 printf(" %s\n", _("URL to GET or POST (default: /)"));
1787 printf (" %s\n", _("URL decoded http POST data")); 1835 printf(" %s\n", "-P, --post=STRING");
1788 printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT, CONNECT:POST)"); 1836 printf(" %s\n", _("URL decoded http POST data"));
1789 printf (" %s\n", _("Set HTTP method.")); 1837 printf(" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, "
1790 printf (" %s\n", "-N, --no-body"); 1838 "CONNECT, CONNECT:POST)");
1791 printf (" %s\n", _("Don't wait for document body: stop reading after headers.")); 1839 printf(" %s\n", _("Set HTTP method."));
1792 printf (" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)")); 1840 printf(" %s\n", "-N, --no-body");
1793 printf (" %s\n", "-M, --max-age=SECONDS"); 1841 printf(" %s\n", _("Don't wait for document body: stop reading after headers."));
1794 printf (" %s\n", _("Warn if document is more than SECONDS old. the number can also be of")); 1842 printf(" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
1795 printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days.")); 1843 printf(" %s\n", "-M, --max-age=SECONDS");
1796 printf (" %s\n", "-T, --content-type=STRING"); 1844 printf(" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
1797 printf (" %s\n", _("specify Content-Type header media type when POSTing\n")); 1845 printf(" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
1798 1846 printf(" %s\n", "-T, --content-type=STRING");
1799 printf (" %s\n", "-l, --linespan"); 1847 printf(" %s\n", _("specify Content-Type header media type when POSTing\n"));
1800 printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)")); 1848
1801 printf (" %s\n", "-r, --regex, --ereg=STRING"); 1849 printf(" %s\n", "-l, --linespan");
1802 printf (" %s\n", _("Search page for regex STRING")); 1850 printf(" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
1803 printf (" %s\n", "-R, --eregi=STRING"); 1851 printf(" %s\n", "-r, --regex, --ereg=STRING");
1804 printf (" %s\n", _("Search page for case-insensitive regex STRING")); 1852 printf(" %s\n", _("Search page for regex STRING"));
1805 printf (" %s\n", "--invert-regex"); 1853 printf(" %s\n", "-R, --eregi=STRING");
1806 printf (" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)")); 1854 printf(" %s\n", _("Search page for case-insensitive regex STRING"));
1807 printf (" %s\n", _("can be changed with --state--regex)")); 1855 printf(" %s\n", "--invert-regex");
1808 printf (" %s\n", "--regex-state=STATE"); 1856 printf(" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)"));
1809 printf (" %s\n", _("Return STATE if regex is found, OK if not\n")); 1857 printf(" %s\n", _("can be changed with --state--regex)"));
1810 1858 printf(" %s\n", "--state-regex=STATE");
1811 printf (" %s\n", "-a, --authorization=AUTH_PAIR"); 1859 printf(" %s\n", _("Return STATE if regex is found, OK if not\n"));
1812 printf (" %s\n", _("Username:password on sites with basic authentication")); 1860
1813 printf (" %s\n", "-b, --proxy-authorization=AUTH_PAIR"); 1861 printf(" %s\n", "-a, --authorization=AUTH_PAIR");
1814 printf (" %s\n", _("Username:password on proxy-servers with basic authentication")); 1862 printf(" %s\n", _("Username:password on sites with basic authentication"));
1815 printf (" %s\n", "-A, --useragent=STRING"); 1863 printf(" %s\n", "-b, --proxy-authorization=AUTH_PAIR");
1816 printf (" %s\n", _("String to be sent in http header as \"User Agent\"")); 1864 printf(" %s\n", _("Username:password on proxy-servers with basic authentication"));
1817 printf (" %s\n", "-k, --header=STRING"); 1865 printf(" %s\n", "-A, --useragent=STRING");
1818 printf (" %s\n", _("Any other tags to be sent in http header. Use multiple times for additional headers")); 1866 printf(" %s\n", _("String to be sent in http header as \"User Agent\""));
1819 printf (" %s\n", "-E, --extended-perfdata"); 1867 printf(" %s\n", "-k, --header=STRING");
1820 printf (" %s\n", _("Print additional performance data")); 1868 printf(
1821 printf (" %s\n", "-B, --show-body"); 1869 " %s\n",
1822 printf (" %s\n", _("Print body content below status line")); 1870 _("Any other tags to be sent in http header. Use multiple times for additional headers"));
1823 printf (" %s\n", "-L, --link"); 1871 printf(" %s\n", "-E, --extended-perfdata");
1824 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)")); 1872 printf(" %s\n", _("Print additional performance data"));
1825 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport>"); 1873 printf(" %s\n", "-B, --show-body");
1826 printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the")); 1874 printf(" %s\n", _("Print body content below status line"));
1827 printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same.")); 1875 printf(" %s\n", "-L, --link");
1828 printf (" %s\n", "--max-redirs=INTEGER"); 1876 printf(" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1829 printf (" %s", _("Maximal number of redirects (default: ")); 1877 printf(" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport>");
1830 printf ("%d)\n", DEFAULT_MAX_REDIRS); 1878 printf(" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
1831 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>"); 1879 printf(" %s\n", _("specified IP address. stickyport also ensures port stays the same."));
1832 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)")); 1880 printf(" %s\n", "--max-redirs=INTEGER");
1833 printf (UT_WARN_CRIT); 1881 printf(" %s", _("Maximal number of redirects (default: "));
1834 1882 printf("%d)\n", DEFAULT_MAX_REDIRS);
1835 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 1883 printf(" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1836 1884 printf(" %s\n",
1837 printf (UT_VERBOSE); 1885 _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1838 1886 printf(UT_WARN_CRIT);
1839 printf ("\n"); 1887
1840 printf ("%s\n", _("Notes:")); 1888 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1841 printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host.")); 1889
1842 printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL")); 1890 printf(UT_VERBOSE);
1843 printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response")); 1891
1844 printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are")); 1892 printf("\n");
1845 printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN")); 1893 printf("%s\n", _("Notes:"));
1846 printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument.")); 1894 printf(" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
1895 printf(" %s\n",
1896 _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
1897 printf(" %s\n",
1898 _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response"));
1899 printf(" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
1900 printf(" %s\n",
1901 _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
1902 printf(" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
1847 1903
1848#ifdef HAVE_SSL 1904#ifdef HAVE_SSL
1849 printf ("\n"); 1905 printf("\n");
1850 printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to")); 1906 printf(" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
1851 printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 ")); 1907 printf(" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
1852 printf (" %s\n", _("certificate is still valid for the specified number of days.")); 1908 printf(" %s\n", _("certificate is still valid for the specified number of days."));
1853 printf ("\n"); 1909 printf("\n");
1854 printf (" %s\n", _("Please note that this plugin does not check if the presented server")); 1910 printf(" %s\n", _("Please note that this plugin does not check if the presented server"));
1855 printf (" %s\n", _("certificate matches the hostname of the server, or if the certificate")); 1911 printf(" %s\n", _("certificate matches the hostname of the server, or if the certificate"));
1856 printf (" %s\n", _("has a valid chain of trust to one of the locally installed CAs.")); 1912 printf(" %s\n", _("has a valid chain of trust to one of the locally installed CAs."));
1857 printf ("\n"); 1913 printf("\n");
1858 printf ("%s\n", _("Examples:")); 1914 printf("%s\n", _("Examples:"));
1859 printf (" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com"); 1915 printf(" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com");
1860 printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,")); 1916 printf(" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
1861 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds")); 1917 printf(" %s\n",
1862 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,")); 1918 _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1863 printf (" %s\n", _("a STATE_CRITICAL will be returned.")); 1919 printf(" %s\n",
1864 printf ("\n"); 1920 _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1865 printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14"); 1921 printf(" %s\n", _("a STATE_CRITICAL will be returned."));
1866 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,")); 1922 printf("\n");
1867 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than")); 1923 printf(" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14");
1868 printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when")); 1924 printf(" %s\n",
1869 printf (" %s\n\n", _("the certificate is expired.")); 1925 _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
1870 printf ("\n"); 1926 printf(" %s\n",
1871 printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 30,14"); 1927 _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1872 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 30 days,")); 1928 printf(" %s\n",
1873 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than")); 1929 _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
1874 printf (" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned.")); 1930 printf(" %s\n\n", _("the certificate is expired."));
1875 printf (" %s\n", _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days")); 1931 printf("\n");
1876 1932 printf(" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 30,14");
1877 printf (" %s\n\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: "); 1933 printf(" %s\n",
1878 printf (" %s\n", _("check_http -I 192.168.100.35 -p 80 -u https://www.verisign.com/ -S -j CONNECT -H www.verisign.com ")); 1934 _("When the certificate of 'www.verisign.com' is valid for more than 30 days,"));
1879 printf (" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> -S(sl) -j CONNECT -H <webserver>")); 1935 printf(" %s\n",
1880 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds")); 1936 _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1881 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,")); 1937 printf(" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned."));
1882 printf (" %s\n", _("a STATE_CRITICAL will be returned. By adding a colon to the method you can set the method used")); 1938 printf(" %s\n",
1883 printf (" %s\n", _("inside the proxied connection: -j CONNECT:POST")); 1939 _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days"));
1940
1941 printf(" %s\n\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: ");
1942 printf(" %s\n", _("check_http -I 192.168.100.35 -p 80 -u https://www.verisign.com/ -S -j "
1943 "CONNECT -H www.verisign.com "));
1944 printf(" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> "
1945 "-S(sl) -j CONNECT -H <webserver>"));
1946 printf(" %s\n",
1947 _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1948 printf(" %s\n",
1949 _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1950 printf(" %s\n", _("a STATE_CRITICAL will be returned. By adding a colon to the method you can "
1951 "set the method used"));
1952 printf(" %s\n", _("inside the proxied connection: -j CONNECT:POST"));
1884 1953
1885#endif 1954#endif
1886 1955
1887 printf (UT_SUPPORT); 1956 printf(UT_SUPPORT);
1888
1889} 1957}
1890 1958
1891 1959void print_usage(void) {
1892 1960 printf("%s\n", _("Usage:"));
1893void 1961 printf(" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n", progname);
1894print_usage (void) 1962 printf(" [-J <client certificate file>] [-K <private key>]\n");
1895{ 1963 printf(" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n");
1896 printf ("%s\n", _("Usage:")); 1964 printf(" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport>]\n");
1897 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname); 1965 printf(" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive "
1898 printf (" [-J <client certificate file>] [-K <private key>]\n"); 1966 "regex>]\n");
1899 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n"); 1967 printf(" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
1900 printf (" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport>]\n"); 1968 printf(" [-A string] [-k string] [-S <version>] [--sni]\n");
1901 printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n"); 1969 printf(" [-T <content-type>] [-j method]\n");
1902 printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n"); 1970 printf(" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n", progname);
1903 printf (" [-A string] [-k string] [-S <version>] [--sni]\n"); 1971 printf(" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n");
1904 printf (" [-T <content-type>] [-j method]\n");
1905 printf (" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n",progname);
1906 printf (" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n");
1907} 1972}
diff --git a/plugins/check_ide_smart.c b/plugins/check_ide_smart.c
index 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..77a33304 100644
--- a/plugins/check_ldap.c
+++ b/plugins/check_ldap.c
@@ -1,242 +1,216 @@
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) !=
147 LDAP_OPT_SUCCESS ) { 112 LDAP_OPT_SUCCESS) {
148 printf(_("Could not set protocol version %d\n"), ld_protocol); 113 printf(_("Could not set protocol version %d\n"), config.ld_protocol);
149 return STATE_CRITICAL; 114 return STATE_CRITICAL;
150 } 115 }
151#endif 116#endif
152 117
153 if (ld_port == LDAPS_PORT || ssl_on_connect) { 118 int version = 3;
154 xasprintf (&SERVICE, "LDAPS"); 119 int tls;
120 if (config.ld_port == LDAPS_PORT || config.ssl_on_connect) {
155#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS) 121#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)
156 /* ldaps: set option tls */ 122 /* ldaps: set option tls */
157 tls = LDAP_OPT_X_TLS_HARD; 123 tls = LDAP_OPT_X_TLS_HARD;
158 124
159 if (ldap_set_option (ld, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS) 125 if (ldap_set_option(ldap_connection, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS) {
160 { 126 if (verbose) {
161 if (verbose) 127 ldap_perror(ldap_connection, "ldaps_option");
162 ldap_perror(ld, "ldaps_option"); 128 }
163 printf (_("Could not init TLS at port %i!\n"), ld_port); 129 printf(_("Could not init TLS at port %i!\n"), config.ld_port);
164 return STATE_CRITICAL; 130 return STATE_CRITICAL;
165 } 131 }
166#else 132#else
167 printf (_("TLS not supported by the libraries!\n")); 133 printf(_("TLS not supported by the libraries!\n"));
168 return STATE_CRITICAL; 134 return STATE_CRITICAL;
169#endif /* LDAP_OPT_X_TLS */ 135#endif /* LDAP_OPT_X_TLS */
170 } else if (starttls) { 136 } else if (config.starttls) {
171 xasprintf (&SERVICE, "LDAP-TLS");
172#if defined(HAVE_LDAP_SET_OPTION) && defined(HAVE_LDAP_START_TLS_S) 137#if defined(HAVE_LDAP_SET_OPTION) && defined(HAVE_LDAP_START_TLS_S)
173 /* ldap with startTLS: set option version */ 138 /* ldap with startTLS: set option version */
174 if (ldap_get_option(ld,LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS ) 139 if (ldap_get_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version) ==
175 { 140 LDAP_OPT_SUCCESS) {
176 if (version < LDAP_VERSION3) 141 if (version < LDAP_VERSION3) {
177 {
178 version = LDAP_VERSION3; 142 version = LDAP_VERSION3;
179 ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version); 143 ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version);
180 } 144 }
181 } 145 }
182 /* call start_tls */ 146 /* call start_tls */
183 if (ldap_start_tls_s(ld, NULL, NULL) != LDAP_SUCCESS) 147 if (ldap_start_tls_s(ldap_connection, NULL, NULL) != LDAP_SUCCESS) {
184 { 148 if (verbose) {
185 if (verbose) 149 ldap_perror(ldap_connection, "ldap_start_tls");
186 ldap_perror(ld, "ldap_start_tls"); 150 }
187 printf (_("Could not init startTLS at port %i!\n"), ld_port); 151 printf(_("Could not init startTLS at port %i!\n"), config.ld_port);
188 return STATE_CRITICAL; 152 return STATE_CRITICAL;
189 } 153 }
190#else 154#else
191 printf (_("startTLS not supported by the library, needs LDAPv3!\n")); 155 printf(_("startTLS not supported by the library, needs LDAPv3!\n"));
192 return STATE_CRITICAL; 156 return STATE_CRITICAL;
193#endif /* HAVE_LDAP_START_TLS_S */ 157#endif /* HAVE_LDAP_START_TLS_S */
194 } 158 }
195 159
196 /* bind to the ldap server */ 160 /* bind to the ldap server */
197 if (ldap_bind_s (ld, ld_binddn, ld_passwd, LDAP_AUTH_SIMPLE) != 161 if (ldap_bind_s(ldap_connection, config.ld_binddn, config.ld_passwd, LDAP_AUTH_SIMPLE) !=
198 LDAP_SUCCESS) { 162 LDAP_SUCCESS) {
199 if (verbose) 163 if (verbose) {
200 ldap_perror(ld, "ldap_bind"); 164 ldap_perror(ldap_connection, "ldap_bind");
201 printf (_("Could not bind to the LDAP server\n")); 165 }
166 printf(_("Could not bind to the LDAP server\n"));
202 return STATE_CRITICAL; 167 return STATE_CRITICAL;
203 } 168 }
204 169
170 LDAPMessage *result;
171 int num_entries = 0;
205 /* do a search of all objectclasses in the base dn */ 172 /* 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) 173 if (ldap_search_s(ldap_connection, config.ld_base,
207 != LDAP_SUCCESS) { 174 (config.crit_entries != NULL || config.warn_entries != NULL)
208 if (verbose) 175 ? LDAP_SCOPE_SUBTREE
209 ldap_perror(ld, "ldap_search"); 176 : LDAP_SCOPE_BASE,
210 printf (_("Could not search/find objectclasses in %s\n"), ld_base); 177 config.ld_attr, NULL, 0, &result) != LDAP_SUCCESS) {
178 if (verbose) {
179 ldap_perror(ldap_connection, "ldap_search");
180 }
181 printf(_("Could not search/find objectclasses in %s\n"), config.ld_base);
211 return STATE_CRITICAL; 182 return STATE_CRITICAL;
212 } else if (crit_entries!=NULL || warn_entries!=NULL) { 183 }
213 num_entries = ldap_count_entries(ld, result); 184
185 if (config.crit_entries != NULL || config.warn_entries != NULL) {
186 num_entries = ldap_count_entries(ldap_connection, result);
214 } 187 }
215 188
216 /* unbind from the ldap server */ 189 /* unbind from the ldap server */
217 ldap_unbind (ld); 190 ldap_unbind(ldap_connection);
218 191
219 /* reset the alarm handler */ 192 /* reset the alarm handler */
220 alarm (0); 193 alarm(0);
221 194
222 /* calculate the elapsed time and compare to thresholds */ 195 /* calculate the elapsed time and compare to thresholds */
223 196
224 microsec = deltime (tv); 197 long microsec = deltime(start_time);
225 elapsed_time = (double)microsec / 1.0e6; 198 double elapsed_time = (double)microsec / 1.0e6;
226 199 mp_state_enum status = STATE_UNKNOWN;
227 if (crit_time!=UNDEFINED && elapsed_time>crit_time) 200 if (config.crit_time_set && elapsed_time > config.crit_time) {
228 status = STATE_CRITICAL; 201 status = STATE_CRITICAL;
229 else if (warn_time!=UNDEFINED && elapsed_time>warn_time) 202 } else if (config.warn_time_set && elapsed_time > config.warn_time) {
230 status = STATE_WARNING; 203 status = STATE_WARNING;
231 else 204 } else {
232 status = STATE_OK; 205 status = STATE_OK;
206 }
233 207
234 if(entries_thresholds != NULL) { 208 if (config.entries_thresholds != NULL) {
235 if (verbose) { 209 if (verbose) {
236 printf ("entries found: %d\n", num_entries); 210 printf("entries found: %d\n", num_entries);
237 print_thresholds("entry thresholds", entries_thresholds); 211 print_thresholds("entry thresholds", config.entries_thresholds);
238 } 212 }
239 status_entries = get_status(num_entries, entries_thresholds); 213 mp_state_enum status_entries = get_status(num_entries, config.entries_thresholds);
240 if (status_entries == STATE_CRITICAL) { 214 if (status_entries == STATE_CRITICAL) {
241 status = STATE_CRITICAL; 215 status = STATE_CRITICAL;
242 } else if (status != STATE_CRITICAL) { 216 } else if (status != STATE_CRITICAL) {
@@ -245,273 +219,281 @@ main (int argc, char *argv[])
245 } 219 }
246 220
247 /* print out the result */ 221 /* print out the result */
248 if (crit_entries!=NULL || warn_entries!=NULL) { 222 if (config.crit_entries != NULL || config.warn_entries != NULL) {
249 printf (_("LDAP %s - found %d entries in %.3f seconds|%s %s\n"), 223 printf(_("LDAP %s - found %d entries in %.3f seconds|%s %s\n"), state_text(status),
250 state_text (status), 224 num_entries, elapsed_time,
251 num_entries, 225 fperfdata("time", elapsed_time, "s", config.warn_time_set, config.warn_time,
252 elapsed_time, 226 config.crit_time_set, config.crit_time, true, 0, false, 0),
253 fperfdata ("time", elapsed_time, "s", 227 sperfdata("entries", (double)num_entries, "", config.warn_entries,
254 (int)warn_time, warn_time, 228 config.crit_entries, true, 0.0, false, 0.0));
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 { 229 } else {
262 printf (_("LDAP %s - %.3f seconds response time|%s\n"), 230 printf(_("LDAP %s - %.3f seconds response time|%s\n"), state_text(status), elapsed_time,
263 state_text (status), 231 fperfdata("time", elapsed_time, "s", config.warn_time_set, config.warn_time,
264 elapsed_time, 232 config.crit_time_set, config.crit_time, true, 0, 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 } 233 }
270 234
271 return status; 235 exit(status);
272} 236}
273 237
274/* process command-line arguments */ 238/* process command-line arguments */
275int 239check_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 */ 240 /* initialize the long option struct */
282 static struct option longopts[] = { 241 static struct option longopts[] = {{"help", no_argument, 0, 'h'},
283 {"help", no_argument, 0, 'h'}, 242 {"version", no_argument, 0, 'V'},
284 {"version", no_argument, 0, 'V'}, 243 {"timeout", required_argument, 0, 't'},
285 {"timeout", required_argument, 0, 't'}, 244 {"hostname", required_argument, 0, 'H'},
286 {"hostname", required_argument, 0, 'H'}, 245 {"base", required_argument, 0, 'b'},
287 {"base", required_argument, 0, 'b'}, 246 {"attr", required_argument, 0, 'a'},
288 {"attr", required_argument, 0, 'a'}, 247 {"bind", required_argument, 0, 'D'},
289 {"bind", required_argument, 0, 'D'}, 248 {"pass", required_argument, 0, 'P'},
290 {"pass", required_argument, 0, 'P'},
291#ifdef HAVE_LDAP_SET_OPTION 249#ifdef HAVE_LDAP_SET_OPTION
292 {"ver2", no_argument, 0, '2'}, 250 {"ver2", no_argument, 0, '2'},
293 {"ver3", no_argument, 0, '3'}, 251 {"ver3", no_argument, 0, '3'},
294#endif 252#endif
295 {"starttls", no_argument, 0, 'T'}, 253 {"starttls", no_argument, 0, 'T'},
296 {"ssl", no_argument, 0, 'S'}, 254 {"ssl", no_argument, 0, 'S'},
297 {"use-ipv4", no_argument, 0, '4'}, 255 {"use-ipv4", no_argument, 0, '4'},
298 {"use-ipv6", no_argument, 0, '6'}, 256 {"use-ipv6", no_argument, 0, '6'},
299 {"port", required_argument, 0, 'p'}, 257 {"port", required_argument, 0, 'p'},
300 {"warn", required_argument, 0, 'w'}, 258 {"warn", required_argument, 0, 'w'},
301 {"crit", required_argument, 0, 'c'}, 259 {"crit", required_argument, 0, 'c'},
302 {"warn-entries", required_argument, 0, 'W'}, 260 {"warn-entries", required_argument, 0, 'W'},
303 {"crit-entries", required_argument, 0, 'C'}, 261 {"crit-entries", required_argument, 0, 'C'},
304 {"verbose", no_argument, 0, 'v'}, 262 {"verbose", no_argument, 0, 'v'},
305 {0, 0, 0, 0} 263 {0, 0, 0, 0}};
264
265 check_ldap_config_wrapper result = {
266 .errorcode = OK,
267 .config = check_ldap_config_init(),
306 }; 268 };
307 269
308 if (argc < 2) 270 if (argc < 2) {
309 return ERROR; 271 result.errorcode = ERROR;
272 return result;
273 }
310 274
311 for (c = 1; c < argc; c++) { 275 for (int index = 1; index < argc; index++) {
312 if (strcmp ("-to", argv[c]) == 0) 276 if (strcmp("-to", argv[index]) == 0) {
313 strcpy (argv[c], "-t"); 277 strcpy(argv[index], "-t");
278 }
314 } 279 }
315 280
281 int option = 0;
316 while (true) { 282 while (true) {
317 c = getopt_long (argc, argv, "hvV234TS6t:c:w:H:b:p:a:D:P:C:W:", longopts, &option); 283 int option_index =
284 getopt_long(argc, argv, "hvV234TS6t:c:w:H:b:p:a:D:P:C:W:", longopts, &option);
318 285
319 if (c == -1 || c == EOF) 286 if (option_index == -1 || option_index == EOF) {
320 break; 287 break;
288 }
321 289
322 switch (c) { 290 switch (option_index) {
323 case 'h': /* help */ 291 case 'h': /* help */
324 print_help (); 292 print_help();
325 exit (STATE_UNKNOWN); 293 exit(STATE_UNKNOWN);
326 case 'V': /* version */ 294 case 'V': /* version */
327 print_revision (progname, NP_VERSION); 295 print_revision(progname, NP_VERSION);
328 exit (STATE_UNKNOWN); 296 exit(STATE_UNKNOWN);
329 case 't': /* timeout period */ 297 case 't': /* timeout period */
330 if (!is_intnonneg (optarg)) 298 if (!is_intnonneg(optarg)) {
331 usage2 (_("Timeout interval must be a positive integer"), optarg); 299 usage2(_("Timeout interval must be a positive integer"), optarg);
332 else 300 } else {
333 socket_timeout = atoi (optarg); 301 socket_timeout = atoi(optarg);
302 }
334 break; 303 break;
335 case 'H': 304 case 'H':
336 ld_host = optarg; 305 result.config.ld_host = optarg;
337 break; 306 break;
338 case 'b': 307 case 'b':
339 ld_base = optarg; 308 result.config.ld_base = optarg;
340 break; 309 break;
341 case 'p': 310 case 'p':
342 ld_port = atoi (optarg); 311 result.config.ld_port = atoi(optarg);
343 break; 312 break;
344 case 'a': 313 case 'a':
345 ld_attr = optarg; 314 result.config.ld_attr = optarg;
346 break; 315 break;
347 case 'D': 316 case 'D':
348 ld_binddn = optarg; 317 result.config.ld_binddn = optarg;
349 break; 318 break;
350 case 'P': 319 case 'P':
351 ld_passwd = optarg; 320 result.config.ld_passwd = optarg;
352 break; 321 break;
353 case 'w': 322 case 'w':
354 warn_time = strtod (optarg, NULL); 323 result.config.warn_time_set = true;
324 result.config.warn_time = strtod(optarg, NULL);
355 break; 325 break;
356 case 'c': 326 case 'c':
357 crit_time = strtod (optarg, NULL); 327 result.config.crit_time_set = true;
328 result.config.crit_time = strtod(optarg, NULL);
358 break; 329 break;
359 case 'W': 330 case 'W':
360 warn_entries = optarg; 331 result.config.warn_entries = optarg;
361 break; 332 break;
362 case 'C': 333 case 'C':
363 crit_entries = optarg; 334 result.config.crit_entries = optarg;
364 break; 335 break;
365#ifdef HAVE_LDAP_SET_OPTION 336#ifdef HAVE_LDAP_SET_OPTION
366 case '2': 337 case '2':
367 ld_protocol = 2; 338 result.config.ld_protocol = 2;
368 break; 339 break;
369 case '3': 340 case '3':
370 ld_protocol = 3; 341 result.config.ld_protocol = 3;
371 break; 342 break;
372#endif 343#endif // HAVE_LDAP_SET_OPTION
373 case '4': 344 case '4':
374 address_family = AF_INET; 345 address_family = AF_INET;
375 break; 346 break;
376 case 'v': 347 case 'v':
377 verbose = true; 348 verbose++;
378 break; 349 break;
379 case 'T': 350 case 'T':
380 if (! ssl_on_connect) 351 if (!result.config.ssl_on_connect) {
381 starttls = true; 352 result.config.starttls = true;
382 else 353 } else {
383 usage_va(_("%s cannot be combined with %s"), "-T/--starttls", "-S/--ssl"); 354 usage_va(_("%s cannot be combined with %s"), "-T/--starttls", "-S/--ssl");
355 }
384 break; 356 break;
385 case 'S': 357 case 'S':
386 if (! starttls) { 358 if (!result.config.starttls) {
387 ssl_on_connect = true; 359 result.config.ssl_on_connect = true;
388 if (ld_port == -1) 360 if (result.config.ld_port == -1) {
389 ld_port = LDAPS_PORT; 361 result.config.ld_port = LDAPS_PORT;
390 } else 362 }
363 } else {
391 usage_va(_("%s cannot be combined with %s"), "-S/--ssl", "-T/--starttls"); 364 usage_va(_("%s cannot be combined with %s"), "-S/--ssl", "-T/--starttls");
365 }
392 break; 366 break;
393 case '6': 367 case '6':
394#ifdef USE_IPV6 368#ifdef USE_IPV6
395 address_family = AF_INET6; 369 address_family = AF_INET6;
396#else 370#else
397 usage (_("IPv6 support not available\n")); 371 usage(_("IPv6 support not available\n"));
398#endif 372#endif
399 break; 373 break;
400 default: 374 default:
401 usage5 (); 375 usage5();
402 } 376 }
403 } 377 }
404 378
405 c = optind; 379 int index = optind;
406 if (ld_host == NULL && is_host(argv[c])) 380 if ((result.config.ld_host == NULL) && is_host(argv[index])) {
407 ld_host = strdup (argv[c++]); 381 result.config.ld_host = strdup(argv[index++]);
382 }
408 383
409 if (ld_base == NULL && argv[c]) 384 if ((result.config.ld_base == NULL) && argv[index]) {
410 ld_base = strdup (argv[c++]); 385 result.config.ld_base = strdup(argv[index++]);
386 }
411 387
412 if (ld_port == -1) 388 if (result.config.ld_port == -1) {
413 ld_port = DEFAULT_PORT; 389 result.config.ld_port = DEFAULT_PORT;
390 }
414 391
415 return validate_arguments (); 392 if (strstr(argv[0], "check_ldaps") && !result.config.starttls &&
393 !result.config.ssl_on_connect) {
394 result.config.starttls = true;
395 }
396
397 return validate_arguments(result);
416} 398}
417 399
400check_ldap_config_wrapper validate_arguments(check_ldap_config_wrapper config_wrapper) {
401 if (config_wrapper.config.ld_host == NULL || strlen(config_wrapper.config.ld_host) == 0) {
402 usage4(_("Please specify the host name\n"));
403 }
418 404
419int 405 if (config_wrapper.config.ld_base == NULL) {
420validate_arguments () 406 usage4(_("Please specify the LDAP base\n"));
421{ 407 }
422 if (ld_host==NULL || strlen(ld_host)==0)
423 usage4 (_("Please specify the host name\n"));
424 408
425 if (ld_base==NULL) 409 if (config_wrapper.config.crit_entries != NULL || config_wrapper.config.warn_entries != NULL) {
426 usage4 (_("Please specify the LDAP base\n")); 410 set_thresholds(&config_wrapper.config.entries_thresholds,
411 config_wrapper.config.warn_entries, config_wrapper.config.crit_entries);
412 }
427 413
428 if (crit_entries!=NULL || warn_entries!=NULL) { 414 if (config_wrapper.config.ld_passwd == NULL) {
429 set_thresholds(&entries_thresholds, 415 config_wrapper.config.ld_passwd = getenv("LDAP_PASSWORD");
430 warn_entries, crit_entries);
431 } 416 }
432 if (ld_passwd==NULL)
433 ld_passwd = getenv("LDAP_PASSWORD");
434 417
435 return OK; 418 return config_wrapper;
436} 419}
437 420
438 421void print_help(void) {
439void
440print_help (void)
441{
442 char *myport; 422 char *myport;
443 xasprintf (&myport, "%d", DEFAULT_PORT); 423 xasprintf(&myport, "%d", DEFAULT_PORT);
444 424
445 print_revision (progname, NP_VERSION); 425 print_revision(progname, NP_VERSION);
446 426
447 printf ("Copyright (c) 1999 Didi Rieder (adrieder@sbox.tu-graz.ac.at)\n"); 427 printf("Copyright (c) 1999 Didi Rieder (adrieder@sbox.tu-graz.ac.at)\n");
448 printf (COPYRIGHT, copyright, email); 428 printf(COPYRIGHT, copyright, email);
449 429
450 printf ("\n\n"); 430 printf("\n\n");
451 431
452 print_usage (); 432 print_usage();
453 433
454 printf (UT_HELP_VRSN); 434 printf(UT_HELP_VRSN);
455 printf (UT_EXTRA_OPTS); 435 printf(UT_EXTRA_OPTS);
456 436
457 printf (UT_HOST_PORT, 'p', myport); 437 printf(UT_HOST_PORT, 'p', myport);
458 438
459 printf (UT_IPv46); 439 printf(UT_IPv46);
460 440
461 printf (" %s\n", "-a [--attr]"); 441 printf(" %s\n", "-a [--attr]");
462 printf (" %s\n", _("ldap attribute to search (default: \"(objectclass=*)\"")); 442 printf(" %s\n", _("ldap attribute to search (default: \"(objectclass=*)\""));
463 printf (" %s\n", "-b [--base]"); 443 printf(" %s\n", "-b [--base]");
464 printf (" %s\n", _("ldap base (eg. ou=my unit, o=my org, c=at")); 444 printf(" %s\n", _("ldap base (eg. ou=my unit, o=my org, c=at"));
465 printf (" %s\n", "-D [--bind]"); 445 printf(" %s\n", "-D [--bind]");
466 printf (" %s\n", _("ldap bind DN (if required)")); 446 printf(" %s\n", _("ldap bind DN (if required)"));
467 printf (" %s\n", "-P [--pass]"); 447 printf(" %s\n", "-P [--pass]");
468 printf (" %s\n", _("ldap password (if required, or set the password through environment variable 'LDAP_PASSWORD')")); 448 printf(" %s\n", _("ldap password (if required, or set the password through environment "
469 printf (" %s\n", "-T [--starttls]"); 449 "variable 'LDAP_PASSWORD')"));
470 printf (" %s\n", _("use starttls mechanism introduced in protocol version 3")); 450 printf(" %s\n", "-T [--starttls]");
471 printf (" %s\n", "-S [--ssl]"); 451 printf(" %s\n", _("use starttls mechanism introduced in protocol version 3"));
472 printf (" %s %i\n", _("use ldaps (ldap v2 ssl method). this also sets the default port to"), LDAPS_PORT); 452 printf(" %s\n", "-S [--ssl]");
453 printf(" %s %i\n", _("use ldaps (ldap v2 ssl method). this also sets the default port to"),
454 LDAPS_PORT);
473 455
474#ifdef HAVE_LDAP_SET_OPTION 456#ifdef HAVE_LDAP_SET_OPTION
475 printf (" %s\n", "-2 [--ver2]"); 457 printf(" %s\n", "-2 [--ver2]");
476 printf (" %s\n", _("use ldap protocol version 2")); 458 printf(" %s\n", _("use ldap protocol version 2"));
477 printf (" %s\n", "-3 [--ver3]"); 459 printf(" %s\n", "-3 [--ver3]");
478 printf (" %s\n", _("use ldap protocol version 3")); 460 printf(" %s\n", _("use ldap protocol version 3"));
479 printf (" (%s %d)\n", _("default protocol version:"), DEFAULT_PROTOCOL); 461 printf(" (%s %d)\n", _("default protocol version:"), DEFAULT_PROTOCOL);
480#endif 462#endif
481 463
482 printf (UT_WARN_CRIT); 464 printf(UT_WARN_CRIT);
483 465
484 printf (" %s\n", "-W [--warn-entries]"); 466 printf(" %s\n", "-W [--warn-entries]");
485 printf (" %s\n", _("Number of found entries to result in warning status")); 467 printf(" %s\n", _("Number of found entries to result in warning status"));
486 printf (" %s\n", "-C [--crit-entries]"); 468 printf(" %s\n", "-C [--crit-entries]");
487 printf (" %s\n", _("Number of found entries to result in critical status")); 469 printf(" %s\n", _("Number of found entries to result in critical status"));
488 470
489 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 471 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
490 472
491 printf (UT_VERBOSE); 473 printf(UT_VERBOSE);
492 474
493 printf ("\n"); 475 printf("\n");
494 printf ("%s\n", _("Notes:")); 476 printf("%s\n", _("Notes:"));
495 printf (" %s\n", _("If this plugin is called via 'check_ldaps', method 'STARTTLS' will be")); 477 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); 478 printf(_(" implied (using default port %i) unless --port=636 is specified. In that case\n"),
497 printf (" %s\n", _("'SSL on connect' will be used no matter how the plugin was called.")); 479 DEFAULT_PORT);
498 printf (" %s\n", _("This detection is deprecated, please use 'check_ldap' with the '--starttls' or '--ssl' flags")); 480 printf(" %s\n", _("'SSL on connect' will be used no matter how the plugin was called."));
499 printf (" %s\n", _("to define the behaviour explicitly instead.")); 481 printf(" %s\n", _("This detection is deprecated, please use 'check_ldap' with the '--starttls' "
500 printf (" %s\n", _("The parameters --warn-entries and --crit-entries are optional.")); 482 "or '--ssl' flags"));
483 printf(" %s\n", _("to define the behaviour explicitly instead."));
484 printf(" %s\n", _("The parameters --warn-entries and --crit-entries are optional."));
501 485
502 printf (UT_SUPPORT); 486 printf(UT_SUPPORT);
503} 487}
504 488
505void 489void print_usage(void) {
506print_usage (void) 490 printf("%s\n", _("Usage:"));
507{ 491 printf(" %s -H <host> -b <base_dn> [-p <port>] [-a <attr>] [-D <binddn>]", progname);
508 printf ("%s\n", _("Usage:")); 492 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 493#ifdef HAVE_LDAP_SET_OPTION
512 "\n [-2|-3] [-4|-6]" 494 "\n [-2|-3] [-4|-6]"
513#else 495#else
514 "" 496 ""
515#endif 497#endif
516 ); 498 );
517} 499}
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..644cd604 100644
--- a/plugins/check_load.c
+++ b/plugins/check_load.c
@@ -1,350 +1,430 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_load plugin 3 * Monitoring check_load plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2007 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2007 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_load plugin 10 * This file contains the check_load plugin
11* 11 *
12* This plugin tests the current system load average. 12 * This plugin tests the current system load average.
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 15 * This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31const char *progname = "check_load"; 31const char *progname = "check_load";
32const char *copyright = "1999-2022"; 32const char *copyright = "1999-2022";
33const char *email = "devel@monitoring-plugins.org"; 33const char *email = "devel@monitoring-plugins.org";
34 34
35#include "./common.h" 35#include "./common.h"
36#include <string.h>
36#include "./runcmd.h" 37#include "./runcmd.h"
37#include "./utils.h" 38#include "./utils.h"
38#include "./popen.h" 39#include "./popen.h"
40#include "../lib/states.h"
41#include "../lib/output.h"
42#include "../lib/perfdata.h"
43#include "../lib/thresholds.h"
44#include "check_load.d/config.h"
39 45
40#include <string.h> 46// getloadavg comes from gnulib
41 47#include "../gl/stdlib.h"
42#ifdef HAVE_SYS_LOADAVG_H
43#include <sys/loadavg.h>
44#endif
45 48
46/* needed for compilation under NetBSD, as suggested by Andy Doran */ 49/* needed for compilation under NetBSD, as suggested by Andy Doran */
47#ifndef LOADAVG_1MIN 50#ifndef LOADAVG_1MIN
48#define LOADAVG_1MIN 0 51# define LOADAVG_1MIN 0
49#define LOADAVG_5MIN 1 52# define LOADAVG_5MIN 1
50#define LOADAVG_15MIN 2 53# define LOADAVG_15MIN 2
51#endif /* !defined LOADAVG_1MIN */ 54#endif /* !defined LOADAVG_1MIN */
52 55
56typedef struct {
57 int errorcode;
58 check_load_config config;
59} check_load_config_wrapper;
60static check_load_config_wrapper process_arguments(int argc, char **argv);
61
62void print_help(void);
63void print_usage(void);
64typedef struct {
65 int errorcode;
66 char **top_processes;
67} top_processes_result;
68static top_processes_result print_top_consuming_processes(unsigned long n_procs_to_show);
69
70typedef struct {
71 mp_range load[3];
72} parsed_thresholds;
73static parsed_thresholds get_threshold(char *arg) {
74 size_t index;
75 char *str = arg;
76 char *tmp_pointer;
77 bool valid = false;
78
79 parsed_thresholds result = {
80 .load =
81 {
82 mp_range_init(),
83 mp_range_init(),
84 mp_range_init(),
85 },
86 };
53 87
54static int process_arguments (int argc, char **argv); 88 size_t arg_length = strlen(arg);
55static int validate_arguments (void); 89 for (index = 0; index < 3; index++) {
56void print_help (void); 90 double tmp = strtod(str, &tmp_pointer);
57void print_usage (void); 91 if (tmp_pointer == str) {
58static int print_top_consuming_processes(); 92 break;
59 93 }
60static int n_procs_to_show = 0;
61
62/* strictly for pretty-print usage in loops */
63static const int nums[3] = { 1, 5, 15 };
64
65/* provide some fairly sane defaults */
66double wload[3] = { 0.0, 0.0, 0.0 };
67double cload[3] = { 0.0, 0.0, 0.0 };
68#define la1 la[0]
69#define la5 la[1]
70#define la15 la[2]
71
72char *status_line;
73bool take_into_account_cpus = false;
74
75static void
76get_threshold(char *arg, double *th)
77{
78 size_t i, n;
79 int valid = 0;
80 char *str = arg, *p;
81 94
82 n = strlen(arg); 95 result.load[index] = mp_range_set_end(result.load[index], mp_create_pd_value(tmp));
83 for(i = 0; i < 3; i++) {
84 th[i] = strtod(str, &p);
85 if(p == str) break;
86 96
87 valid = 1; 97 valid = true;
88 str = p + 1; 98 str = tmp_pointer + 1;
89 if(n <= (size_t)(str - arg)) break; 99 if (arg_length <= (size_t)(str - arg)) {
100 break;
101 }
90 } 102 }
91 103
92 /* empty argument or non-floatish, so warn about it and die */ 104 /* empty argument or non-floatish, so warn about it and die */
93 if(!i && !valid) usage (_("Warning threshold must be float or float triplet!\n")); 105 if (!index && !valid) {
106 usage(_("Warning threshold must be float or float triplet!\n"));
107 }
94 108
95 if(i != 2) { 109 if (index != 2) {
96 /* one or more numbers were given, so fill array with last 110 /* one or more numbers were given, so fill array with last
97 * we got (most likely to NOT produce the least expected result) */ 111 * we got (most likely to NOT produce the least expected result) */
98 for(n = i; n < 3; n++) th[n] = th[i]; 112 for (size_t tmp_index = index; tmp_index < 3; tmp_index++) {
113 result.load[tmp_index] = result.load[index];
114 }
99 } 115 }
116 return result;
100} 117}
101 118
102 119int main(int argc, char **argv) {
103int 120 setlocale(LC_ALL, "");
104main (int argc, char **argv) 121 bindtextdomain(PACKAGE, LOCALEDIR);
105{ 122 textdomain(PACKAGE);
106 int result = -1;
107 int i;
108 long numcpus;
109
110 double la[3] = { 0.0, 0.0, 0.0 }; /* NetBSD complains about uninitialized arrays */
111#ifndef HAVE_GETLOADAVG
112 char input_buffer[MAX_INPUT_BUFFER];
113#endif
114
115 setlocale (LC_ALL, "");
116 bindtextdomain (PACKAGE, LOCALEDIR);
117 textdomain (PACKAGE);
118 setlocale(LC_NUMERIC, "POSIX"); 123 setlocale(LC_NUMERIC, "POSIX");
119 124
120 /* Parse extra opts if any */ 125 /* Parse extra opts if any */
121 argv = np_extra_opts (&argc, argv, progname); 126 argv = np_extra_opts(&argc, argv, progname);
122 127
123 if (process_arguments (argc, argv) == ERROR) 128 check_load_config_wrapper tmp_config = process_arguments(argc, argv);
124 usage4 (_("Could not parse arguments")); 129 if (tmp_config.errorcode == ERROR) {
125 130 usage4(_("Could not parse arguments"));
126#ifdef HAVE_GETLOADAVG
127 result = getloadavg (la, 3);
128 if (result != 3)
129 return STATE_UNKNOWN;
130#else
131 child_process = spopen (PATH_TO_UPTIME);
132 if (child_process == NULL) {
133 printf (_("Error opening %s\n"), PATH_TO_UPTIME);
134 return STATE_UNKNOWN;
135 }
136 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
137 if (child_stderr == NULL) {
138 printf (_("Could not open stderr for %s\n"), PATH_TO_UPTIME);
139 }
140 fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
141 if(strstr(input_buffer, "load average:")) {
142 sscanf (input_buffer, "%*[^l]load average: %lf, %lf, %lf", &la1, &la5, &la15);
143 }
144 else if(strstr(input_buffer, "load averages:")) {
145 sscanf (input_buffer, "%*[^l]load averages: %lf, %lf, %lf", &la1, &la5, &la15);
146 }
147 else {
148 printf (_("could not parse load from uptime %s: %d\n"), PATH_TO_UPTIME, result);
149 return STATE_UNKNOWN;
150 }
151
152 result = spclose (child_process);
153 if (result) {
154 printf (_("Error code %d returned in %s\n"), result, PATH_TO_UPTIME);
155 return STATE_UNKNOWN;
156 }
157#endif
158
159 if ((la[0] < 0.0) || (la[1] < 0.0) || (la[2] < 0.0)) {
160#ifdef HAVE_GETLOADAVG
161 printf (_("Error in getloadavg()\n"));
162#else
163 printf (_("Error processing %s\n"), PATH_TO_UPTIME);
164#endif
165 return STATE_UNKNOWN;
166 } 131 }
167 132
168 /* we got this far, so assume OK until we've measured */ 133 const check_load_config config = tmp_config.config;
169 result = STATE_OK; 134
135 double load_values[3] = {0, 0, 0};
170 136
171 xasprintf(&status_line, _("load average: %.2f, %.2f, %.2f"), la1, la5, la15); 137 // this should be getloadavg from gnulib, should work everywhereâ„¢
172 xasprintf(&status_line, ("total %s"), status_line); 138 int error = getloadavg(load_values, 3);
139 if (error != 3) {
140 die(STATE_UNKNOWN, _("Failed to retrieve load values"));
141 }
173 142
143 mp_check overall = mp_check_init();
144 if (config.output_format_set) {
145 mp_set_format(config.output_format);
146 }
174 147
175 double scaled_la[3] = { 0.0, 0.0, 0.0 };
176 bool is_using_scaled_load_values = false; 148 bool is_using_scaled_load_values = false;
177 149 long numcpus;
178 if (take_into_account_cpus == true && (numcpus = GET_NUMBER_OF_CPUS()) > 0) { 150 if (config.take_into_account_cpus && ((numcpus = GET_NUMBER_OF_CPUS()) > 0)) {
179 is_using_scaled_load_values = true; 151 is_using_scaled_load_values = true;
180 152
181 scaled_la[0] = la[0] / numcpus; 153 double scaled_la[3] = {
182 scaled_la[1] = la[1] / numcpus; 154 load_values[0] / numcpus,
183 scaled_la[2] = la[2] / numcpus; 155 load_values[1] / numcpus,
156 load_values[2] / numcpus,
157 };
158
159 mp_subcheck scaled_load_sc = mp_subcheck_init();
160 scaled_load_sc = mp_set_subcheck_default_state(scaled_load_sc, STATE_OK);
161 scaled_load_sc.output = "Scaled Load (divided by number of CPUs";
162
163 mp_perfdata pd_scaled_load1 = perfdata_init();
164 pd_scaled_load1.label = "scaled_load1";
165 pd_scaled_load1 = mp_set_pd_value(pd_scaled_load1, scaled_la[0]);
166 pd_scaled_load1 = mp_pd_set_thresholds(pd_scaled_load1, config.th_load[0]);
167
168 mp_subcheck scaled_load_sc1 = mp_subcheck_init();
169 scaled_load_sc1 = mp_set_subcheck_state(scaled_load_sc1, mp_get_pd_status(pd_scaled_load1));
170 mp_add_perfdata_to_subcheck(&scaled_load_sc1, pd_scaled_load1);
171 xasprintf(&scaled_load_sc1.output, "1 Minute: %s",
172 pd_value_to_string(pd_scaled_load1.value));
173 mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc1);
174
175 mp_perfdata pd_scaled_load5 = perfdata_init();
176 pd_scaled_load5.label = "scaled_load5";
177 pd_scaled_load5 = mp_set_pd_value(pd_scaled_load5, scaled_la[1]);
178 pd_scaled_load5 = mp_pd_set_thresholds(pd_scaled_load5, config.th_load[1]);
179
180 mp_subcheck scaled_load_sc5 = mp_subcheck_init();
181 scaled_load_sc5 = mp_set_subcheck_state(scaled_load_sc5, mp_get_pd_status(pd_scaled_load5));
182 mp_add_perfdata_to_subcheck(&scaled_load_sc5, pd_scaled_load5);
183 xasprintf(&scaled_load_sc5.output, "5 Minutes: %s",
184 pd_value_to_string(pd_scaled_load5.value));
185 mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc5);
186
187 mp_perfdata pd_scaled_load15 = perfdata_init();
188 pd_scaled_load15.label = "scaled_load15";
189 pd_scaled_load15 = mp_set_pd_value(pd_scaled_load15, scaled_la[2]);
190 pd_scaled_load15 = mp_pd_set_thresholds(pd_scaled_load15, config.th_load[2]);
191
192 mp_subcheck scaled_load_sc15 = mp_subcheck_init();
193 scaled_load_sc15 =
194 mp_set_subcheck_state(scaled_load_sc15, mp_get_pd_status(pd_scaled_load15));
195 mp_add_perfdata_to_subcheck(&scaled_load_sc15, pd_scaled_load15);
196 xasprintf(&scaled_load_sc15.output, "15 Minutes: %s",
197 pd_value_to_string(pd_scaled_load15.value));
198 mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc15);
199
200 mp_add_subcheck_to_check(&overall, scaled_load_sc);
201 }
202
203 mp_subcheck load_sc = mp_subcheck_init();
204 load_sc = mp_set_subcheck_default_state(load_sc, STATE_OK);
205 load_sc.output = "Total Load";
184 206
185 char *tmp = NULL; 207 mp_perfdata pd_load1 = perfdata_init();
186 xasprintf(&tmp, _("load average: %.2f, %.2f, %.2f"), scaled_la[0], scaled_la[1], scaled_la[2]); 208 pd_load1.label = "load1";
187 xasprintf(&status_line, "scaled %s - %s", tmp, status_line); 209 pd_load1 = mp_set_pd_value(pd_load1, load_values[0]);
210 if (!is_using_scaled_load_values) {
211 pd_load1 = mp_pd_set_thresholds(pd_load1, config.th_load[0]);
188 } 212 }
189 213
190 for(i = 0; i < 3; i++) { 214 mp_subcheck load_sc1 = mp_subcheck_init();
191 if (is_using_scaled_load_values) { 215 load_sc1 = mp_set_subcheck_state(load_sc1, mp_get_pd_status(pd_load1));
192 if(scaled_la[i] > cload[i]) { 216 mp_add_perfdata_to_subcheck(&load_sc1, pd_load1);
193 result = STATE_CRITICAL; 217 xasprintf(&load_sc1.output, "1 Minute: %s", pd_value_to_string(pd_load1.value));
194 break; 218 mp_add_subcheck_to_subcheck(&load_sc, load_sc1);
195 } 219
196 else if(scaled_la[i] > wload[i]) result = STATE_WARNING; 220 mp_perfdata pd_load5 = perfdata_init();
197 } else { 221 pd_load5.label = "load5";
198 if(la[i] > cload[i]) { 222 pd_load5 = mp_set_pd_value(pd_load5, load_values[1]);
199 result = STATE_CRITICAL; 223 if (!is_using_scaled_load_values) {
200 break; 224 pd_load5 = mp_pd_set_thresholds(pd_load5, config.th_load[1]);
201 }
202 else if(la[i] > wload[i]) result = STATE_WARNING;
203 }
204 } 225 }
205 226
206 printf("LOAD %s - %s|", state_text(result), status_line); 227 mp_subcheck load_sc5 = mp_subcheck_init();
207 for(i = 0; i < 3; i++) { 228 load_sc5 = mp_set_subcheck_state(load_sc5, mp_get_pd_status(pd_load5));
208 if (is_using_scaled_load_values) { 229 mp_add_perfdata_to_subcheck(&load_sc5, pd_load5);
209 printf("load%d=%.3f;;;0; ", nums[i], la[i]); 230 xasprintf(&load_sc5.output, "5 Minutes: %s", pd_value_to_string(pd_load5.value));
210 printf("scaled_load%d=%.3f;%.3f;%.3f;0; ", nums[i], scaled_la[i], wload[i], cload[i]); 231 mp_add_subcheck_to_subcheck(&load_sc, load_sc5);
211 } else { 232
212 printf("load%d=%.3f;%.3f;%.3f;0; ", nums[i], la[i], wload[i], cload[i]); 233 mp_perfdata pd_load15 = perfdata_init();
213 } 234 pd_load15.label = "load15";
235 pd_load15 = mp_set_pd_value(pd_load15, load_values[2]);
236 if (!is_using_scaled_load_values) {
237 pd_load15 = mp_pd_set_thresholds(pd_load15, config.th_load[2]);
214 } 238 }
215 239
216 putchar('\n'); 240 mp_subcheck load_sc15 = mp_subcheck_init();
217 if (n_procs_to_show > 0) { 241 load_sc15 = mp_set_subcheck_state(load_sc15, mp_get_pd_status(pd_load15));
218 print_top_consuming_processes(); 242 mp_add_perfdata_to_subcheck(&load_sc15, pd_load15);
243 xasprintf(&load_sc15.output, "15 Minutes: %s", pd_value_to_string(pd_load15.value));
244 mp_add_subcheck_to_subcheck(&load_sc, load_sc15);
245
246 mp_add_subcheck_to_check(&overall, load_sc);
247
248 if (config.n_procs_to_show > 0) {
249 mp_subcheck top_proc_sc = mp_subcheck_init();
250 top_proc_sc = mp_set_subcheck_state(top_proc_sc, STATE_OK);
251 top_processes_result top_proc = print_top_consuming_processes(config.n_procs_to_show);
252 xasprintf(&top_proc_sc.output, "Top %lu CPU time consuming processes",
253 config.n_procs_to_show);
254
255 if (top_proc.errorcode == OK) {
256 for (unsigned long i = 0; i < config.n_procs_to_show; i++) {
257 xasprintf(&top_proc_sc.output, "%s\n%s", top_proc_sc.output,
258 top_proc.top_processes[i]);
259 }
260 }
261
262 mp_add_subcheck_to_check(&overall, top_proc_sc);
219 } 263 }
220 return result;
221}
222 264
265 mp_exit(overall);
266}
223 267
224/* process command-line arguments */ 268/* process command-line arguments */
225static int 269static check_load_config_wrapper process_arguments(int argc, char **argv) {
226process_arguments (int argc, char **argv) 270
227{ 271 enum {
228 int c = 0; 272 output_format_index = CHAR_MAX + 1,
229
230 int option = 0;
231 static struct option longopts[] = {
232 {"warning", required_argument, 0, 'w'},
233 {"critical", required_argument, 0, 'c'},
234 {"percpu", no_argument, 0, 'r'},
235 {"version", no_argument, 0, 'V'},
236 {"help", no_argument, 0, 'h'},
237 {"procs-to-show", required_argument, 0, 'n'},
238 {0, 0, 0, 0}
239 }; 273 };
240 274
241 if (argc < 2) 275 static struct option longopts[] = {{"warning", required_argument, 0, 'w'},
242 return ERROR; 276 {"critical", required_argument, 0, 'c'},
277 {"percpu", no_argument, 0, 'r'},
278 {"version", no_argument, 0, 'V'},
279 {"help", no_argument, 0, 'h'},
280 {"procs-to-show", required_argument, 0, 'n'},
281 {"output-format", required_argument, 0, output_format_index},
282 {0, 0, 0, 0}};
283
284 check_load_config_wrapper result = {
285 .errorcode = OK,
286 .config = check_load_config_init(),
287 };
243 288
244 while (1) { 289 if (argc < 2) {
245 c = getopt_long (argc, argv, "Vhrc:w:n:", longopts, &option); 290 result.errorcode = ERROR;
291 return result;
292 }
246 293
247 if (c == -1 || c == EOF) 294 while (true) {
248 break; 295 int option = 0;
296 int option_index = getopt_long(argc, argv, "Vhrc:w:n:", longopts, &option);
249 297
250 switch (c) { 298 if (option_index == -1 || option_index == EOF) {
251 case 'w': /* warning time threshold */
252 get_threshold(optarg, wload);
253 break; 299 break;
254 case 'c': /* critical time threshold */ 300 }
255 get_threshold(optarg, cload); 301
302 switch (option_index) {
303 case output_format_index: {
304 parsed_output_format parser = mp_parse_output_format(optarg);
305 if (!parser.parsing_success) {
306 printf("Invalid output format: %s\n", optarg);
307 exit(STATE_UNKNOWN);
308 }
309
310 result.config.output_format_set = true;
311 result.config.output_format = parser.output_format;
256 break; 312 break;
313 }
314 case 'w': /* warning time threshold */ {
315 parsed_thresholds warning_range = get_threshold(optarg);
316 result.config.th_load[0].warning = warning_range.load[0];
317 result.config.th_load[0].warning_is_set = true;
318
319 result.config.th_load[1].warning = warning_range.load[1];
320 result.config.th_load[1].warning_is_set = true;
321
322 result.config.th_load[2].warning = warning_range.load[2];
323 result.config.th_load[2].warning_is_set = true;
324 } break;
325 case 'c': /* critical time threshold */ {
326 parsed_thresholds critical_range = get_threshold(optarg);
327 result.config.th_load[0].critical = critical_range.load[0];
328 result.config.th_load[0].critical_is_set = true;
329
330 result.config.th_load[1].critical = critical_range.load[1];
331 result.config.th_load[1].critical_is_set = true;
332
333 result.config.th_load[2].critical = critical_range.load[2];
334 result.config.th_load[2].critical_is_set = true;
335 } break;
257 case 'r': /* Divide load average by number of CPUs */ 336 case 'r': /* Divide load average by number of CPUs */
258 take_into_account_cpus = true; 337 result.config.take_into_account_cpus = true;
259 break; 338 break;
260 case 'V': /* version */ 339 case 'V': /* version */
261 print_revision (progname, NP_VERSION); 340 print_revision(progname, NP_VERSION);
262 exit (STATE_UNKNOWN); 341 exit(STATE_UNKNOWN);
263 case 'h': /* help */ 342 case 'h': /* help */
264 print_help (); 343 print_help();
265 exit (STATE_UNKNOWN); 344 exit(STATE_UNKNOWN);
266 case 'n': 345 case 'n':
267 n_procs_to_show = atoi(optarg); 346 result.config.n_procs_to_show = (unsigned long)atol(optarg);
268 break; 347 break;
269 case '?': /* help */ 348 case '?': /* help */
270 usage5 (); 349 usage5();
271 } 350 }
272 } 351 }
273 352
274 c = optind; 353 int index = optind;
275 if (c == argc) 354 if (index == argc) {
276 return validate_arguments (); 355 return result;
356 }
277 357
278 /* handle the case if both arguments are missing, 358 /* handle the case if both arguments are missing,
279 * but not if only one is given without -c or -w flag */ 359 * but not if only one is given without -c or -w flag */
280 if(c - argc == 2) { 360 if (index - argc == 2) {
281 get_threshold(argv[c++], wload); 361 parsed_thresholds warning_range = get_threshold(argv[index++]);
282 get_threshold(argv[c++], cload); 362 result.config.th_load[0].warning = warning_range.load[0];
283 } 363 result.config.th_load[0].warning_is_set = true;
284 else if(c - argc == 1) { 364
285 get_threshold(argv[c++], cload); 365 result.config.th_load[1].warning = warning_range.load[1];
286 } 366 result.config.th_load[1].warning_is_set = true;
287 367
288 return validate_arguments (); 368 result.config.th_load[2].warning = warning_range.load[2];
289} 369 result.config.th_load[2].warning_is_set = true;
290 370 parsed_thresholds critical_range = get_threshold(argv[index++]);
291 371 result.config.th_load[0].critical = critical_range.load[0];
292static int 372 result.config.th_load[0].critical_is_set = true;
293validate_arguments (void) 373
294{ 374 result.config.th_load[1].critical = critical_range.load[1];
295 int i = 0; 375 result.config.th_load[1].critical_is_set = true;
296 376
297 /* match cload first, as it will give the most friendly error message 377 result.config.th_load[2].critical = critical_range.load[2];
298 * if user hasn't given the -c switch properly */ 378 result.config.th_load[2].critical_is_set = true;
299 for(i = 0; i < 3; i++) { 379 } else if (index - argc == 1) {
300 if(cload[i] < 0) 380 parsed_thresholds critical_range = get_threshold(argv[index++]);
301 die (STATE_UNKNOWN, _("Critical threshold for %d-minute load average is not specified\n"), nums[i]); 381 result.config.th_load[0].critical = critical_range.load[0];
302 if(wload[i] < 0) 382 result.config.th_load[0].critical_is_set = true;
303 die (STATE_UNKNOWN, _("Warning threshold for %d-minute load average is not specified\n"), nums[i]); 383
304 if(wload[i] > cload[i]) 384 result.config.th_load[1].critical = critical_range.load[1];
305 die (STATE_UNKNOWN, _("Parameter inconsistency: %d-minute \"warning load\" is greater than \"critical load\"\n"), nums[i]); 385 result.config.th_load[1].critical_is_set = true;
386
387 result.config.th_load[2].critical = critical_range.load[2];
388 result.config.th_load[2].critical_is_set = true;
306 } 389 }
307 390
308 return OK; 391 return result;
309} 392}
310 393
394void print_help(void) {
395 print_revision(progname, NP_VERSION);
311 396
312void 397 printf("Copyright (c) 1999 Felipe Gustavo de Almeida <galmeida@linux.ime.usp.br>\n");
313print_help (void) 398 printf(COPYRIGHT, copyright, email);
314{
315 print_revision (progname, NP_VERSION);
316 399
317 printf ("Copyright (c) 1999 Felipe Gustavo de Almeida <galmeida@linux.ime.usp.br>\n"); 400 printf(_("This plugin tests the current system load average."));
318 printf (COPYRIGHT, copyright, email);
319 401
320 printf (_("This plugin tests the current system load average.")); 402 printf("\n\n");
321 403
322 printf ("\n\n"); 404 print_usage();
323 405
324 print_usage (); 406 printf(UT_HELP_VRSN);
407 printf(UT_EXTRA_OPTS);
325 408
326 printf (UT_HELP_VRSN); 409 printf(" %s\n", "-w, --warning=WLOAD1,WLOAD5,WLOAD15");
327 printf (UT_EXTRA_OPTS); 410 printf(" %s\n", _("Exit with WARNING status if load average exceeds WLOADn"));
411 printf(" %s\n", "-c, --critical=CLOAD1,CLOAD5,CLOAD15");
412 printf(" %s\n", _("Exit with CRITICAL status if load average exceed CLOADn"));
413 printf(" %s\n", _("the load average format is the same used by \"uptime\" and \"w\""));
414 printf(" %s\n", "-r, --percpu");
415 printf(" %s\n", _("Divide the load averages by the number of CPUs (when possible)"));
416 printf(" %s\n", "-n, --procs-to-show=NUMBER_OF_PROCS");
417 printf(" %s\n", _("Number of processes to show when printing the top consuming processes."));
418 printf(" %s\n", _("NUMBER_OF_PROCS=0 disables this feature. Default value is 0"));
328 419
329 printf (" %s\n", "-w, --warning=WLOAD1,WLOAD5,WLOAD15"); 420 printf(UT_OUTPUT_FORMAT);
330 printf (" %s\n", _("Exit with WARNING status if load average exceeds WLOADn")); 421 printf(UT_SUPPORT);
331 printf (" %s\n", "-c, --critical=CLOAD1,CLOAD5,CLOAD15");
332 printf (" %s\n", _("Exit with CRITICAL status if load average exceed CLOADn"));
333 printf (" %s\n", _("the load average format is the same used by \"uptime\" and \"w\""));
334 printf (" %s\n", "-r, --percpu");
335 printf (" %s\n", _("Divide the load averages by the number of CPUs (when possible)"));
336 printf (" %s\n", "-n, --procs-to-show=NUMBER_OF_PROCS");
337 printf (" %s\n", _("Number of processes to show when printing the top consuming processes."));
338 printf (" %s\n", _("NUMBER_OF_PROCS=0 disables this feature. Default value is 0"));
339
340 printf (UT_SUPPORT);
341} 422}
342 423
343void 424void print_usage(void) {
344print_usage (void) 425 printf("%s\n", _("Usage:"));
345{ 426 printf("%s [-r] -w WLOAD1,WLOAD5,WLOAD15 -c CLOAD1,CLOAD5,CLOAD15 [-n NUMBER_OF_PROCS]\n",
346 printf ("%s\n", _("Usage:")); 427 progname);
347 printf ("%s [-r] -w WLOAD1,WLOAD5,WLOAD15 -c CLOAD1,CLOAD5,CLOAD15 [-n NUMBER_OF_PROCS]\n", progname);
348} 428}
349 429
350#ifdef PS_USES_PROCPCPU 430#ifdef PS_USES_PROCPCPU
@@ -356,36 +436,52 @@ int cmpstringp(const void *p1, const void *p2) {
356 int procrss = 0; 436 int procrss = 0;
357 float procpcpu = 0; 437 float procpcpu = 0;
358 char procstat[8]; 438 char procstat[8];
359#ifdef PS_USES_PROCETIME 439# ifdef PS_USES_PROCETIME
360 char procetime[MAX_INPUT_BUFFER]; 440 char procetime[MAX_INPUT_BUFFER];
361#endif /* PS_USES_PROCETIME */ 441# endif /* PS_USES_PROCETIME */
362 char procprog[MAX_INPUT_BUFFER]; 442 char procprog[MAX_INPUT_BUFFER];
363 int pos; 443 int pos;
364 sscanf (* (char * const *) p1, PS_FORMAT, PS_VARLIST); 444 sscanf(*(char *const *)p1, PS_FORMAT, PS_VARLIST);
365 float procpcpu1 = procpcpu; 445 float procpcpu1 = procpcpu;
366 sscanf (* (char * const *) p2, PS_FORMAT, PS_VARLIST); 446 sscanf(*(char *const *)p2, PS_FORMAT, PS_VARLIST);
367 return procpcpu1 < procpcpu; 447 return procpcpu1 < procpcpu;
368} 448}
369#endif /* PS_USES_PROCPCPU */ 449#endif /* PS_USES_PROCPCPU */
370 450
371static int print_top_consuming_processes() { 451static top_processes_result print_top_consuming_processes(unsigned long n_procs_to_show) {
372 int i = 0; 452 top_processes_result result = {
373 struct output chld_out, chld_err; 453 .errorcode = OK,
374 if(np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0) != 0){ 454 };
455 output chld_out;
456 output chld_err;
457 if (np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0) != 0) {
375 fprintf(stderr, _("'%s' exited with non-zero status.\n"), PS_COMMAND); 458 fprintf(stderr, _("'%s' exited with non-zero status.\n"), PS_COMMAND);
376 return STATE_UNKNOWN; 459 result.errorcode = ERROR;
460 return result;
377 } 461 }
462
378 if (chld_out.lines < 2) { 463 if (chld_out.lines < 2) {
379 fprintf(stderr, _("some error occurred getting procs list.\n")); 464 fprintf(stderr, _("some error occurred getting procs list.\n"));
380 return STATE_UNKNOWN; 465 result.errorcode = ERROR;
466 return result;
381 } 467 }
468
382#ifdef PS_USES_PROCPCPU 469#ifdef PS_USES_PROCPCPU
383 qsort(chld_out.line + 1, chld_out.lines - 1, sizeof(char*), cmpstringp); 470 qsort(chld_out.line + 1, chld_out.lines - 1, sizeof(char *), cmpstringp);
384#endif /* PS_USES_PROCPCPU */ 471#endif /* PS_USES_PROCPCPU */
385 int lines_to_show = chld_out.lines < (size_t)(n_procs_to_show + 1) 472 unsigned long lines_to_show =
386 ? (int)chld_out.lines : n_procs_to_show + 1; 473 chld_out.lines < (size_t)(n_procs_to_show + 1) ? chld_out.lines : n_procs_to_show + 1;
387 for (i = 0; i < lines_to_show; i += 1) { 474
388 printf("%s\n", chld_out.line[i]); 475 result.top_processes = calloc(lines_to_show, sizeof(char *));
476 if (result.top_processes == NULL) {
477 // Failed allocation
478 result.errorcode = ERROR;
479 return result;
389 } 480 }
390 return OK; 481
482 for (unsigned long i = 0; i < lines_to_show; i += 1) {
483 xasprintf(&result.top_processes[i], "%s", chld_out.line[i]);
484 }
485
486 return result;
391} 487}
diff --git a/plugins/check_load.d/config.h b/plugins/check_load.d/config.h
new file mode 100644
index 00000000..fd735455
--- /dev/null
+++ b/plugins/check_load.d/config.h
@@ -0,0 +1,30 @@
1#pragma once
2
3#include "output.h"
4#include "thresholds.h"
5typedef struct {
6 mp_thresholds th_load[3];
7
8 bool take_into_account_cpus;
9 unsigned long n_procs_to_show;
10
11 mp_output_format output_format;
12 bool output_format_set;
13} check_load_config;
14
15check_load_config check_load_config_init() {
16 check_load_config tmp = {
17 .th_load =
18 {
19 mp_thresholds_init(),
20 mp_thresholds_init(),
21 mp_thresholds_init(),
22 },
23
24 .take_into_account_cpus = false,
25 .n_procs_to_show = 0,
26
27 .output_format_set = false,
28 };
29 return tmp;
30}
diff --git a/plugins/check_mrtg.c b/plugins/check_mrtg.c
index 826b77e9..4a17049a 100644
--- a/plugins/check_mrtg.c
+++ b/plugins/check_mrtg.c
@@ -1,385 +1,387 @@
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"),
136 (int) ((current_time - timestamp) / 60)); 133 (int)((current_time - timestamp) / 60));
137 return STATE_WARNING; 134 return STATE_WARNING;
138 } 135 }
139 136
137 unsigned long rate = 0L;
140 /* else check the incoming/outgoing rates */ 138 /* else check the incoming/outgoing rates */
141 if (use_average) 139 if (config.use_average) {
142 rate = average_value_rate; 140 rate = average_value_rate;
143 else 141 } else {
144 rate = maximum_value_rate; 142 rate = maximum_value_rate;
143 }
145 144
146 if (rate > value_critical_threshold) 145 int result = STATE_OK;
146 if (config.value_critical_threshold_set && rate > config.value_critical_threshold) {
147 result = STATE_CRITICAL; 147 result = STATE_CRITICAL;
148 else if (rate > value_warning_threshold) 148 } else if (config.value_warning_threshold_set && rate > config.value_warning_threshold) {
149 result = STATE_WARNING; 149 result = STATE_WARNING;
150 }
150 151
151 printf("%s. %s = %lu %s|%s\n", 152 printf("%s. %s = %lu %s|%s\n", (config.use_average) ? _("Avg") : _("Max"), config.label, rate,
152 (use_average) ? _("Avg") : _("Max"), 153 config.units,
153 label, rate, units, 154 perfdata(config.label, (long)rate, config.units, config.value_warning_threshold_set,
154 perfdata(label, (long) rate, units, 155 (long)config.value_warning_threshold, config.value_critical_threshold_set,
155 (int) value_warning_threshold, (long) value_warning_threshold, 156 (long)config.value_critical_threshold, 0, 0, 0, 0));
156 (int) value_critical_threshold, (long) value_critical_threshold,
157 0, 0, 0, 0));
158 157
159 return result; 158 return result;
160} 159}
161 160
162
163
164/* process command-line arguments */ 161/* process command-line arguments */
165int 162check_mrtg_config_wrapper process_arguments(int argc, char **argv) {
166process_arguments (int argc, char **argv) 163 static struct option longopts[] = {{"logfile", required_argument, 0, 'F'},
167{ 164 {"expires", required_argument, 0, 'e'},
168 int c; 165 {"aggregation", required_argument, 0, 'a'},
169 166 {"variable", required_argument, 0, 'v'},
170 int option = 0; 167 {"critical", required_argument, 0, 'c'},
171 static struct option longopts[] = { 168 {"warning", required_argument, 0, 'w'},
172 {"logfile", required_argument, 0, 'F'}, 169 {"label", required_argument, 0, 'l'},
173 {"expires", required_argument, 0, 'e'}, 170 {"units", required_argument, 0, 'u'},
174 {"aggregation", required_argument, 0, 'a'}, 171 {"variable", required_argument, 0, 'v'},
175 {"variable", required_argument, 0, 'v'}, 172 {"version", no_argument, 0, 'V'},
176 {"critical", required_argument, 0, 'c'}, 173 {"help", no_argument, 0, 'h'},
177 {"warning", required_argument, 0, 'w'}, 174 {0, 0, 0, 0}};
178 {"label", required_argument, 0, 'l'}, 175
179 {"units", required_argument, 0, 'u'}, 176 check_mrtg_config_wrapper result = {
180 {"variable", required_argument, 0, 'v'}, 177 .errorcode = OK,
181 {"version", no_argument, 0, 'V'}, 178 .config = check_mrtg_config_init(),
182 {"help", no_argument, 0, 'h'},
183 {0, 0, 0, 0}
184 }; 179 };
185 180
186 if (argc < 2) 181 if (argc < 2) {
187 return ERROR; 182 result.errorcode = ERROR;
183 return result;
184 }
188 185
189 for (c = 1; c < argc; c++) { 186 for (int i = 1; i < argc; i++) {
190 if (strcmp ("-to", argv[c]) == 0) 187 if (strcmp("-to", argv[i]) == 0) {
191 strcpy (argv[c], "-t"); 188 strcpy(argv[i], "-t");
192 else if (strcmp ("-wt", argv[c]) == 0) 189 } else if (strcmp("-wt", argv[i]) == 0) {
193 strcpy (argv[c], "-w"); 190 strcpy(argv[i], "-w");
194 else if (strcmp ("-ct", argv[c]) == 0) 191 } else if (strcmp("-ct", argv[i]) == 0) {
195 strcpy (argv[c], "-c"); 192 strcpy(argv[i], "-c");
193 }
196 } 194 }
197 195
196 int option_char;
197 int option = 0;
198 while (1) { 198 while (1) {
199 c = getopt_long (argc, argv, "hVF:e:a:v:c:w:l:u:", longopts, 199 option_char = getopt_long(argc, argv, "hVF:e:a:v:c:w:l:u:", longopts, &option);
200 &option);
201 200
202 if (c == -1 || c == EOF) 201 if (option_char == -1 || option_char == EOF) {
203 break; 202 break;
203 }
204 204
205 switch (c) { 205 switch (option_char) {
206 case 'F': /* input file */ 206 case 'F': /* input file */
207 log_file = optarg; 207 result.config.log_file = optarg;
208 break; 208 break;
209 case 'e': /* ups name */ 209 case 'e': /* ups name */
210 expire_minutes = atoi (optarg); 210 result.config.expire_minutes = atoi(optarg);
211 break; 211 break;
212 case 'a': /* port */ 212 case 'a': /* port */
213 if (!strcmp (optarg, "MAX")) 213 result.config.use_average = (bool)(strcmp(optarg, "MAX"));
214 use_average = false;
215 else
216 use_average = true;
217 break; 214 break;
218 case 'v': 215 case 'v':
219 variable_number = atoi (optarg); 216 result.config.variable_number = atoi(optarg);
220 if (variable_number < 1 || variable_number > 2) 217 if (result.config.variable_number < 1 || result.config.variable_number > 2) {
221 usage4 (_("Invalid variable number")); 218 usage4(_("Invalid variable number"));
219 }
222 break; 220 break;
223 case 'w': /* critical time threshold */ 221 case 'w': /* critical time threshold */
224 value_warning_threshold = strtoul (optarg, NULL, 10); 222 result.config.value_warning_threshold_set = true;
223 result.config.value_warning_threshold = strtoul(optarg, NULL, 10);
225 break; 224 break;
226 case 'c': /* warning time threshold */ 225 case 'c': /* warning time threshold */
227 value_critical_threshold = strtoul (optarg, NULL, 10); 226 result.config.value_critical_threshold_set = true;
227 result.config.value_critical_threshold = strtoul(optarg, NULL, 10);
228 break; 228 break;
229 case 'l': /* label */ 229 case 'l': /* label */
230 label = optarg; 230 result.config.label = optarg;
231 break; 231 break;
232 case 'u': /* timeout */ 232 case 'u': /* timeout */
233 units = optarg; 233 result.config.units = optarg;
234 break; 234 break;
235 case 'V': /* version */ 235 case 'V': /* version */
236 print_revision (progname, NP_VERSION); 236 print_revision(progname, NP_VERSION);
237 exit (STATE_UNKNOWN); 237 exit(STATE_UNKNOWN);
238 case 'h': /* help */ 238 case 'h': /* help */
239 print_help (); 239 print_help();
240 exit (STATE_UNKNOWN); 240 exit(STATE_UNKNOWN);
241 case '?': /* help */ 241 case '?': /* help */
242 usage5 (); 242 usage5();
243 } 243 }
244 } 244 }
245 245
246 c = optind; 246 option_char = optind;
247 if (log_file == NULL && argc > c) { 247 if (result.config.log_file == NULL && argc > option_char) {
248 log_file = argv[c++]; 248 result.config.log_file = argv[option_char++];
249 } 249 }
250 250
251 if (expire_minutes <= 0 && argc > c) { 251 if (result.config.expire_minutes <= 0 && argc > option_char) {
252 if (is_intpos (argv[c])) 252 if (is_intpos(argv[option_char])) {
253 expire_minutes = atoi (argv[c++]); 253 result.config.expire_minutes = atoi(argv[option_char++]);
254 else 254 } else {
255 die (STATE_UNKNOWN, 255 die(STATE_UNKNOWN,
256 _("%s is not a valid expiration time\nUse '%s -h' for additional help\n"), 256 _("%s is not a valid expiration time\nUse '%s -h' for additional help\n"),
257 argv[c], progname); 257 argv[option_char], progname);
258 }
258 } 259 }
259 260
260 if (argc > c && strcmp (argv[c], "MAX") == 0) { 261 if (argc > option_char && strcmp(argv[option_char], "MAX") == 0) {
261 use_average = false; 262 result.config.use_average = false;
262 c++; 263 option_char++;
263 } 264 } else if (argc > option_char && strcmp(argv[option_char], "AVG") == 0) {
264 else if (argc > c && strcmp (argv[c], "AVG") == 0) { 265 result.config.use_average = true;
265 use_average = true; 266 option_char++;
266 c++;
267 } 267 }
268 268
269 if (argc > c && variable_number == -1) { 269 if (argc > option_char && result.config.variable_number == -1) {
270 variable_number = atoi (argv[c++]); 270 result.config.variable_number = atoi(argv[option_char++]);
271 if (variable_number < 1 || variable_number > 2) { 271 if (result.config.variable_number < 1 || result.config.variable_number > 2) {
272 printf ("%s :", argv[c]); 272 printf("%s :", argv[option_char]);
273 usage (_("Invalid variable number\n")); 273 usage(_("Invalid variable number\n"));
274 } 274 }
275 } 275 }
276 276
277 if (argc > c && value_warning_threshold == 0) { 277 if (argc > option_char && !result.config.value_warning_threshold_set) {
278 value_warning_threshold = strtoul (argv[c++], NULL, 10); 278 result.config.value_warning_threshold_set = true;
279 result.config.value_warning_threshold = strtoul(argv[option_char++], NULL, 10);
279 } 280 }
280 281
281 if (argc > c && value_critical_threshold == 0) { 282 if (argc > option_char && !result.config.value_critical_threshold_set) {
282 value_critical_threshold = strtoul (argv[c++], NULL, 10); 283 result.config.value_critical_threshold_set = true;
284 result.config.value_critical_threshold = strtoul(argv[option_char++], NULL, 10);
283 } 285 }
284 286
285 if (argc > c && strlen (label) == 0) { 287 if (argc > option_char && strlen(result.config.label) == 0) {
286 label = argv[c++]; 288 result.config.label = argv[option_char++];
287 } 289 }
288 290
289 if (argc > c && strlen (units) == 0) { 291 if (argc > option_char && strlen(result.config.units) == 0) {
290 units = argv[c++]; 292 result.config.units = argv[option_char++];
291 } 293 }
292 294
293 return validate_arguments (); 295 return validate_arguments(result);
294} 296}
295 297
296int 298check_mrtg_config_wrapper validate_arguments(check_mrtg_config_wrapper config_wrapper) {
297validate_arguments (void) 299 if (config_wrapper.config.variable_number == -1) {
298{ 300 usage4(_("You must supply the variable number"));
299 if (variable_number == -1) 301 }
300 usage4 (_("You must supply the variable number"));
301 302
302 if (label == NULL) 303 if (config_wrapper.config.label == NULL) {
303 label = strdup ("value"); 304 config_wrapper.config.label = strdup("value");
305 }
304 306
305 if (units == NULL) 307 if (config_wrapper.config.units == NULL) {
306 units = strdup (""); 308 config_wrapper.config.units = strdup("");
309 }
307 310
308 return OK; 311 return config_wrapper;
309} 312}
310 313
311 314void print_help(void) {
312 315 print_revision(progname, NP_VERSION);
313void 316
314print_help (void) 317 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
315{ 318 printf(COPYRIGHT, copyright, email);
316 print_revision (progname, NP_VERSION); 319
317 320 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"); 321 printf("%s\n", _("two variables recorded in an MRTG log file."));
319 printf (COPYRIGHT, copyright, email); 322
320 323 printf("\n\n");
321 printf ("%s\n", _("This plugin will check either the average or maximum value of one of the")); 324
322 printf ("%s\n", _("two variables recorded in an MRTG log file.")); 325 print_usage();
323 326
324 printf ("\n\n"); 327 printf(UT_HELP_VRSN);
325 328 printf(UT_EXTRA_OPTS);
326 print_usage (); 329
327 330 printf(" %s\n", "-F, --logfile=FILE");
328 printf (UT_HELP_VRSN); 331 printf(" %s\n", _("The MRTG log file containing the data you want to monitor"));
329 printf (UT_EXTRA_OPTS); 332 printf(" %s\n", "-e, --expires=MINUTES");
330 333 printf(" %s\n", _("Minutes before MRTG data is considered to be too old"));
331 printf (" %s\n", "-F, --logfile=FILE"); 334 printf(" %s\n", "-a, --aggregation=AVG|MAX");
332 printf (" %s\n", _("The MRTG log file containing the data you want to monitor")); 335 printf(" %s\n", _("Should we check average or maximum values?"));
333 printf (" %s\n", "-e, --expires=MINUTES"); 336 printf(" %s\n", "-v, --variable=INTEGER");
334 printf (" %s\n", _("Minutes before MRTG data is considered to be too old")); 337 printf(" %s\n", _("Which variable set should we inspect? (1 or 2)"));
335 printf (" %s\n", "-a, --aggregation=AVG|MAX"); 338 printf(" %s\n", "-w, --warning=INTEGER");
336 printf (" %s\n", _("Should we check average or maximum values?")); 339 printf(" %s\n", _("Threshold value for data to result in WARNING status"));
337 printf (" %s\n", "-v, --variable=INTEGER"); 340 printf(" %s\n", "-c, --critical=INTEGER");
338 printf (" %s\n", _("Which variable set should we inspect? (1 or 2)")); 341 printf(" %s\n", _("Threshold value for data to result in CRITICAL status"));
339 printf (" %s\n", "-w, --warning=INTEGER"); 342 printf(" %s\n", "-l, --label=STRING");
340 printf (" %s\n", _("Threshold value for data to result in WARNING status")); 343 printf(" %s\n", _("Type label for data (Examples: Conns, \"Processor Load\", In, Out)"));
341 printf (" %s\n", "-c, --critical=INTEGER"); 344 printf(" %s\n", "-u, --units=STRING");
342 printf (" %s\n", _("Threshold value for data to result in CRITICAL status")); 345 printf(" %s\n", _("Option units label for data (Example: Packets/Sec, Errors/Sec,"));
343 printf (" %s\n", "-l, --label=STRING"); 346 printf(" %s\n", _("\"Bytes Per Second\", \"%% Utilization\")"));
344 printf (" %s\n", _("Type label for data (Examples: Conns, \"Processor Load\", In, Out)")); 347
345 printf (" %s\n", "-u, --units=STRING"); 348 printf("\n");
346 printf (" %s\n", _("Option units label for data (Example: Packets/Sec, Errors/Sec,")); 349 printf(" %s\n",
347 printf (" %s\n", _("\"Bytes Per Second\", \"%% Utilization\")")); 350 _("If the value exceeds the <vwl> threshold, a WARNING status is returned. If"));
348 351 printf(" %s\n", _("the value exceeds the <vcl> threshold, a CRITICAL status is returned. If"));
349 printf ("\n"); 352 printf(" %s\n", _("the data in the log file is older than <expire_minutes> old, a WARNING"));
350 printf (" %s\n", _("If the value exceeds the <vwl> threshold, a WARNING status is returned. If")); 353 printf(" %s\n", _("status is returned and a warning message is printed."));
351 printf (" %s\n", _("the value exceeds the <vcl> threshold, a CRITICAL status is returned. If")); 354
352 printf (" %s\n", _("the data in the log file is older than <expire_minutes> old, a WARNING")); 355 printf("\n");
353 printf (" %s\n", _("status is returned and a warning message is printed.")); 356 printf(" %s\n",
354 357 _("This plugin is useful for monitoring MRTG data that does not correspond to"));
355 printf ("\n"); 358 printf(" %s\n",
356 printf (" %s\n", _("This plugin is useful for monitoring MRTG data that does not correspond to")); 359 _("bandwidth usage. (Use the check_mrtgtraf plugin for monitoring bandwidth)."));
357 printf (" %s\n", _("bandwidth usage. (Use the check_mrtgtraf plugin for monitoring bandwidth).")); 360 printf(" %s\n",
358 printf (" %s\n", _("It can be used to monitor any kind of data that MRTG is monitoring - errors,")); 361 _("It can be used to monitor any kind of data that MRTG is monitoring - errors,"));
359 printf (" %s\n", _("packets/sec, etc. I use MRTG in conjunction with the Novell NLM that allows")); 362 printf(" %s\n",
360 printf (" %s\n", _("me to track processor utilization, user connections, drive space, etc and")); 363 _("packets/sec, etc. I use MRTG in conjunction with the Novell NLM that allows"));
361 printf (" %s\n\n", _("this plugin works well for monitoring that kind of data as well.")); 364 printf(" %s\n", _("me to track processor utilization, user connections, drive space, etc and"));
362 365 printf(" %s\n\n", _("this plugin works well for monitoring that kind of data as well."));
363 printf ("%s\n", _("Notes:")); 366
364 printf (" %s\n", _("- This plugin only monitors one of the two variables stored in the MRTG log")); 367 printf("%s\n", _("Notes:"));
365 printf (" %s\n", _("file. If you want to monitor both values you will have to define two")); 368 printf(" %s\n",
366 printf (" %s\n", _("commands with different values for the <variable> argument. Of course,")); 369 _("- This plugin only monitors one of the two variables stored in the MRTG log"));
367 printf (" %s\n", _("you can always hack the code to make this plugin work for you...")); 370 printf(" %s\n", _("file. If you want to monitor both values you will have to define two"));
368 printf (" %s\n", _("- MRTG stands for the Multi Router Traffic Grapher. It can be downloaded from")); 371 printf(" %s\n", _("commands with different values for the <variable> argument. Of course,"));
369 printf (" %s\n", "http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html"); 372 printf(" %s\n", _("you can always hack the code to make this plugin work for you..."));
370 373 printf(" %s\n",
371 printf (UT_SUPPORT); 374 _("- MRTG stands for the Multi Router Traffic Grapher. It can be downloaded from"));
375 printf(" %s\n", "http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html");
376
377 printf(UT_SUPPORT);
372} 378}
373 379
374
375
376/* original command line: 380/* original command line:
377 <log_file> <expire_minutes> <AVG|MAX> <variable> <vwl> <vcl> <label> [units] */ 381 <log_file> <expire_minutes> <AVG|MAX> <variable> <vwl> <vcl> <label> [units] */
378 382
379void 383void print_usage(void) {
380print_usage (void) 384 printf("%s\n", _("Usage:"));
381{ 385 printf("%s -F log_file -a <AVG | MAX> -v variable -w warning -c critical\n", progname);
382 printf ("%s\n", _("Usage:")); 386 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} 387}
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..10ce936f 100644
--- a/plugins/check_mrtgtraf.c
+++ b/plugins/check_mrtgtraf.c
@@ -1,381 +1,360 @@
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"),
137 (int) ((current_time - timestamp) / 60)); 126 (int)((current_time - timestamp) / 60));
127 }
138 128
129 unsigned long incoming_rate = 0L;
130 unsigned long outgoing_rate = 0L;
139 /* else check the incoming/outgoing rates */ 131 /* else check the incoming/outgoing rates */
140 if (use_average) { 132 if (config.use_average) {
141 incoming_rate = average_incoming_rate; 133 incoming_rate = average_incoming_rate;
142 outgoing_rate = average_outgoing_rate; 134 outgoing_rate = average_outgoing_rate;
143 } 135 } else {
144 else {
145 incoming_rate = maximum_incoming_rate; 136 incoming_rate = maximum_incoming_rate;
146 outgoing_rate = maximum_outgoing_rate; 137 outgoing_rate = maximum_outgoing_rate;
147 } 138 }
148 139
140 double adjusted_incoming_rate = 0.0;
141 char incoming_speed_rating[8];
149 /* report incoming traffic in Bytes/sec */ 142 /* report incoming traffic in Bytes/sec */
150 if (incoming_rate < 1024) { 143 if (incoming_rate < 1024) {
151 strcpy (incoming_speed_rating, "B"); 144 strcpy(incoming_speed_rating, "B");
152 adjusted_incoming_rate = (double) incoming_rate; 145 adjusted_incoming_rate = (double)incoming_rate;
153 } 146 }
154 147
155 /* report incoming traffic in KBytes/sec */ 148 /* report incoming traffic in KBytes/sec */
156 else if (incoming_rate < (1024 * 1024)) { 149 else if (incoming_rate < (1024 * 1024)) {
157 strcpy (incoming_speed_rating, "KB"); 150 strcpy(incoming_speed_rating, "KB");
158 adjusted_incoming_rate = (double) (incoming_rate / 1024.0); 151 adjusted_incoming_rate = (double)(incoming_rate / 1024.0);
159 } 152 }
160 153
161 /* report incoming traffic in MBytes/sec */ 154 /* report incoming traffic in MBytes/sec */
162 else { 155 else {
163 strcpy (incoming_speed_rating, "MB"); 156 strcpy(incoming_speed_rating, "MB");
164 adjusted_incoming_rate = (double) (incoming_rate / 1024.0 / 1024.0); 157 adjusted_incoming_rate = (double)(incoming_rate / 1024.0 / 1024.0);
165 } 158 }
166 159
160 double adjusted_outgoing_rate = 0.0;
161 char outgoing_speed_rating[8];
167 /* report outgoing traffic in Bytes/sec */ 162 /* report outgoing traffic in Bytes/sec */
168 if (outgoing_rate < 1024) { 163 if (outgoing_rate < 1024) {
169 strcpy (outgoing_speed_rating, "B"); 164 strcpy(outgoing_speed_rating, "B");
170 adjusted_outgoing_rate = (double) outgoing_rate; 165 adjusted_outgoing_rate = (double)outgoing_rate;
171 } 166 }
172 167
173 /* report outgoing traffic in KBytes/sec */ 168 /* report outgoing traffic in KBytes/sec */
174 else if (outgoing_rate < (1024 * 1024)) { 169 else if (outgoing_rate < (1024 * 1024)) {
175 strcpy (outgoing_speed_rating, "KB"); 170 strcpy(outgoing_speed_rating, "KB");
176 adjusted_outgoing_rate = (double) (outgoing_rate / 1024.0); 171 adjusted_outgoing_rate = (double)(outgoing_rate / 1024.0);
177 } 172 }
178 173
179 /* report outgoing traffic in MBytes/sec */ 174 /* report outgoing traffic in MBytes/sec */
180 else { 175 else {
181 strcpy (outgoing_speed_rating, "MB"); 176 strcpy(outgoing_speed_rating, "MB");
182 adjusted_outgoing_rate = (double) (outgoing_rate / 1024.0 / 1024.0); 177 adjusted_outgoing_rate = (outgoing_rate / 1024.0 / 1024.0);
183 } 178 }
184 179
185 if (incoming_rate > incoming_critical_threshold 180 int result = STATE_OK;
186 || outgoing_rate > outgoing_critical_threshold) { 181 if (incoming_rate > config.incoming_critical_threshold ||
182 outgoing_rate > config.outgoing_critical_threshold) {
187 result = STATE_CRITICAL; 183 result = STATE_CRITICAL;
188 } 184 } else if (incoming_rate > config.incoming_warning_threshold ||
189 else if (incoming_rate > incoming_warning_threshold 185 outgoing_rate > config.outgoing_warning_threshold) {
190 || outgoing_rate > outgoing_warning_threshold) {
191 result = STATE_WARNING; 186 result = STATE_WARNING;
192 } 187 }
193 188
194 xasprintf (&error_message, _("%s. In = %0.1f %s/s, %s. Out = %0.1f %s/s|%s %s\n"), 189 char *error_message;
195 (use_average) ? _("Avg") : _("Max"), adjusted_incoming_rate, 190 xasprintf(&error_message, _("%s. In = %0.1f %s/s, %s. Out = %0.1f %s/s|%s %s\n"),
196 incoming_speed_rating, (use_average) ? _("Avg") : _("Max"), 191 (config.use_average) ? _("Avg") : _("Max"), adjusted_incoming_rate,
197 adjusted_outgoing_rate, outgoing_speed_rating, 192 incoming_speed_rating, (config.use_average) ? _("Avg") : _("Max"),
198 fperfdata("in", adjusted_incoming_rate, incoming_speed_rating, 193 adjusted_outgoing_rate, outgoing_speed_rating,
199 (int)incoming_warning_threshold, incoming_warning_threshold, 194 fperfdata("in", adjusted_incoming_rate, incoming_speed_rating,
200 (int)incoming_critical_threshold, incoming_critical_threshold, 195 (int)config.incoming_warning_threshold, config.incoming_warning_threshold,
201 true, 0, false, 0), 196 (int)config.incoming_critical_threshold, config.incoming_critical_threshold,
202 fperfdata("out", adjusted_outgoing_rate, outgoing_speed_rating, 197 true, 0, false, 0),
203 (int)outgoing_warning_threshold, outgoing_warning_threshold, 198 fperfdata("out", adjusted_outgoing_rate, outgoing_speed_rating,
204 (int)outgoing_critical_threshold, outgoing_critical_threshold, 199 (int)config.outgoing_warning_threshold, config.outgoing_warning_threshold,
205 true, 0, false, 0)); 200 (int)config.outgoing_critical_threshold, config.outgoing_critical_threshold,
206 201 true, 0, false, 0));
207 printf (_("Traffic %s - %s\n"), state_text(result), error_message); 202
203 printf(_("Traffic %s - %s\n"), state_text(result), error_message);
208 204
209 return result; 205 return result;
210} 206}
211 207
212
213
214/* process command-line arguments */ 208/* process command-line arguments */
215int 209check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) {
216process_arguments (int argc, char **argv) 210 static struct option longopts[] = {{"filename", required_argument, 0, 'F'},
217{ 211 {"expires", required_argument, 0, 'e'},
218 int c; 212 {"aggregation", required_argument, 0, 'a'},
219 213 {"critical", required_argument, 0, 'c'},
220 int option = 0; 214 {"warning", required_argument, 0, 'w'},
221 static struct option longopts[] = { 215 {"version", no_argument, 0, 'V'},
222 {"filename", required_argument, 0, 'F'}, 216 {"help", no_argument, 0, 'h'},
223 {"expires", required_argument, 0, 'e'}, 217 {0, 0, 0, 0}};
224 {"aggregation", required_argument, 0, 'a'}, 218
225 {"critical", required_argument, 0, 'c'}, 219 check_mrtgtraf_config_wrapper result = {
226 {"warning", required_argument, 0, 'w'}, 220 .errorcode = OK,
227 {"version", no_argument, 0, 'V'}, 221 .config = check_mrtgtraf_config_init(),
228 {"help", no_argument, 0, 'h'},
229 {0, 0, 0, 0}
230 }; 222 };
223 if (argc < 2) {
224 result.errorcode = ERROR;
225 return result;
226 }
231 227
232 if (argc < 2) 228 for (int i = 1; i < argc; i++) {
233 return ERROR; 229 if (strcmp("-to", argv[i]) == 0) {
234 230 strcpy(argv[i], "-t");
235 for (c = 1; c < argc; c++) { 231 } else if (strcmp("-wt", argv[i]) == 0) {
236 if (strcmp ("-to", argv[c]) == 0) 232 strcpy(argv[i], "-w");
237 strcpy (argv[c], "-t"); 233 } else if (strcmp("-ct", argv[i]) == 0) {
238 else if (strcmp ("-wt", argv[c]) == 0) 234 strcpy(argv[i], "-c");
239 strcpy (argv[c], "-w"); 235 }
240 else if (strcmp ("-ct", argv[c]) == 0)
241 strcpy (argv[c], "-c");
242 } 236 }
243 237
244 while (1) { 238 int option_char;
245 c = getopt_long (argc, argv, "hVF:e:a:c:w:", longopts, &option); 239 int option = 0;
240 while (true) {
241 option_char = getopt_long(argc, argv, "hVF:e:a:c:w:", longopts, &option);
246 242
247 if (c == -1 || c == EOF) 243 if (option_char == -1 || option_char == EOF) {
248 break; 244 break;
245 }
249 246
250 switch (c) { 247 switch (option_char) {
251 case 'F': /* input file */ 248 case 'F': /* input file */
252 log_file = optarg; 249 result.config.log_file = optarg;
253 break; 250 break;
254 case 'e': /* expiration time */ 251 case 'e': /* expiration time */
255 expire_minutes = atoi (optarg); 252 result.config.expire_minutes = atoi(optarg);
256 break; 253 break;
257 case 'a': /* aggregation (AVE or MAX) */ 254 case 'a': /* aggregation (AVE or MAX) */
258 if (!strcmp (optarg, "MAX")) 255 result.config.use_average = (bool)(strcmp(optarg, "MAX"));
259 use_average = false;
260 else
261 use_average = true;
262 break; 256 break;
263 case 'c': /* warning threshold */ 257 case 'c': /* warning threshold */
264 sscanf (optarg, "%lu,%lu", &incoming_critical_threshold, 258 sscanf(optarg, "%lu,%lu", &result.config.incoming_critical_threshold,
265 &outgoing_critical_threshold); 259 &result.config.outgoing_critical_threshold);
266 break; 260 break;
267 case 'w': /* critical threshold */ 261 case 'w': /* critical threshold */
268 sscanf (optarg, "%lu,%lu", &incoming_warning_threshold, 262 sscanf(optarg, "%lu,%lu", &result.config.incoming_warning_threshold,
269 &outgoing_warning_threshold); 263 &result.config.outgoing_warning_threshold);
270 break; 264 break;
271 case 'V': /* version */ 265 case 'V': /* version */
272 print_revision (progname, NP_VERSION); 266 print_revision(progname, NP_VERSION);
273 exit (STATE_UNKNOWN); 267 exit(STATE_UNKNOWN);
274 case 'h': /* help */ 268 case 'h': /* help */
275 print_help (); 269 print_help();
276 exit (STATE_UNKNOWN); 270 exit(STATE_UNKNOWN);
277 case '?': /* help */ 271 case '?': /* help */
278 usage5 (); 272 usage5();
279 } 273 }
280 } 274 }
281 275
282 c = optind; 276 option_char = optind;
283 if (argc > c && log_file == NULL) { 277 if (argc > option_char && result.config.log_file == NULL) {
284 log_file = argv[c++]; 278 result.config.log_file = argv[option_char++];
285 } 279 }
286 280
287 if (argc > c && expire_minutes == -1) { 281 if (argc > option_char && result.config.expire_minutes == -1) {
288 expire_minutes = atoi (argv[c++]); 282 result.config.expire_minutes = atoi(argv[option_char++]);
289 } 283 }
290 284
291 if (argc > c && strcmp (argv[c], "MAX") == 0) { 285 if (argc > option_char && strcmp(argv[option_char], "MAX") == 0) {
292 use_average = false; 286 result.config.use_average = false;
293 c++; 287 option_char++;
294 } 288 } else if (argc > option_char && strcmp(argv[option_char], "AVG") == 0) {
295 else if (argc > c && strcmp (argv[c], "AVG") == 0) { 289 result.config.use_average = true;
296 use_average = true; 290 option_char++;
297 c++;
298 } 291 }
299 292
300 if (argc > c && incoming_warning_threshold == 0) { 293 if (argc > option_char && result.config.incoming_warning_threshold == 0) {
301 incoming_warning_threshold = strtoul (argv[c++], NULL, 10); 294 result.config.incoming_warning_threshold = strtoul(argv[option_char++], NULL, 10);
302 } 295 }
303 296
304 if (argc > c && incoming_critical_threshold == 0) { 297 if (argc > option_char && result.config.incoming_critical_threshold == 0) {
305 incoming_critical_threshold = strtoul (argv[c++], NULL, 10); 298 result.config.incoming_critical_threshold = strtoul(argv[option_char++], NULL, 10);
306 } 299 }
307 300
308 if (argc > c && outgoing_warning_threshold == 0) { 301 if (argc > option_char && result.config.outgoing_warning_threshold == 0) {
309 outgoing_warning_threshold = strtoul (argv[c++], NULL, 10); 302 result.config.outgoing_warning_threshold = strtoul(argv[option_char++], NULL, 10);
310 } 303 }
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 304
305 if (argc > option_char && result.config.outgoing_critical_threshold == 0) {
306 result.config.outgoing_critical_threshold = strtoul(argv[option_char++], NULL, 10);
307 }
319 308
320int 309 return result;
321validate_arguments (void)
322{
323 return OK;
324} 310}
325 311
326 312void print_help(void) {
327void 313 print_revision(progname, NP_VERSION);
328print_help (void) 314
329{ 315 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
330 print_revision (progname, NP_VERSION); 316 printf(COPYRIGHT, copyright, email);
331 317
332 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 318 printf("%s\n", _("This plugin will check the incoming/outgoing transfer rates of a router,"));
333 printf (COPYRIGHT, copyright, email); 319 printf("%s\n", _("switch, etc recorded in an MRTG log. If the newest log entry is older"));
334 320 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,")); 321 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")); 322 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")); 323 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")); 324
339 printf ("%s\n", _("Bytes/sec), a CRITICAL status results. If either of the rates exceed")); 325 printf("\n\n");
340 printf ("%s\n", _("the <iwl> or <owl> thresholds (in Bytes/sec), a WARNING status results.")); 326
341 327 print_usage();
342 printf ("\n\n"); 328
343 329 printf(UT_HELP_VRSN);
344 print_usage (); 330 printf(UT_EXTRA_OPTS);
345 331
346 printf (UT_HELP_VRSN); 332 printf(" %s\n", "-F, --filename=STRING");
347 printf (UT_EXTRA_OPTS); 333 printf(" %s\n", _("File to read log from"));
348 334 printf(" %s\n", "-e, --expires=INTEGER");
349 printf (" %s\n", "-F, --filename=STRING"); 335 printf(" %s\n", _("Minutes after which log expires"));
350 printf (" %s\n", _("File to read log from")); 336 printf(" %s\n", "-a, --aggregation=(AVG|MAX)");
351 printf (" %s\n", "-e, --expires=INTEGER"); 337 printf(" %s\n", _("Test average or maximum"));
352 printf (" %s\n", _("Minutes after which log expires")); 338 printf(" %s\n", "-w, --warning");
353 printf (" %s\n", "-a, --aggregation=(AVG|MAX)"); 339 printf(" %s\n", _("Warning threshold pair <incoming>,<outgoing>"));
354 printf (" %s\n", _("Test average or maximum")); 340 printf(" %s\n", "-c, --critical");
355 printf (" %s\n", "-w, --warning"); 341 printf(" %s\n", _("Critical threshold pair <incoming>,<outgoing>"));
356 printf (" %s\n", _("Warning threshold pair <incoming>,<outgoing>")); 342
357 printf (" %s\n", "-c, --critical"); 343 printf("\n");
358 printf (" %s\n", _("Critical threshold pair <incoming>,<outgoing>")); 344 printf("%s\n", _("Notes:"));
359 345 printf(" %s\n", _("- MRTG stands for Multi Router Traffic Grapher. It can be downloaded from"));
360 printf ("\n"); 346 printf(" %s\n", " http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html");
361 printf ("%s\n", _("Notes:")); 347 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")); 348 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"); 349 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")); 350 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.")); 351 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")); 352
367 printf (" %s\n", _(" reports. I'm not sure why this is right now, but will look into it")); 353 printf(UT_SUPPORT);
368 printf (" %s\n", _(" for future enhancements of this plugin."));
369
370 printf (UT_SUPPORT);
371} 354}
372 355
373 356void print_usage(void) {
374 357 printf(_("Usage"));
375void 358 printf(" %s -F <log_file> -a <AVG | MAX> -w <warning_pair>\n", progname);
376print_usage (void) 359 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} 360}
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 6a7daf11..6134d6c6 100644
--- a/plugins/check_mysql.c
+++ b/plugins/check_mysql.c
@@ -1,444 +1,495 @@
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;
62int check_slave = 0, warn_sec = 0, crit_sec = 0;
63int ignore_auth = 0;
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",
72 "Open_tables", 54 "Threads_connected", "Threads_running"};
73 "Qcache_free_memory",
74 "Qcache_queries_in_cache",
75 "Threads_connected",
76 "Threads_running"
77};
78 55
79#define LENGTH_METRIC_COUNTER 9 56#define LENGTH_METRIC_COUNTER 9
80static const char *metric_counter[LENGTH_METRIC_COUNTER] = { 57static const char *metric_counter[LENGTH_METRIC_COUNTER] = {"Connections",
81 "Connections", 58 "Qcache_hits",
82 "Qcache_hits", 59 "Qcache_inserts",
83 "Qcache_inserts", 60 "Qcache_lowmem_prunes",
84 "Qcache_lowmem_prunes", 61 "Qcache_not_cached",
85 "Qcache_not_cached", 62 "Queries",
86 "Queries", 63 "Questions",
87 "Questions", 64 "Table_locks_waited",
88 "Table_locks_waited", 65 "Uptime"};
89 "Uptime" 66
90}; 67#define MYSQLDUMP_THREADS_QUERY \
91 68 "SELECT COUNT(1) mysqldumpThreads FROM information_schema.processlist WHERE info LIKE " \
92#define MYSQLDUMP_THREADS_QUERY "SELECT COUNT(1) mysqldumpThreads FROM information_schema.processlist WHERE info LIKE 'SELECT /*!40001 SQL_NO_CACHE */%'" 69 "'SELECT /*!40001 SQL_NO_CACHE */%'"
93 70
94thresholds *my_threshold = NULL; 71typedef struct {
95 72 int errorcode;
96int process_arguments (int, char **); 73 check_mysql_config config;
97int validate_arguments (void); 74} check_mysql_config_wrapper;
98void print_help (void); 75static check_mysql_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
99void print_usage (void); 76static check_mysql_config_wrapper validate_arguments(check_mysql_config_wrapper /*config_wrapper*/);
100 77static void print_help(void);
101int 78void print_usage(void);
102main (int argc, char **argv) 79
103{ 80int main(int argc, char **argv) {
81 setlocale(LC_ALL, "");
82 bindtextdomain(PACKAGE, LOCALEDIR);
83 textdomain(PACKAGE);
104 84
105 MYSQL mysql; 85 /* Parse extra opts if any */
106 MYSQL_RES *res; 86 argv = np_extra_opts(&argc, argv, progname);
107 MYSQL_ROW row;
108
109 /* should be status */
110 87
111 char *result = NULL; 88 check_mysql_config_wrapper tmp_config = process_arguments(argc, argv);
112 char *error = NULL; 89 if (tmp_config.errorcode == ERROR) {
113 char slaveresult[SLAVERESULTSIZE] = { 0 }; 90 usage4(_("Could not parse arguments"));
114 char* perf; 91 }
115 92
116 perf = strdup (""); 93 const check_mysql_config config = tmp_config.config;
117 94
118 setlocale (LC_ALL, ""); 95 MYSQL mysql;
119 bindtextdomain (PACKAGE, LOCALEDIR); 96 /* initialize mysql */
120 textdomain (PACKAGE); 97 mysql_init(&mysql);
121 98
122 /* Parse extra opts if any */ 99 if (config.opt_file != NULL) {
123 argv=np_extra_opts (&argc, argv, progname); 100 mysql_options(&mysql, MYSQL_READ_DEFAULT_FILE, config.opt_file);
101 }
124 102
125 if (process_arguments (argc, argv) == ERROR) 103 if (config.opt_group != NULL) {
126 usage4 (_("Could not parse arguments")); 104 mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, config.opt_group);
105 } else {
106 mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "client");
107 }
127 108
128 /* initialize mysql */ 109 if (config.ssl) {
129 mysql_init (&mysql); 110 mysql_ssl_set(&mysql, config.key, config.cert, config.ca_cert, config.ca_dir,
130 111 config.ciphers);
131 if (opt_file != NULL) 112 }
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 */ 113 /* 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)) { 114 if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db,
115 config.db_port, config.db_socket, 0)) {
143 /* Depending on internally-selected auth plugin MySQL might return */ 116 /* Depending on internally-selected auth plugin MySQL might return */
144 /* ER_ACCESS_DENIED_NO_PASSWORD_ERROR or ER_ACCESS_DENIED_ERROR. */ 117 /* ER_ACCESS_DENIED_NO_PASSWORD_ERROR or ER_ACCESS_DENIED_ERROR. */
145 /* Semantically these errors are the same. */ 118 /* 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)) 119 if (config.ignore_auth && (mysql_errno(&mysql) == ER_ACCESS_DENIED_ERROR ||
147 { 120 mysql_errno(&mysql) == ER_ACCESS_DENIED_NO_PASSWORD_ERROR)) {
148 printf("MySQL OK - Version: %s (protocol %d)\n", 121 printf("MySQL OK - Version: %s (protocol %d)\n", mysql_get_server_info(&mysql),
149 mysql_get_server_info(&mysql), 122 mysql_get_proto_info(&mysql));
150 mysql_get_proto_info(&mysql) 123 mysql_close(&mysql);
151 );
152 mysql_close (&mysql);
153 return STATE_OK; 124 return STATE_OK;
154 } 125 }
155 else if (mysql_errno (&mysql) == CR_UNKNOWN_HOST) 126
156 die (STATE_WARNING, "%s\n", mysql_error (&mysql)); 127 if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) {
157 else if (mysql_errno (&mysql) == CR_VERSION_ERROR) 128 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
158 die (STATE_WARNING, "%s\n", mysql_error (&mysql)); 129 } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) {
159 else if (mysql_errno (&mysql) == CR_OUT_OF_MEMORY) 130 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
160 die (STATE_WARNING, "%s\n", mysql_error (&mysql)); 131 } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) {
161 else if (mysql_errno (&mysql) == CR_IPSOCK_ERROR) 132 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
162 die (STATE_WARNING, "%s\n", mysql_error (&mysql)); 133 } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) {
163 else if (mysql_errno (&mysql) == CR_SOCKET_CREATE_ERROR) 134 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
164 die (STATE_WARNING, "%s\n", mysql_error (&mysql)); 135 } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) {
165 else 136 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
166 die (STATE_CRITICAL, "%s\n", mysql_error (&mysql)); 137 } else {
138 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql));
139 }
167 } 140 }
168 141
169 /* get the server stats */ 142 /* get the server stats */
170 result = strdup (mysql_stat (&mysql)); 143 char *result = strdup(mysql_stat(&mysql));
171 144
172 /* error checking once more */ 145 /* error checking once more */
173 if (mysql_error (&mysql)) { 146 if (mysql_error(&mysql)) {
174 if (mysql_errno (&mysql) == CR_SERVER_GONE_ERROR) 147 if (mysql_errno(&mysql) == CR_SERVER_GONE_ERROR) {
175 die (STATE_CRITICAL, "%s\n", mysql_error (&mysql)); 148 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql));
176 else if (mysql_errno (&mysql) == CR_SERVER_LOST) 149 } else if (mysql_errno(&mysql) == CR_SERVER_LOST) {
177 die (STATE_CRITICAL, "%s\n", mysql_error (&mysql)); 150 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql));
178 else if (mysql_errno (&mysql) == CR_UNKNOWN_ERROR) 151 } else if (mysql_errno(&mysql) == CR_UNKNOWN_ERROR) {
179 die (STATE_CRITICAL, "%s\n", mysql_error (&mysql)); 152 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql));
153 }
180 } 154 }
181 155
156 char *perf = strdup("");
157 char *error = NULL;
158 MYSQL_RES *res;
159 MYSQL_ROW row;
182 /* try to fetch some perf data */ 160 /* try to fetch some perf data */
183 if (mysql_query (&mysql, "show global status") == 0) { 161 if (mysql_query(&mysql, "show global status") == 0) {
184 if ( (res = mysql_store_result (&mysql)) == NULL) { 162 if ((res = mysql_store_result(&mysql)) == NULL) {
185 error = strdup(mysql_error(&mysql)); 163 error = strdup(mysql_error(&mysql));
186 mysql_close (&mysql); 164 mysql_close(&mysql);
187 die (STATE_CRITICAL, _("status store_result error: %s\n"), error); 165 die(STATE_CRITICAL, _("status store_result error: %s\n"), error);
188 } 166 }
189 167
190 while ( (row = mysql_fetch_row (res)) != NULL) { 168 while ((row = mysql_fetch_row(res)) != NULL) {
191 int i; 169 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) { 170 if (strcmp(row[0], metric_unit[i]) == 0) {
195 xasprintf(&perf, "%s%s ", perf, perfdata(metric_unit[i], 171 xasprintf(&perf, "%s%s ", perf,
196 atol(row[1]), "", false, 0, false, 0, false, 0, false, 0)); 172 perfdata(metric_unit[i], atol(row[1]), "", false, 0, false, 0, false,
173 0, false, 0));
197 continue; 174 continue;
198 } 175 }
199 } 176 }
200 for(i = 0; i < LENGTH_METRIC_COUNTER; i++) { 177 for (int i = 0; i < LENGTH_METRIC_COUNTER; i++) {
201 if (strcmp(row[0], metric_counter[i]) == 0) { 178 if (strcmp(row[0], metric_counter[i]) == 0) {
202 xasprintf(&perf, "%s%s ", perf, perfdata(metric_counter[i], 179 xasprintf(&perf, "%s%s ", perf,
203 atol(row[1]), "c", false, 0, false, 0, false, 0, false, 0)); 180 perfdata(metric_counter[i], atol(row[1]), "c", false, 0, false, 0,
181 false, 0, false, 0));
204 continue; 182 continue;
205 } 183 }
206 } 184 }
207 } 185 }
208 /* remove trailing space */ 186 /* remove trailing space */
209 if (strlen(perf) > 0) 187 if (strlen(perf) > 0) {
210 perf[strlen(perf) - 1] = '\0'; 188 perf[strlen(perf) - 1] = '\0';
189 }
211 } 190 }
212 191
213 if(check_slave) { 192 char replica_result[REPLICA_RESULTSIZE] = {0};
214 /* check the slave status */ 193 if (config.check_replica) {
215 if (mysql_query (&mysql, "show slave status") != 0) { 194 // Detect which version we are, on older version
195 // "show slave status" should work, on newer ones
196 // "show replica status"
197 // But first we have to find out whether this is
198 // MySQL or MariaDB since the version numbering scheme
199 // is different
200 bool use_deprecated_slave_status = false;
201 const char *server_version = mysql_get_server_info(&mysql);
202 unsigned long server_verion_int = mysql_get_server_version(&mysql);
203 unsigned long major_version = server_verion_int / 10000;
204 unsigned long minor_version = (server_verion_int % 10000) / 100;
205 unsigned long patch_version = (server_verion_int % 100);
206 if (verbose) {
207 printf("Found MariaDB: %s, main version: %lu, minor version: %lu, patch version: %lu\n",
208 server_version, major_version, minor_version, patch_version);
209 }
210
211 if (strstr(server_version, "MariaDB") != NULL) {
212 // Looks like MariaDB, new commands should be available after 10.5.1
213 if (major_version < 10) {
214 use_deprecated_slave_status = true;
215 } else if (major_version == 10) {
216 if (minor_version < 5) {
217 use_deprecated_slave_status = true;
218 } else if (minor_version == 5 && patch_version < 1) {
219 use_deprecated_slave_status = true;
220 }
221 }
222 } else {
223 // Looks like MySQL or at least not like MariaDB
224 if (major_version < 8) {
225 use_deprecated_slave_status = true;
226 } else if (major_version == 10 && minor_version < 4) {
227 use_deprecated_slave_status = true;
228 }
229 }
230
231 char *replica_query = NULL;
232 if (use_deprecated_slave_status) {
233 replica_query = "show slave status";
234 } else {
235 replica_query = "show replica status";
236 }
237
238 /* check the replica status */
239 if (mysql_query(&mysql, replica_query) != 0) {
216 error = strdup(mysql_error(&mysql)); 240 error = strdup(mysql_error(&mysql));
217 mysql_close (&mysql); 241 mysql_close(&mysql);
218 die (STATE_CRITICAL, _("slave query error: %s\n"), error); 242 die(STATE_CRITICAL, _("replica query error: %s\n"), error);
219 } 243 }
220 244
221 /* store the result */ 245 /* store the result */
222 if ( (res = mysql_store_result (&mysql)) == NULL) { 246 if ((res = mysql_store_result(&mysql)) == NULL) {
223 error = strdup(mysql_error(&mysql)); 247 error = strdup(mysql_error(&mysql));
224 mysql_close (&mysql); 248 mysql_close(&mysql);
225 die (STATE_CRITICAL, _("slave store_result error: %s\n"), error); 249 die(STATE_CRITICAL, _("replica store_result error: %s\n"), error);
226 } 250 }
227 251
228 /* Check there is some data */ 252 /* Check there is some data */
229 if (mysql_num_rows(res) == 0) { 253 if (mysql_num_rows(res) == 0) {
230 mysql_close(&mysql); 254 mysql_close(&mysql);
231 die (STATE_WARNING, "%s\n", _("No slaves defined")); 255 die(STATE_WARNING, "%s\n", _("No replicas defined"));
232 } 256 }
233 257
234 /* fetch the first row */ 258 /* fetch the first row */
235 if ( (row = mysql_fetch_row (res)) == NULL) { 259 if ((row = mysql_fetch_row(res)) == NULL) {
236 error = strdup(mysql_error(&mysql)); 260 error = strdup(mysql_error(&mysql));
237 mysql_free_result (res); 261 mysql_free_result(res);
238 mysql_close (&mysql); 262 mysql_close(&mysql);
239 die (STATE_CRITICAL, _("slave fetch row error: %s\n"), error); 263 die(STATE_CRITICAL, _("replica fetch row error: %s\n"), error);
240 } 264 }
241 265
242 if (mysql_field_count (&mysql) == 12) { 266 if (mysql_field_count(&mysql) == 12) {
243 /* mysql 3.23.x */ 267 /* mysql 3.23.x */
244 snprintf (slaveresult, SLAVERESULTSIZE, _("Slave running: %s"), row[6]); 268 snprintf(replica_result, REPLICA_RESULTSIZE, _("Replica running: %s"), row[6]);
245 if (strcmp (row[6], "Yes") != 0) { 269 if (strcmp(row[6], "Yes") != 0) {
246 mysql_free_result (res); 270 mysql_free_result(res);
247 mysql_close (&mysql); 271 mysql_close(&mysql);
248 die (STATE_CRITICAL, "%s\n", slaveresult); 272 die(STATE_CRITICAL, "%s\n", replica_result);
249 } 273 }
250 274
251 } else { 275 } else {
252 /* mysql 4.x.x and mysql 5.x.x */ 276 /* 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; 277 int replica_io_field = -1;
254 MYSQL_FIELD* fields; 278 int replica_sql_field = -1;
255 279 int seconds_behind_field = -1;
280 int num_fields;
281 MYSQL_FIELD *fields;
256 num_fields = mysql_num_fields(res); 282 num_fields = mysql_num_fields(res);
257 fields = mysql_fetch_fields(res); 283 fields = mysql_fetch_fields(res);
258 for(i = 0; i < num_fields; i++) { 284 for (int i = 0; i < num_fields; i++) {
259 if (strcmp(fields[i].name, "Slave_IO_Running") == 0) { 285 if (use_deprecated_slave_status) {
260 slave_io_field = i; 286 if (strcmp(fields[i].name, "Slave_IO_Running") == 0) {
261 continue; 287 replica_io_field = i;
262 } 288 continue;
263 if (strcmp(fields[i].name, "Slave_SQL_Running") == 0) { 289 }
264 slave_sql_field = i; 290 if (strcmp(fields[i].name, "Slave_SQL_Running") == 0) {
265 continue; 291 replica_sql_field = i;
266 } 292 continue;
267 if (strcmp(fields[i].name, "Seconds_Behind_Master") == 0) { 293 }
268 seconds_behind_field = i; 294 if (strcmp(fields[i].name, "Seconds_Behind_Master") == 0) {
269 continue; 295 seconds_behind_field = i;
296 continue;
297 }
298 } else {
299 if (strcmp(fields[i].name, "Replica_IO_Running") == 0) {
300 replica_io_field = i;
301 continue;
302 }
303 if (strcmp(fields[i].name, "Replica_SQL_Running") == 0) {
304 replica_sql_field = i;
305 continue;
306 }
307 if (strcmp(fields[i].name, "Seconds_Behind_Source") == 0) {
308 seconds_behind_field = i;
309 continue;
310 }
270 } 311 }
271 } 312 }
272 313
273 /* Check if slave status is available */ 314 /* Check if replica status is available */
274 if ((slave_io_field < 0) || (slave_sql_field < 0) || (num_fields == 0)) { 315 if ((replica_io_field < 0) || (replica_sql_field < 0) || (num_fields == 0)) {
275 mysql_free_result (res); 316 mysql_free_result(res);
276 mysql_close (&mysql); 317 mysql_close(&mysql);
277 die (STATE_CRITICAL, "Slave status unavailable\n"); 318 die(STATE_CRITICAL, "Replica status unavailable\n");
278 } 319 }
279 320
280 /* Save slave status in slaveresult */ 321 /* 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"); 322 snprintf(replica_result, REPLICA_RESULTSIZE,
323 "Replica IO: %s Replica SQL: %s Seconds Behind Master: %s",
324 row[replica_io_field], row[replica_sql_field],
325 seconds_behind_field != -1 ? row[seconds_behind_field] : "Unknown");
282 326
283 /* Raise critical error if SQL THREAD or IO THREAD are stopped, but only if there are no mysqldump threads running */ 327 /* Raise critical error if SQL THREAD or IO THREAD are stopped, but only if there are no
284 if (strcmp (row[slave_io_field], "Yes") != 0 || strcmp (row[slave_sql_field], "Yes") != 0) { 328 * mysqldump threads running */
329 if (strcmp(row[replica_io_field], "Yes") != 0 ||
330 strcmp(row[replica_sql_field], "Yes") != 0) {
285 MYSQL_RES *res_mysqldump; 331 MYSQL_RES *res_mysqldump;
286 MYSQL_ROW row_mysqldump; 332 MYSQL_ROW row_mysqldump;
287 unsigned int mysqldump_threads = 0; 333 unsigned int mysqldump_threads = 0;
288 334
289 if (mysql_query (&mysql, MYSQLDUMP_THREADS_QUERY) == 0) { 335 if (mysql_query(&mysql, MYSQLDUMP_THREADS_QUERY) == 0) {
290 /* store the result */ 336 /* store the result */
291 if ( (res_mysqldump = mysql_store_result (&mysql)) != NULL) { 337 if ((res_mysqldump = mysql_store_result(&mysql)) != NULL) {
292 if (mysql_num_rows(res_mysqldump) == 1) { 338 if (mysql_num_rows(res_mysqldump) == 1) {
293 if ( (row_mysqldump = mysql_fetch_row (res_mysqldump)) != NULL) { 339 if ((row_mysqldump = mysql_fetch_row(res_mysqldump)) != NULL) {
294 mysqldump_threads = atoi(row_mysqldump[0]); 340 mysqldump_threads = atoi(row_mysqldump[0]);
295 } 341 }
296 } 342 }
297 /* free the result */ 343 /* free the result */
298 mysql_free_result (res_mysqldump); 344 mysql_free_result(res_mysqldump);
299 } 345 }
300 mysql_close (&mysql); 346 mysql_close(&mysql);
301 } 347 }
302 if (mysqldump_threads == 0) { 348 if (mysqldump_threads == 0) {
303 die (STATE_CRITICAL, "%s\n", slaveresult); 349 die(STATE_CRITICAL, "%s\n", replica_result);
304 } else { 350 } else {
305 strncat(slaveresult, " Mysqldump: in progress", SLAVERESULTSIZE-1); 351 strncat(replica_result, " Mysqldump: in progress", REPLICA_RESULTSIZE - 1);
306 } 352 }
307 } 353 }
308 354
309 if (verbose >=3) { 355 if (verbose >= 3) {
310 if (seconds_behind_field == -1) { 356 if (seconds_behind_field == -1) {
311 printf("seconds_behind_field not found\n"); 357 printf("seconds_behind_field not found\n");
312 } else { 358 } else {
313 printf ("seconds_behind_field(index %d)=%s\n", seconds_behind_field, row[seconds_behind_field]); 359 printf("seconds_behind_field(index %d)=%s\n", seconds_behind_field,
360 row[seconds_behind_field]);
314 } 361 }
315 } 362 }
316 363
317 /* Check Seconds Behind against threshold */ 364 /* Check Seconds Behind against threshold */
318 if ((seconds_behind_field != -1) && (row[seconds_behind_field] != NULL && strcmp (row[seconds_behind_field], "NULL") != 0)) { 365 if ((seconds_behind_field != -1) && (row[seconds_behind_field] != NULL &&
366 strcmp(row[seconds_behind_field], "NULL") != 0)) {
319 double value = atof(row[seconds_behind_field]); 367 double value = atof(row[seconds_behind_field]);
320 int status; 368 int status;
321 369
322 status = get_status(value, my_threshold); 370 status = get_status(value, config.my_threshold);
323 371
324 xasprintf (&perf, "%s %s", perf, fperfdata ("seconds behind master", value, "s", 372 xasprintf(&perf, "%s %s", perf,
325 true, (double) warning_time, 373 fperfdata("seconds behind master", value, "s", true,
326 true, (double) critical_time, 374 (double)config.warning_time, true, (double)config.critical_time,
327 false, 0, 375 false, 0, false, 0));
328 false, 0));
329 376
330 if (status == STATE_WARNING) { 377 if (status == STATE_WARNING) {
331 printf("SLOW_SLAVE %s: %s|%s\n", _("WARNING"), slaveresult, perf); 378 printf("SLOW_REPLICA %s: %s|%s\n", _("WARNING"), replica_result, perf);
332 exit(STATE_WARNING); 379 exit(STATE_WARNING);
333 } else if (status == STATE_CRITICAL) { 380 } else if (status == STATE_CRITICAL) {
334 printf("SLOW_SLAVE %s: %s|%s\n", _("CRITICAL"), slaveresult, perf); 381 printf("SLOW_REPLICA %s: %s|%s\n", _("CRITICAL"), replica_result, perf);
335 exit(STATE_CRITICAL); 382 exit(STATE_CRITICAL);
336 } 383 }
337 } 384 }
338 } 385 }
339 386
340 /* free the result */ 387 /* free the result */
341 mysql_free_result (res); 388 mysql_free_result(res);
342 } 389 }
343 390
344 /* close the connection */ 391 /* close the connection */
345 mysql_close (&mysql); 392 mysql_close(&mysql);
346 393
347 /* print out the result of stats */ 394 /* print out the result of stats */
348 if (check_slave) { 395 if (config.check_replica) {
349 printf ("%s %s|%s\n", result, slaveresult, perf); 396 printf("%s %s|%s\n", result, replica_result, perf);
350 } else { 397 } else {
351 printf ("%s|%s\n", result, perf); 398 printf("%s|%s\n", result, perf);
352 } 399 }
353 400
354 return STATE_OK; 401 return STATE_OK;
355} 402}
356 403
404#define CHECK_REPLICA_OPT CHAR_MAX + 1
357 405
358/* process command-line arguments */ 406/* process command-line arguments */
359int 407check_mysql_config_wrapper process_arguments(int argc, char **argv) {
360process_arguments (int argc, char **argv) 408 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
361{ 409 {"socket", required_argument, 0, 's'},
362 int c; 410 {"database", required_argument, 0, 'd'},
411 {"username", required_argument, 0, 'u'},
412 {"password", required_argument, 0, 'p'},
413 {"file", required_argument, 0, 'f'},
414 {"group", required_argument, 0, 'g'},
415 {"port", required_argument, 0, 'P'},
416 {"critical", required_argument, 0, 'c'},
417 {"warning", required_argument, 0, 'w'},
418 {"check-slave", no_argument, 0, 'S'},
419 {"check-replica", no_argument, 0, CHECK_REPLICA_OPT},
420 {"ignore-auth", no_argument, 0, 'n'},
421 {"verbose", no_argument, 0, 'v'},
422 {"version", no_argument, 0, 'V'},
423 {"help", no_argument, 0, 'h'},
424 {"ssl", no_argument, 0, 'l'},
425 {"ca-cert", optional_argument, 0, 'C'},
426 {"key", required_argument, 0, 'k'},
427 {"cert", required_argument, 0, 'a'},
428 {"ca-dir", required_argument, 0, 'D'},
429 {"ciphers", required_argument, 0, 'L'},
430 {0, 0, 0, 0}};
431
432 check_mysql_config_wrapper result = {
433 .errorcode = OK,
434 .config = check_mysql_config_init(),
435 };
436
437 if (argc < 1) {
438 result.errorcode = ERROR;
439 return result;
440 }
441
363 char *warning = NULL; 442 char *warning = NULL;
364 char *critical = NULL; 443 char *critical = NULL;
365 444
366 int option = 0; 445 int option = 0;
367 static struct option longopts[] = { 446 while (true) {
368 {"hostname", required_argument, 0, 'H'}, 447 int option_index =
369 {"socket", required_argument, 0, 's'}, 448 getopt_long(argc, argv, "hlvVnSP:p:u:d:H:s:c:w:a:k:C:D:L:f:g:", longopts, &option);
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
392 if (argc < 1)
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 449
398 if (c == -1 || c == EOF) 450 if (option_index == -1 || option_index == EOF) {
399 break; 451 break;
452 }
400 453
401 switch (c) { 454 switch (option_index) {
402 case 'H': /* hostname */ 455 case 'H': /* hostname */
403 if (is_host (optarg)) { 456 if (is_host(optarg)) {
404 db_host = optarg; 457 result.config.db_host = optarg;
405 } 458 } else if (*optarg == '/') {
406 else if (*optarg == '/') { 459 result.config.db_socket = optarg;
407 db_socket = optarg; 460 } else {
408 } 461 usage2(_("Invalid hostname/address"), optarg);
409 else {
410 usage2 (_("Invalid hostname/address"), optarg);
411 } 462 }
412 break; 463 break;
413 case 's': /* socket */ 464 case 's': /* socket */
414 db_socket = optarg; 465 result.config.db_socket = optarg;
415 break; 466 break;
416 case 'd': /* database */ 467 case 'd': /* database */
417 db = optarg; 468 result.config.db = optarg;
418 break; 469 break;
419 case 'l': 470 case 'l':
420 ssl = true; 471 result.config.ssl = true;
421 break; 472 break;
422 case 'C': 473 case 'C':
423 ca_cert = optarg; 474 result.config.ca_cert = optarg;
424 break; 475 break;
425 case 'a': 476 case 'a':
426 cert = optarg; 477 result.config.cert = optarg;
427 break; 478 break;
428 case 'k': 479 case 'k':
429 key = optarg; 480 result.config.key = optarg;
430 break; 481 break;
431 case 'D': 482 case 'D':
432 ca_dir = optarg; 483 result.config.ca_dir = optarg;
433 break; 484 break;
434 case 'L': 485 case 'L':
435 ciphers = optarg; 486 result.config.ciphers = optarg;
436 break; 487 break;
437 case 'u': /* username */ 488 case 'u': /* username */
438 db_user = optarg; 489 result.config.db_user = optarg;
439 break; 490 break;
440 case 'p': /* authentication information: password */ 491 case 'p': /* authentication information: password */
441 db_pass = strdup(optarg); 492 result.config.db_pass = strdup(optarg);
442 493
443 /* Delete the password from process list */ 494 /* Delete the password from process list */
444 while (*optarg != '\0') { 495 while (*optarg != '\0') {
@@ -446,167 +497,166 @@ process_arguments (int argc, char **argv)
446 optarg++; 497 optarg++;
447 } 498 }
448 break; 499 break;
449 case 'f': /* client options file */ 500 case 'f': /* client options file */
450 opt_file = optarg; 501 result.config.opt_file = optarg;
451 break; 502 break;
452 case 'g': /* client options group */ 503 case 'g': /* client options group */
453 opt_group = optarg; 504 result.config.opt_group = optarg;
454 break; 505 break;
455 case 'P': /* critical time threshold */ 506 case 'P': /* critical time threshold */
456 db_port = atoi (optarg); 507 result.config.db_port = atoi(optarg);
457 break; 508 break;
458 case 'S': 509 case 'S':
459 check_slave = 1; /* check-slave */ 510 case CHECK_REPLICA_OPT:
511 result.config.check_replica = true; /* check-slave */
460 break; 512 break;
461 case 'n': 513 case 'n':
462 ignore_auth = 1; /* ignore-auth */ 514 result.config.ignore_auth = true; /* ignore-auth */
463 break; 515 break;
464 case 'w': 516 case 'w':
465 warning = optarg; 517 warning = optarg;
466 warning_time = strtod (warning, NULL); 518 result.config.warning_time = strtod(warning, NULL);
467 break; 519 break;
468 case 'c': 520 case 'c':
469 critical = optarg; 521 critical = optarg;
470 critical_time = strtod (critical, NULL); 522 result.config.critical_time = strtod(critical, NULL);
471 break; 523 break;
472 case 'V': /* version */ 524 case 'V': /* version */
473 print_revision (progname, NP_VERSION); 525 print_revision(progname, NP_VERSION);
474 exit (STATE_UNKNOWN); 526 exit(STATE_UNKNOWN);
475 case 'h': /* help */ 527 case 'h': /* help */
476 print_help (); 528 print_help();
477 exit (STATE_UNKNOWN); 529 exit(STATE_UNKNOWN);
478 case 'v': 530 case 'v':
479 verbose++; 531 verbose++;
480 break; 532 break;
481 case '?': /* help */ 533 case '?': /* help */
482 usage5 (); 534 usage5();
483 } 535 }
484 } 536 }
485 537
486 c = optind; 538 int index = optind;
487
488 set_thresholds(&my_threshold, warning, critical);
489 539
490 while ( argc > c ) { 540 set_thresholds(&result.config.my_threshold, warning, critical);
491 541
492 if (db_host == NULL) 542 while (argc > index) {
493 if (is_host (argv[c])) { 543 if (result.config.db_host == NULL) {
494 db_host = argv[c++]; 544 if (is_host(argv[index])) {
545 result.config.db_host = argv[index++];
546 } else {
547 usage2(_("Invalid hostname/address"), argv[index]);
495 } 548 }
496 else { 549 } else if (result.config.db_user == NULL) {
497 usage2 (_("Invalid hostname/address"), argv[c]); 550 result.config.db_user = argv[index++];
498 } 551 } else if (result.config.db_pass == NULL) {
499 else if (db_user == NULL) 552 result.config.db_pass = argv[index++];
500 db_user = argv[c++]; 553 } else if (result.config.db == NULL) {
501 else if (db_pass == NULL) 554 result.config.db = argv[index++];
502 db_pass = argv[c++]; 555 } else if (is_intnonneg(argv[index])) {
503 else if (db == NULL) 556 result.config.db_port = atoi(argv[index++]);
504 db = argv[c++]; 557 } else {
505 else if (is_intnonneg (argv[c]))
506 db_port = atoi (argv[c++]);
507 else
508 break; 558 break;
559 }
509 } 560 }
510 561
511 return validate_arguments (); 562 return validate_arguments(result);
512} 563}
513 564
565check_mysql_config_wrapper validate_arguments(check_mysql_config_wrapper config_wrapper) {
566 if (config_wrapper.config.db_user == NULL) {
567 config_wrapper.config.db_user = strdup("");
568 }
514 569
515int 570 if (config_wrapper.config.db_host == NULL) {
516validate_arguments (void) 571 config_wrapper.config.db_host = strdup("");
517{ 572 }
518 if (db_user == NULL)
519 db_user = strdup("");
520
521 if (db_host == NULL)
522 db_host = strdup("");
523 573
524 if (db == NULL) 574 if (config_wrapper.config.db == NULL) {
525 db = strdup(""); 575 config_wrapper.config.db = strdup("");
576 }
526 577
527 return OK; 578 return config_wrapper;
528} 579}
529 580
530 581void print_help(void) {
531void
532print_help (void)
533{
534 char *myport; 582 char *myport;
535 xasprintf (&myport, "%d", MYSQL_PORT); 583 xasprintf(&myport, "%d", MYSQL_PORT);
536 584
537 print_revision (progname, NP_VERSION); 585 print_revision(progname, NP_VERSION);
538 586
539 printf (_(COPYRIGHT), copyright, email); 587 printf(_(COPYRIGHT), copyright, email);
540 588
541 printf ("%s\n", _("This program tests connections to a MySQL server")); 589 printf("%s\n", _("This program tests connections to a MySQL server"));
542 590
543 printf ("\n\n"); 591 printf("\n\n");
544 592
545 print_usage (); 593 print_usage();
546 594
547 printf (UT_HELP_VRSN); 595 printf(UT_HELP_VRSN);
548 printf (UT_EXTRA_OPTS); 596 printf(UT_EXTRA_OPTS);
549 597
550 printf (UT_HOST_PORT, 'P', myport); 598 printf(UT_HOST_PORT, 'P', myport);
551 printf (" %s\n", "-n, --ignore-auth"); 599 printf(" %s\n", "-n, --ignore-auth");
552 printf (" %s\n", _("Ignore authentication failure and check for mysql connectivity only")); 600 printf(" %s\n", _("Ignore authentication failure and check for mysql connectivity only"));
553 601
554 printf (" %s\n", "-s, --socket=STRING"); 602 printf(" %s\n", "-s, --socket=STRING");
555 printf (" %s\n", _("Use the specified socket (has no effect if -H is used)")); 603 printf(" %s\n", _("Use the specified socket (has no effect if -H is used)"));
556 604
557 printf (" %s\n", "-d, --database=STRING"); 605 printf(" %s\n", "-d, --database=STRING");
558 printf (" %s\n", _("Check database with indicated name")); 606 printf(" %s\n", _("Check database with indicated name"));
559 printf (" %s\n", "-f, --file=STRING"); 607 printf(" %s\n", "-f, --file=STRING");
560 printf (" %s\n", _("Read from the specified client options file")); 608 printf(" %s\n", _("Read from the specified client options file"));
561 printf (" %s\n", "-g, --group=STRING"); 609 printf(" %s\n", "-g, --group=STRING");
562 printf (" %s\n", _("Use a client options group")); 610 printf(" %s\n", _("Use a client options group"));
563 printf (" %s\n", "-u, --username=STRING"); 611 printf(" %s\n", "-u, --username=STRING");
564 printf (" %s\n", _("Connect using the indicated username")); 612 printf(" %s\n", _("Connect using the indicated username"));
565 printf (" %s\n", "-p, --password=STRING"); 613 printf(" %s\n", "-p, --password=STRING");
566 printf (" %s\n", _("Use the indicated password to authenticate the connection")); 614 printf(" %s\n", _("Use the indicated password to authenticate the connection"));
567 printf (" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!")); 615 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")); 616 printf(" %s\n", _("Your clear-text password could be visible as a process table entry"));
569 printf (" %s\n", "-S, --check-slave"); 617 printf(" %s\n", "-S, --check-slave");
570 printf (" %s\n", _("Check if the slave thread is running properly.")); 618 printf(" %s\n", _("Check if the slave thread is running properly. This option is deprecated "
571 printf (" %s\n", "-w, --warning"); 619 "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")); 620 printf(" %s\n", "--check-replica");
573 printf (" %s\n", _("behind master")); 621 printf(" %s\n", _("Check if the replica thread is running properly."));
574 printf (" %s\n", "-c, --critical"); 622 printf(" %s\n", "-w, --warning");
575 printf (" %s\n", _("Exit with CRITICAL status if slave server is more then INTEGER seconds")); 623 printf(" %s\n",
576 printf (" %s\n", _("behind master")); 624 _("Exit with WARNING status if replica server is more than INTEGER seconds"));
577 printf (" %s\n", "-l, --ssl"); 625 printf(" %s\n", _("behind master"));
578 printf (" %s\n", _("Use ssl encryption")); 626 printf(" %s\n", "-c, --critical");
579 printf (" %s\n", "-C, --ca-cert=STRING"); 627 printf(" %s\n",
580 printf (" %s\n", _("Path to CA signing the cert")); 628 _("Exit with CRITICAL status if replica server is more then INTEGER seconds"));
581 printf (" %s\n", "-a, --cert=STRING"); 629 printf(" %s\n", _("behind master"));
582 printf (" %s\n", _("Path to SSL certificate")); 630 printf(" %s\n", "-l, --ssl");
583 printf (" %s\n", "-k, --key=STRING"); 631 printf(" %s\n", _("Use ssl encryption"));
584 printf (" %s\n", _("Path to private SSL key")); 632 printf(" %s\n", "-C, --ca-cert=STRING");
585 printf (" %s\n", "-D, --ca-dir=STRING"); 633 printf(" %s\n", _("Path to CA signing the cert"));
586 printf (" %s\n", _("Path to CA directory")); 634 printf(" %s\n", "-a, --cert=STRING");
587 printf (" %s\n", "-L, --ciphers=STRING"); 635 printf(" %s\n", _("Path to SSL certificate"));
588 printf (" %s\n", _("List of valid SSL ciphers")); 636 printf(" %s\n", "-k, --key=STRING");
589 637 printf(" %s\n", _("Path to private SSL key"));
590 638 printf(" %s\n", "-D, --ca-dir=STRING");
591 printf ("\n"); 639 printf(" %s\n", _("Path to CA directory"));
592 printf (" %s\n", _("There are no required arguments. By default, the local database is checked")); 640 printf(" %s\n", "-L, --ciphers=STRING");
593 printf (" %s\n", _("using the default unix socket. You can force TCP on localhost by using an")); 641 printf(" %s\n", _("List of valid SSL ciphers"));
594 printf (" %s\n", _("IP address or FQDN ('localhost' will use the socket as well).")); 642
595 643 printf("\n");
596 printf ("\n"); 644 printf(" %s\n",
597 printf ("%s\n", _("Notes:")); 645 _("There are no required arguments. By default, the local database is checked"));
598 printf (" %s\n", _("You must specify -p with an empty string to force an empty password,")); 646 printf(" %s\n", _("using the default unix socket. You can force TCP on localhost by using an"));
599 printf (" %s\n", _("overriding any my.cnf settings.")); 647 printf(" %s\n", _("IP address or FQDN ('localhost' will use the socket as well)."));
600 648
601 printf (UT_SUPPORT); 649 printf("\n");
650 printf("%s\n", _("Notes:"));
651 printf(" %s\n", _("You must specify -p with an empty string to force an empty password,"));
652 printf(" %s\n", _("overriding any my.cnf settings."));
653
654 printf(UT_SUPPORT);
602} 655}
603 656
604 657void print_usage(void) {
605void 658 printf("%s\n", _("Usage:"));
606print_usage (void) 659 printf(" %s [-d database] [-H host] [-P port] [-s socket]\n", progname);
607{ 660 printf(" [-u user] [-p password] [-S] [-l] [-a cert] [-k key]\n");
608 printf ("%s\n", _("Usage:")); 661 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} 662}
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..c7e84deb 100644
--- a/plugins/check_mysql_query.c
+++ b/plugins/check_mysql_query.c
@@ -1,157 +1,153 @@
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
50char *opt_group = NULL; 51 validate_arguments(check_mysql_query_config_wrapper /*config_wrapper*/);
51unsigned int db_port = MYSQL_PORT; 52static void print_help(void);
53void print_usage(void);
52 54
53int process_arguments (int, char **); 55static int verbose = 0;
54int validate_arguments (void);
55void print_help (void);
56void print_usage (void);
57 56
58char *sql_query = NULL; 57int main(int argc, char **argv) {
59int verbose = 0; 58 setlocale(LC_ALL, "");
60thresholds *my_thresholds = NULL; 59 bindtextdomain(PACKAGE, LOCALEDIR);
61 60 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 61
79 /* Parse extra opts if any */ 62 /* Parse extra opts if any */
80 argv=np_extra_opts (&argc, argv, progname); 63 argv = np_extra_opts(&argc, argv, progname);
81 64
82 if (process_arguments (argc, argv) == ERROR) 65 check_mysql_query_config_wrapper tmp_config = process_arguments(argc, argv);
83 usage4 (_("Could not parse arguments")); 66 if (tmp_config.errorcode == ERROR) {
67 usage4(_("Could not parse arguments"));
68 }
84 69
70 const check_mysql_query_config config = tmp_config.config;
71
72 MYSQL mysql;
85 /* initialize mysql */ 73 /* initialize mysql */
86 mysql_init (&mysql); 74 mysql_init(&mysql);
87 75
88 if (opt_file != NULL) 76 if (config.opt_file != NULL) {
89 mysql_options(&mysql,MYSQL_READ_DEFAULT_FILE,opt_file); 77 mysql_options(&mysql, MYSQL_READ_DEFAULT_FILE, config.opt_file);
78 }
90 79
91 if (opt_group != NULL) 80 if (config.opt_group != NULL) {
92 mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,opt_group); 81 mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, config.opt_group);
93 else 82 } else {
94 mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,"client"); 83 mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "client");
84 }
95 85
96 /* establish a connection to the server and error checking */ 86 /* 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)) { 87 if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db,
98 if (mysql_errno (&mysql) == CR_UNKNOWN_HOST) 88 config.db_port, config.db_socket, 0)) {
99 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql)); 89 if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) {
100 else if (mysql_errno (&mysql) == CR_VERSION_ERROR) 90 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
101 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql)); 91 } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) {
102 else if (mysql_errno (&mysql) == CR_OUT_OF_MEMORY) 92 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
103 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql)); 93 } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) {
104 else if (mysql_errno (&mysql) == CR_IPSOCK_ERROR) 94 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
105 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql)); 95 } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) {
106 else if (mysql_errno (&mysql) == CR_SOCKET_CREATE_ERROR) 96 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
107 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql)); 97 } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) {
108 else 98 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
109 die (STATE_CRITICAL, "QUERY %s: %s\n", _("CRITICAL"), mysql_error (&mysql)); 99 } else {
100 die(STATE_CRITICAL, "QUERY %s: %s\n", _("CRITICAL"), mysql_error(&mysql));
101 }
110 } 102 }
111 103
112 if (mysql_query (&mysql, sql_query) != 0) { 104 char *error = NULL;
105 if (mysql_query(&mysql, config.sql_query) != 0) {
113 error = strdup(mysql_error(&mysql)); 106 error = strdup(mysql_error(&mysql));
114 mysql_close (&mysql); 107 mysql_close(&mysql);
115 die (STATE_CRITICAL, "QUERY %s: %s - %s\n", _("CRITICAL"), _("Error with query"), error); 108 die(STATE_CRITICAL, "QUERY %s: %s - %s\n", _("CRITICAL"), _("Error with query"), error);
116 } 109 }
117 110
111 MYSQL_RES *res;
118 /* store the result */ 112 /* store the result */
119 if ( (res = mysql_store_result (&mysql)) == NULL) { 113 if ((res = mysql_store_result(&mysql)) == NULL) {
120 error = strdup(mysql_error(&mysql)); 114 error = strdup(mysql_error(&mysql));
121 mysql_close (&mysql); 115 mysql_close(&mysql);
122 die (STATE_CRITICAL, "QUERY %s: Error with store_result - %s\n", _("CRITICAL"), error); 116 die(STATE_CRITICAL, "QUERY %s: Error with store_result - %s\n", _("CRITICAL"), error);
123 } 117 }
124 118
125 /* Check there is some data */ 119 /* Check there is some data */
126 if (mysql_num_rows(res) == 0) { 120 if (mysql_num_rows(res) == 0) {
127 mysql_close(&mysql); 121 mysql_close(&mysql);
128 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), _("No rows returned")); 122 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), _("No rows returned"));
129 } 123 }
130 124
125 MYSQL_ROW row;
131 /* fetch the first row */ 126 /* fetch the first row */
132 if ( (row = mysql_fetch_row (res)) == NULL) { 127 if ((row = mysql_fetch_row(res)) == NULL) {
133 error = strdup(mysql_error(&mysql)); 128 error = strdup(mysql_error(&mysql));
134 mysql_free_result (res); 129 mysql_free_result(res);
135 mysql_close (&mysql); 130 mysql_close(&mysql);
136 die (STATE_CRITICAL, "QUERY %s: Fetch row error - %s\n", _("CRITICAL"), error); 131 die(STATE_CRITICAL, "QUERY %s: Fetch row error - %s\n", _("CRITICAL"), error);
137 } 132 }
138 133
139 if (! is_numeric(row[0])) { 134 if (!is_numeric(row[0])) {
140 die (STATE_CRITICAL, "QUERY %s: %s - '%s'\n", _("CRITICAL"), _("Is not a numeric"), row[0]); 135 die(STATE_CRITICAL, "QUERY %s: %s - '%s'\n", _("CRITICAL"), _("Is not a numeric"), row[0]);
141 } 136 }
142 137
143 value = strtod(row[0], NULL); 138 double value = strtod(row[0], NULL);
144 139
145 /* free the result */ 140 /* free the result */
146 mysql_free_result (res); 141 mysql_free_result(res);
147 142
148 /* close the connection */ 143 /* close the connection */
149 mysql_close (&mysql); 144 mysql_close(&mysql);
150 145
151 if (verbose >= 3) 146 if (verbose >= 3) {
152 printf("mysql result: %f\n", value); 147 printf("mysql result: %f\n", value);
148 }
153 149
154 status = get_status(value, my_thresholds); 150 int status = get_status(value, config.my_thresholds);
155 151
156 if (status == STATE_OK) { 152 if (status == STATE_OK) {
157 printf("QUERY %s: ", _("OK")); 153 printf("QUERY %s: ", _("OK"));
@@ -160,75 +156,75 @@ main (int argc, char **argv)
160 } else if (status == STATE_CRITICAL) { 156 } else if (status == STATE_CRITICAL) {
161 printf("QUERY %s: ", _("CRITICAL")); 157 printf("QUERY %s: ", _("CRITICAL"));
162 } 158 }
163 printf(_("'%s' returned %f | %s"), sql_query, value, 159 printf(_("'%s' returned %f | %s"), config.sql_query, value,
164 fperfdata("result", value, "", 160 fperfdata("result", value, "", config.my_thresholds->warning,
165 my_thresholds->warning?true:false, my_thresholds->warning?my_thresholds->warning->end:0, 161 config.my_thresholds->warning ? config.my_thresholds->warning->end : 0,
166 my_thresholds->critical?true:false, my_thresholds->critical?my_thresholds->critical->end:0, 162 config.my_thresholds->critical,
167 false, 0, 163 config.my_thresholds->critical ? config.my_thresholds->critical->end : 0,
168 false, 0) 164 false, 0, false, 0));
169 );
170 printf("\n"); 165 printf("\n");
171 166
172 return status; 167 return status;
173} 168}
174 169
175
176/* process command-line arguments */ 170/* process command-line arguments */
177int 171check_mysql_query_config_wrapper process_arguments(int argc, char **argv) {
178process_arguments (int argc, char **argv) 172 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
179{ 173 {"socket", required_argument, 0, 's'},
180 int c; 174 {"database", required_argument, 0, 'd'},
181 char *warning = NULL; 175 {"username", required_argument, 0, 'u'},
182 char *critical = NULL; 176 {"password", required_argument, 0, 'p'},
183 177 {"file", required_argument, 0, 'f'},
184 int option = 0; 178 {"group", required_argument, 0, 'g'},
185 static struct option longopts[] = { 179 {"port", required_argument, 0, 'P'},
186 {"hostname", required_argument, 0, 'H'}, 180 {"verbose", no_argument, 0, 'v'},
187 {"socket", required_argument, 0, 's'}, 181 {"version", no_argument, 0, 'V'},
188 {"database", required_argument, 0, 'd'}, 182 {"help", no_argument, 0, 'h'},
189 {"username", required_argument, 0, 'u'}, 183 {"query", required_argument, 0, 'q'},
190 {"password", required_argument, 0, 'p'}, 184 {"warning", required_argument, 0, 'w'},
191 {"file", required_argument, 0, 'f'}, 185 {"critical", required_argument, 0, 'c'},
192 {"group", required_argument, 0, 'g'}, 186 {0, 0, 0, 0}};
193 {"port", required_argument, 0, 'P'}, 187
194 {"verbose", no_argument, 0, 'v'}, 188 check_mysql_query_config_wrapper result = {
195 {"version", no_argument, 0, 'V'}, 189 .errorcode = OK,
196 {"help", no_argument, 0, 'h'}, 190 .config = check_mysql_query_config_init(),
197 {"query", required_argument, 0, 'q'},
198 {"warning", required_argument, 0, 'w'},
199 {"critical", required_argument, 0, 'c'},
200 {0, 0, 0, 0}
201 }; 191 };
202 192
203 if (argc < 1) 193 if (argc < 1) {
204 return ERROR; 194 result.errorcode = ERROR;
195 return result;
196 }
205 197
206 while (1) { 198 char *warning = NULL;
207 c = getopt_long (argc, argv, "hvVP:p:u:d:H:s:q:w:c:f:g:", longopts, &option); 199 char *critical = NULL;
208 200
209 if (c == -1 || c == EOF) 201 while (true) {
202 int option = 0;
203 int option_char = getopt_long(argc, argv, "hvVP:p:u:d:H:s:q:w:c:f:g:", longopts, &option);
204
205 if (option_char == -1 || option_char == EOF) {
210 break; 206 break;
207 }
211 208
212 switch (c) { 209 switch (option_char) {
213 case 'H': /* hostname */ 210 case 'H': /* hostname */
214 if (is_host (optarg)) { 211 if (is_host(optarg)) {
215 db_host = optarg; 212 result.config.db_host = optarg;
216 } 213 } else {
217 else { 214 usage2(_("Invalid hostname/address"), optarg);
218 usage2 (_("Invalid hostname/address"), optarg);
219 } 215 }
220 break; 216 break;
221 case 's': /* socket */ 217 case 's': /* socket */
222 db_socket = optarg; 218 result.config.db_socket = optarg;
223 break; 219 break;
224 case 'd': /* database */ 220 case 'd': /* database */
225 db = optarg; 221 result.config.db = optarg;
226 break; 222 break;
227 case 'u': /* username */ 223 case 'u': /* username */
228 db_user = optarg; 224 result.config.db_user = optarg;
229 break; 225 break;
230 case 'p': /* authentication information: password */ 226 case 'p': /* authentication information: password */
231 db_pass = strdup(optarg); 227 result.config.db_pass = strdup(optarg);
232 228
233 /* Delete the password from process list */ 229 /* Delete the password from process list */
234 while (*optarg != '\0') { 230 while (*optarg != '\0') {
@@ -236,26 +232,26 @@ process_arguments (int argc, char **argv)
236 optarg++; 232 optarg++;
237 } 233 }
238 break; 234 break;
239 case 'f': /* client options file */ 235 case 'f': /* client options file */
240 opt_file = optarg; 236 result.config.opt_file = optarg;
241 break; 237 break;
242 case 'g': /* client options group */ 238 case 'g': /* client options group */
243 opt_group = optarg; 239 result.config.opt_group = optarg;
244 break; 240 break;
245 case 'P': /* critical time threshold */ 241 case 'P': /* critical time threshold */
246 db_port = atoi (optarg); 242 result.config.db_port = atoi(optarg);
247 break; 243 break;
248 case 'v': 244 case 'v':
249 verbose++; 245 verbose++;
250 break; 246 break;
251 case 'V': /* version */ 247 case 'V': /* version */
252 print_revision (progname, NP_VERSION); 248 print_revision(progname, NP_VERSION);
253 exit (STATE_UNKNOWN); 249 exit(STATE_UNKNOWN);
254 case 'h': /* help */ 250 case 'h': /* help */
255 print_help (); 251 print_help();
256 exit (STATE_UNKNOWN); 252 exit(STATE_UNKNOWN);
257 case 'q': 253 case 'q':
258 xasprintf(&sql_query, "%s", optarg); 254 xasprintf(&result.config.sql_query, "%s", optarg);
259 break; 255 break;
260 case 'w': 256 case 'w':
261 warning = optarg; 257 warning = optarg;
@@ -263,92 +259,86 @@ process_arguments (int argc, char **argv)
263 case 'c': 259 case 'c':
264 critical = optarg; 260 critical = optarg;
265 break; 261 break;
266 case '?': /* help */ 262 case '?': /* help */
267 usage5 (); 263 usage5();
268 } 264 }
269 } 265 }
270 266
271 c = optind; 267 set_thresholds(&result.config.my_thresholds, warning, critical);
272 268
273 set_thresholds(&my_thresholds, warning, critical); 269 return validate_arguments(result);
274
275 return validate_arguments ();
276} 270}
277 271
278 272check_mysql_query_config_wrapper
279int 273validate_arguments(check_mysql_query_config_wrapper config_wrapper) {
280validate_arguments (void) 274 if (config_wrapper.config.sql_query == NULL) {
281{
282 if (sql_query == NULL)
283 usage("Must specify a SQL query to run"); 275 usage("Must specify a SQL query to run");
276 }
284 277
285 if (db_user == NULL) 278 if (config_wrapper.config.db_user == NULL) {
286 db_user = strdup(""); 279 config_wrapper.config.db_user = strdup("");
280 }
287 281
288 if (db_host == NULL) 282 if (config_wrapper.config.db_host == NULL) {
289 db_host = strdup(""); 283 config_wrapper.config.db_host = strdup("");
284 }
290 285
291 if (db == NULL) 286 if (config_wrapper.config.db == NULL) {
292 db = strdup(""); 287 config_wrapper.config.db = strdup("");
288 }
293 289
294 return OK; 290 return config_wrapper;
295} 291}
296 292
297 293void print_help(void) {
298void
299print_help (void)
300{
301 char *myport; 294 char *myport;
302 xasprintf (&myport, "%d", MYSQL_PORT); 295 xasprintf(&myport, "%d", MYSQL_PORT);
303 296
304 print_revision (progname, NP_VERSION); 297 print_revision(progname, NP_VERSION);
305 298
306 printf (_(COPYRIGHT), copyright, email); 299 printf(_(COPYRIGHT), copyright, email);
307 300
308 printf ("%s\n", _("This program checks a query result against threshold levels")); 301 printf("%s\n", _("This program checks a query result against threshold levels"));
309 302
310 printf ("\n\n"); 303 printf("\n\n");
311 304
312 print_usage (); 305 print_usage();
313 306
314 printf (UT_HELP_VRSN); 307 printf(UT_HELP_VRSN);
315 printf (UT_EXTRA_OPTS); 308 printf(UT_EXTRA_OPTS);
316 printf (" -q, --query=STRING\n"); 309 printf(" -q, --query=STRING\n");
317 printf (" %s\n", _("SQL query to run. Only first column in first row will be read")); 310 printf(" %s\n", _("SQL query to run. Only first column in first row will be read"));
318 printf (UT_WARN_CRIT_RANGE); 311 printf(UT_WARN_CRIT_RANGE);
319 printf (UT_HOST_PORT, 'P', myport); 312 printf(UT_HOST_PORT, 'P', myport);
320 printf (" %s\n", "-s, --socket=STRING"); 313 printf(" %s\n", "-s, --socket=STRING");
321 printf (" %s\n", _("Use the specified socket (has no effect if -H is used)")); 314 printf(" %s\n", _("Use the specified socket (has no effect if -H is used)"));
322 printf (" -d, --database=STRING\n"); 315 printf(" -d, --database=STRING\n");
323 printf (" %s\n", _("Database to check")); 316 printf(" %s\n", _("Database to check"));
324 printf (" %s\n", "-f, --file=STRING"); 317 printf(" %s\n", "-f, --file=STRING");
325 printf (" %s\n", _("Read from the specified client options file")); 318 printf(" %s\n", _("Read from the specified client options file"));
326 printf (" %s\n", "-g, --group=STRING"); 319 printf(" %s\n", "-g, --group=STRING");
327 printf (" %s\n", _("Use a client options group")); 320 printf(" %s\n", _("Use a client options group"));
328 printf (" -u, --username=STRING\n"); 321 printf(" -u, --username=STRING\n");
329 printf (" %s\n", _("Username to login with")); 322 printf(" %s\n", _("Username to login with"));
330 printf (" -p, --password=STRING\n"); 323 printf(" -p, --password=STRING\n");
331 printf (" %s\n", _("Password to login with")); 324 printf(" %s\n", _("Password to login with"));
332 printf (" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!")); 325 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")); 326 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 327
328 printf("\n");
329 printf(" %s\n", _("A query is required. The result from the query should be numeric."));
330 printf(" %s\n", _("For extra security, create a user with minimal access."));
331
332 printf("\n");
333 printf("%s\n", _("Notes:"));
334 printf(" %s\n", _("You must specify -p with an empty string to force an empty password,"));
335 printf(" %s\n", _("overriding any my.cnf settings."));
336
337 printf(UT_SUPPORT);
338}
347 339
348void 340void print_usage(void) {
349print_usage (void) 341 printf("%s\n", _("Usage:"));
350{ 342 printf(" %s -q SQL_query [-w warn] [-c crit] [-H host] [-P port] [-s socket]\n", progname);
351 printf ("%s\n", _("Usage:")); 343 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} 344}
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..35ca92cd 100644
--- a/plugins/check_nt.c
+++ b/plugins/check_nt.c
@@ -1,336 +1,313 @@
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"),
142 xasprintf (&output_message, _("Wrong client version - running: %s, required: %s"), recv_buffer, value_list); 100 recv_buffer, config.value_list);
143 return_code = STATE_WARNING; 101 return_code = STATE_WARNING;
144 } else { 102 } else {
145 xasprintf (&output_message, "%s", recv_buffer); 103 xasprintf(&output_message, "%s", recv_buffer);
146 return_code = STATE_OK; 104 return_code = STATE_OK;
147 } 105 }
148 break; 106 break;
149
150 case CHECK_CPULOAD: 107 case CHECK_CPULOAD:
151 108 if (config.value_list == NULL) {
152 if (value_list==NULL) 109 output_message = strdup(_("missing -l parameters"));
153 output_message = strdup (_("missing -l parameters")); 110 } else if (!strtoularray(lvalue_list, config.value_list, ",")) {
154 else if (! strtoularray(lvalue_list,value_list,",")) 111 output_message = strdup(_("wrong -l parameter."));
155 output_message = strdup (_("wrong -l parameter.")); 112 } else {
156 else {
157 /* -l parameters is present with only integers */ 113 /* -l parameters is present with only integers */
158 return_code=STATE_OK; 114 return_code = STATE_OK;
159 temp_string = strdup (_("CPU Load")); 115 temp_string = strdup(_("CPU Load"));
160 temp_string_perf = strdup (" "); 116 temp_string_perf = strdup(" ");
161 117
162 /* loop until one of the parameters is wrong or not present */ 118 /* loop until one of the parameters is wrong or not present */
163 while (lvalue_list[0+offset]> (unsigned long)0 && 119 int offset = 0;
164 lvalue_list[0+offset]<=(unsigned long)17280 && 120 while (lvalue_list[0 + offset] > (unsigned long)0 &&
165 lvalue_list[1+offset]> (unsigned long)0 && 121 lvalue_list[0 + offset] <= (unsigned long)17280 &&
166 lvalue_list[1+offset]<=(unsigned long)100 && 122 lvalue_list[1 + offset] > (unsigned long)0 &&
167 lvalue_list[2+offset]> (unsigned long)0 && 123 lvalue_list[1 + offset] <= (unsigned long)100 &&
168 lvalue_list[2+offset]<=(unsigned long)100) { 124 lvalue_list[2 + offset] > (unsigned long)0 &&
125 lvalue_list[2 + offset] <= (unsigned long)100) {
169 126
170 /* Send request and retrieve data */ 127 /* Send request and retrieve data */
171 xasprintf(&send_buffer,"%s&2&%lu",req_password,lvalue_list[0+offset]); 128 xasprintf(&send_buffer, "%s&2&%lu", config.req_password, lvalue_list[0 + offset]);
172 fetch_data (server_address, server_port, send_buffer); 129 fetch_data(config.server_address, config.server_port, send_buffer);
173 130
174 utilization=strtoul(recv_buffer,NULL,10); 131 unsigned long utilization = strtoul(recv_buffer, NULL, 10);
175 132
176 /* Check if any of the request is in a warning or critical state */ 133 /* Check if any of the request is in a warning or critical state */
177 if(utilization >= lvalue_list[2+offset]) 134 if (utilization >= lvalue_list[2 + offset]) {
178 return_code=STATE_CRITICAL; 135 return_code = STATE_CRITICAL;
179 else if(utilization >= lvalue_list[1+offset] && return_code<STATE_WARNING) 136 } else if (utilization >= lvalue_list[1 + offset] && return_code < STATE_WARNING) {
180 return_code=STATE_WARNING; 137 return_code = STATE_WARNING;
181 138 }
182 xasprintf(&output_message,_(" %lu%% (%lu min average)"), utilization, lvalue_list[0+offset]); 139
183 xasprintf(&temp_string,"%s%s",temp_string,output_message); 140 xasprintf(&output_message, _(" %lu%% (%lu min average)"), utilization,
184 xasprintf(&perfdata,_(" '%lu min avg Load'=%lu%%;%lu;%lu;0;100"), lvalue_list[0+offset], utilization, 141 lvalue_list[0 + offset]);
185 lvalue_list[1+offset], lvalue_list[2+offset]); 142 xasprintf(&temp_string, "%s%s", temp_string, output_message);
186 xasprintf(&temp_string_perf,"%s%s",temp_string_perf,perfdata); 143 xasprintf(&perfdata, _(" '%lu min avg Load'=%lu%%;%lu;%lu;0;100"),
187 offset+=3; /* move across the array */ 144 lvalue_list[0 + offset], utilization, lvalue_list[1 + offset],
145 lvalue_list[2 + offset]);
146 xasprintf(&temp_string_perf, "%s%s", temp_string_perf, perfdata);
147 offset += 3; /* move across the array */
188 } 148 }
189 149
190 if (strlen(temp_string)>10) { /* we had at least one loop */ 150 if (strlen(temp_string) > 10) { /* we had at least one loop */
191 output_message = strdup (temp_string); 151 output_message = strdup(temp_string);
192 perfdata = temp_string_perf; 152 perfdata = temp_string_perf;
193 } else 153 } else {
194 output_message = strdup (_("not enough values for -l parameters")); 154 output_message = strdup(_("not enough values for -l parameters"));
155 }
195 } 156 }
196 break; 157 break;
197 158 case CHECK_UPTIME: {
198 case CHECK_UPTIME: 159 char *tmp_value_list = config.value_list;
199 160 if (config.value_list == NULL) {
200 if (value_list == NULL) { 161 tmp_value_list = "minutes";
201 value_list = "minutes";
202 } 162 }
203 if (strncmp(value_list, "seconds", strlen("seconds") + 1 ) && 163 if (strncmp(tmp_value_list, "seconds", strlen("seconds") + 1) &&
204 strncmp(value_list, "minutes", strlen("minutes") + 1) && 164 strncmp(tmp_value_list, "minutes", strlen("minutes") + 1) &&
205 strncmp(value_list, "hours", strlen("hours") + 1) && 165 strncmp(config.value_list, "hours", strlen("hours") + 1) &&
206 strncmp(value_list, "days", strlen("days") + 1)) { 166 strncmp(tmp_value_list, "days", strlen("days") + 1)) {
207 167
208 output_message = strdup (_("wrong -l argument")); 168 output_message = strdup(_("wrong -l argument"));
209 } else { 169 } else {
210 xasprintf(&send_buffer, "%s&3", req_password); 170 xasprintf(&send_buffer, "%s&3", config.req_password);
211 fetch_data (server_address, server_port, send_buffer); 171 fetch_data(config.server_address, config.server_port, send_buffer);
212 uptime=strtoul(recv_buffer,NULL,10); 172 unsigned long uptime = strtoul(recv_buffer, NULL, 10);
213 updays = uptime / 86400; 173 int updays = uptime / 86400;
214 uphours = (uptime % 86400) / 3600; 174 int uphours = (uptime % 86400) / 3600;
215 upminutes = ((uptime % 86400) % 3600) / 60; 175 int upminutes = ((uptime % 86400) % 3600) / 60;
216 176
217 if (!strncmp(value_list, "minutes", strlen("minutes"))) 177 if (!strncmp(tmp_value_list, "minutes", strlen("minutes"))) {
218 uptime = uptime / 60; 178 uptime = uptime / 60;
219 else if (!strncmp(value_list, "hours", strlen("hours"))) 179 } else if (!strncmp(tmp_value_list, "hours", strlen("hours"))) {
220 uptime = uptime / 3600; 180 uptime = uptime / 3600;
221 else if (!strncmp(value_list, "days", strlen("days"))) 181 } else if (!strncmp(tmp_value_list, "days", strlen("days"))) {
222 uptime = uptime / 86400; 182 uptime = uptime / 86400;
183 }
223 /* else uptime in seconds, nothing to do */ 184 /* else uptime in seconds, nothing to do */
224 185
225 xasprintf(&output_message,_("System Uptime - %u day(s) %u hour(s) %u minute(s) |uptime=%lu"),updays, uphours, upminutes, uptime); 186 xasprintf(&output_message,
187 _("System Uptime - %u day(s) %u hour(s) %u minute(s) |uptime=%lu"), updays,
188 uphours, upminutes, uptime);
226 189
227 if (check_critical_value && uptime <= critical_value) 190 if (config.check_critical_value && uptime <= config.critical_value) {
228 return_code=STATE_CRITICAL; 191 return_code = STATE_CRITICAL;
229 else if (check_warning_value && uptime <= warning_value) 192 } else if (config.check_warning_value && uptime <= config.warning_value) {
230 return_code=STATE_WARNING; 193 return_code = STATE_WARNING;
231 else 194 } else {
232 return_code=STATE_OK; 195 return_code = STATE_OK;
196 }
233 } 197 }
234 break; 198 } break;
235
236 case CHECK_USEDDISKSPACE: 199 case CHECK_USEDDISKSPACE:
200 if (config.value_list == NULL) {
201 output_message = strdup(_("missing -l parameters"));
202 } else if (strlen(config.value_list) != 1) {
203 output_message = strdup(_("wrong -l argument"));
204 } else {
205 xasprintf(&send_buffer, "%s&4&%s", config.req_password, config.value_list);
206 fetch_data(config.server_address, config.server_port, send_buffer);
207 char *fds = strtok(recv_buffer, "&");
208 char *tds = strtok(NULL, "&");
209 double total_disk_space = 0;
210 double free_disk_space = 0;
211 if (fds != NULL) {
212 free_disk_space = atof(fds);
213 }
214 if (tds != NULL) {
215 total_disk_space = atof(tds);
216 }
237 217
238 if (value_list==NULL) 218 if (total_disk_space > 0 && free_disk_space >= 0) {
239 output_message = strdup (_("missing -l parameters")); 219 double percent_used_space =
240 else if (strlen(value_list)!=1) 220 ((total_disk_space - free_disk_space) / total_disk_space) * 100;
241 output_message = strdup (_("wrong -l argument")); 221 double warning_used_space = ((float)config.warning_value / 100) * total_disk_space;
242 else { 222 double critical_used_space =
243 xasprintf(&send_buffer,"%s&4&%s", req_password, value_list); 223 ((float)config.critical_value / 100) * total_disk_space;
244 fetch_data (server_address, server_port, send_buffer); 224
245 fds=strtok(recv_buffer,"&"); 225 xasprintf(
246 tds=strtok(NULL,"&"); 226 &temp_string,
247 if(fds!=NULL) 227 _("%s:\\ - total: %.2f Gb - used: %.2f Gb (%.0f%%) - free %.2f Gb (%.0f%%)"),
248 free_disk_space=atof(fds); 228 config.value_list, total_disk_space / 1073741824,
249 if(tds!=NULL) 229 (total_disk_space - free_disk_space) / 1073741824, percent_used_space,
250 total_disk_space=atof(tds); 230 free_disk_space / 1073741824, (free_disk_space / total_disk_space) * 100);
251 231 xasprintf(&temp_string_perf, _("'%s:\\ Used Space'=%.2fGb;%.2f;%.2f;0.00;%.2f"),
252 if (total_disk_space>0 && free_disk_space>=0) { 232 config.value_list, (total_disk_space - free_disk_space) / 1073741824,
253 percent_used_space = ((total_disk_space - free_disk_space) / total_disk_space) * 100; 233 warning_used_space / 1073741824, critical_used_space / 1073741824,
254 warning_used_space = ((float)warning_value / 100) * total_disk_space; 234 total_disk_space / 1073741824);
255 critical_used_space = ((float)critical_value / 100) * total_disk_space; 235
256 236 if (config.check_critical_value && percent_used_space >= config.critical_value) {
257 xasprintf(&temp_string,_("%s:\\ - total: %.2f Gb - used: %.2f Gb (%.0f%%) - free %.2f Gb (%.0f%%)"), 237 return_code = STATE_CRITICAL;
258 value_list, total_disk_space / 1073741824, (total_disk_space - free_disk_space) / 1073741824, 238 } else if (config.check_warning_value &&
259 percent_used_space, free_disk_space / 1073741824, (free_disk_space / total_disk_space)*100); 239 percent_used_space >= config.warning_value) {
260 xasprintf(&temp_string_perf,_("'%s:\\ Used Space'=%.2fGb;%.2f;%.2f;0.00;%.2f"), value_list, 240 return_code = STATE_WARNING;
261 (total_disk_space - free_disk_space) / 1073741824, warning_used_space / 1073741824, 241 } else {
262 critical_used_space / 1073741824, total_disk_space / 1073741824); 242 return_code = STATE_OK;
263 243 }
264 if(check_critical_value && percent_used_space >= critical_value) 244
265 return_code=STATE_CRITICAL; 245 output_message = strdup(temp_string);
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; 246 perfdata = temp_string_perf;
273 } else { 247 } else {
274 output_message = strdup (_("Free disk space : Invalid drive")); 248 output_message = strdup(_("Free disk space : Invalid drive"));
275 return_code=STATE_UNKNOWN; 249 return_code = STATE_UNKNOWN;
276 } 250 }
277 } 251 }
278 break; 252 break;
279
280 case CHECK_SERVICESTATE: 253 case CHECK_SERVICESTATE:
281 case CHECK_PROCSTATE: 254 case CHECK_PROCSTATE:
282 255 if (config.value_list == NULL) {
283 if (value_list==NULL) 256 output_message = strdup(_("No service/process specified"));
284 output_message = strdup (_("No service/process specified")); 257 } else {
285 else { 258 preparelist(
286 preparelist(value_list); /* replace , between services with & to send the request */ 259 config.value_list); /* replace , between services with & to send the request */
287 xasprintf(&send_buffer,"%s&%u&%s&%s", req_password,(vars_to_check==CHECK_SERVICESTATE)?5:6, 260 xasprintf(&send_buffer, "%s&%u&%s&%s", config.req_password,
288 (show_all) ? "ShowAll" : "ShowFail",value_list); 261 (config.vars_to_check == CHECK_SERVICESTATE) ? 5 : 6,
289 fetch_data (server_address, server_port, send_buffer); 262 (config.show_all) ? "ShowAll" : "ShowFail", config.value_list);
290 numstr = strtok(recv_buffer,"&"); 263 fetch_data(config.server_address, config.server_port, send_buffer);
291 if (numstr == NULL) 264 char *numstr = strtok(recv_buffer, "&");
265 if (numstr == NULL) {
292 die(STATE_UNKNOWN, _("could not fetch information from server\n")); 266 die(STATE_UNKNOWN, _("could not fetch information from server\n"));
293 return_code=atoi(numstr); 267 }
294 temp_string=strtok(NULL,"&"); 268 return_code = atoi(numstr);
295 output_message = strdup (temp_string); 269 temp_string = strtok(NULL, "&");
270 output_message = strdup(temp_string);
296 } 271 }
297 break; 272 break;
298
299 case CHECK_MEMUSE: 273 case CHECK_MEMUSE:
300 274 xasprintf(&send_buffer, "%s&7", config.req_password);
301 xasprintf(&send_buffer,"%s&7", req_password); 275 fetch_data(config.server_address, config.server_port, send_buffer);
302 fetch_data (server_address, server_port, send_buffer); 276 char *numstr = strtok(recv_buffer, "&");
303 numstr = strtok(recv_buffer,"&"); 277 if (numstr == NULL) {
304 if (numstr == NULL)
305 die(STATE_UNKNOWN, _("could not fetch information from server\n")); 278 die(STATE_UNKNOWN, _("could not fetch information from server\n"));
306 mem_commitLimit=atof(numstr); 279 }
307 numstr = strtok(NULL,"&"); 280 double mem_commitLimit = atof(numstr);
308 if (numstr == NULL) 281 numstr = strtok(NULL, "&");
282 if (numstr == NULL) {
309 die(STATE_UNKNOWN, _("could not fetch information from server\n")); 283 die(STATE_UNKNOWN, _("could not fetch information from server\n"));
310 mem_commitByte=atof(numstr); 284 }
311 percent_used_space = (mem_commitByte / mem_commitLimit) * 100; 285 double mem_commitByte = atof(numstr);
312 warning_used_space = ((float)warning_value / 100) * mem_commitLimit; 286 double percent_used_space = (mem_commitByte / mem_commitLimit) * 100;
313 critical_used_space = ((float)critical_value / 100) * mem_commitLimit; 287 double warning_used_space = ((float)config.warning_value / 100) * mem_commitLimit;
288 double critical_used_space = ((float)config.critical_value / 100) * mem_commitLimit;
314 289
315 /* Divisor should be 1048567, not 3044515, as we are measuring "Commit Charge" here, 290 /* Divisor should be 1048567, not 3044515, as we are measuring "Commit Charge" here,
316 which equals RAM + Pagefiles. */ 291 which equals RAM + Pagefiles. */
317 xasprintf(&output_message,_("Memory usage: total:%.2f MB - used: %.2f MB (%.0f%%) - free: %.2f MB (%.0f%%)"), 292 xasprintf(
318 mem_commitLimit / 1048567, mem_commitByte / 1048567, percent_used_space, 293 &output_message,
319 (mem_commitLimit - mem_commitByte) / 1048567, (mem_commitLimit - mem_commitByte) / mem_commitLimit * 100); 294 _("Memory usage: total:%.2f MB - used: %.2f MB (%.0f%%) - free: %.2f MB (%.0f%%)"),
320 xasprintf(&perfdata,_("'Memory usage'=%.2fMB;%.2f;%.2f;0.00;%.2f"), mem_commitByte / 1048567, 295 mem_commitLimit / 1048567, mem_commitByte / 1048567, percent_used_space,
321 warning_used_space / 1048567, critical_used_space / 1048567, mem_commitLimit / 1048567); 296 (mem_commitLimit - mem_commitByte) / 1048567,
322 297 (mem_commitLimit - mem_commitByte) / mem_commitLimit * 100);
323 return_code=STATE_OK; 298 xasprintf(&perfdata, _("'Memory usage'=%.2fMB;%.2f;%.2f;0.00;%.2f"),
324 if(check_critical_value && percent_used_space >= critical_value) 299 mem_commitByte / 1048567, warning_used_space / 1048567,
325 return_code=STATE_CRITICAL; 300 critical_used_space / 1048567, mem_commitLimit / 1048567);
326 else if (check_warning_value && percent_used_space >= warning_value) 301
327 return_code=STATE_WARNING; 302 return_code = STATE_OK;
303 if (config.check_critical_value && percent_used_space >= config.critical_value) {
304 return_code = STATE_CRITICAL;
305 } else if (config.check_warning_value && percent_used_space >= config.warning_value) {
306 return_code = STATE_WARNING;
307 }
328 308
329 break; 309 break;
330 310 case CHECK_COUNTER: {
331 case CHECK_COUNTER:
332
333
334 /* 311 /*
335 CHECK_COUNTER has been modified to provide extensive perfdata information. 312 CHECK_COUNTER has been modified to provide extensive perfdata information.
336 In order to do this, some modifications have been done to the code 313 In order to do this, some modifications have been done to the code
@@ -347,455 +324,466 @@ int main(int argc, char **argv){
347 the counter unit - that is, the dimensions of the counter you're getting. Examples: 324 the counter unit - that is, the dimensions of the counter you're getting. Examples:
348 pages/s, packets transferred, etc. 325 pages/s, packets transferred, etc.
349 326
350 4) If you want, you may provide the minimum and maximum values to expect. They aren't mandatory, 327 4) If you want, you may provide the minimum and maximum values to expect. They aren't
351 but once specified they MUST have the same order of magnitude and units of -w and -c; otherwise. 328 mandatory, but once specified they MUST have the same order of magnitude and units of -w and
352 strange things will happen when you make graphs of your data. 329 -c; otherwise. strange things will happen when you make graphs of your data.
353 */ 330 */
354 331
355 if (value_list == NULL) 332 double counter_value = 0.0;
356 output_message = strdup (_("No counter specified")); 333 if (config.value_list == NULL) {
357 else 334 output_message = strdup(_("No counter specified"));
358 { 335 } else {
359 preparelist (value_list); /* replace , between services with & to send the request */ 336 preparelist(
360 isPercent = (strchr (value_list, '%') != NULL); 337 config.value_list); /* replace , between services with & to send the request */
361 338 bool isPercent = (strchr(config.value_list, '%') != NULL);
362 strtok (value_list, "&"); /* burn the first parameters */ 339
363 description = strtok (NULL, "&"); 340 strtok(config.value_list, "&"); /* burn the first parameters */
364 counter_unit = strtok (NULL, "&"); 341 description = strtok(NULL, "&");
365 xasprintf (&send_buffer, "%s&8&%s", req_password, value_list); 342 counter_unit = strtok(NULL, "&");
366 fetch_data (server_address, server_port, send_buffer); 343 xasprintf(&send_buffer, "%s&8&%s", config.req_password, config.value_list);
367 counter_value = atof (recv_buffer); 344 fetch_data(config.server_address, config.server_port, send_buffer);
368 345 counter_value = atof(recv_buffer);
369 if (description == NULL) 346
370 xasprintf (&output_message, "%.f", counter_value); 347 bool allRight = false;
371 else if (isPercent) 348 if (description == NULL) {
372 { 349 xasprintf(&output_message, "%.f", counter_value);
373 counter_unit = strdup ("%"); 350 } else if (isPercent) {
351 counter_unit = strdup("%");
374 allRight = true; 352 allRight = true;
375 } 353 }
376 354
377 if ((counter_unit != NULL) && (!allRight)) 355 char *minval = NULL;
378 { 356 char *maxval = NULL;
379 minval = strtok (NULL, "&"); 357 double fminval = 0;
380 maxval = strtok (NULL, "&"); 358 double fmaxval = 0;
359 if ((counter_unit != NULL) && (!allRight)) {
360 minval = strtok(NULL, "&");
361 maxval = strtok(NULL, "&");
381 362
382 /* All parameters specified. Let's check the numbers */ 363 /* All parameters specified. Let's check the numbers */
383 364
384 fminval = (minval != NULL) ? strtod (minval, &errcvt) : -1; 365 fminval = (minval != NULL) ? strtod(minval, &errcvt) : -1;
385 fmaxval = (minval != NULL) ? strtod (maxval, &errcvt) : -1; 366 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 367
368 if ((fminval == 0) && (minval == errcvt)) {
369 output_message = strdup(_("Minimum value contains non-numbers"));
370 } else {
371 if ((fmaxval == 0) && (maxval == errcvt)) {
372 output_message = strdup(_("Maximum value contains non-numbers"));
373 } else {
374 allRight = true; /* Everything is OK. */
375 }
396 } 376 }
377 } else if ((counter_unit == NULL) && (description != NULL)) {
378 output_message = strdup(_("No unit counter specified"));
397 } 379 }
398 else if ((counter_unit == NULL) && (description != NULL))
399 output_message = strdup (_("No unit counter specified"));
400 380
401 if (allRight) 381 if (allRight) {
402 {
403 /* Let's format the output string, finally... */ 382 /* Let's format the output string, finally... */
404 if (strstr(description, "%") == NULL) { 383 if (strstr(description, "%") == NULL) {
405 xasprintf (&output_message, "%s = %.2f %s", description, counter_value, counter_unit); 384 xasprintf(&output_message, "%s = %.2f %s", description, counter_value,
406 } else { 385 counter_unit);
407 /* has formatting, will segv if wrong */ 386 } else {
408 xasprintf (&output_message, description, counter_value); 387 /* has formatting, will segv if wrong */
409 } 388 xasprintf(&output_message, description, counter_value);
410 xasprintf (&output_message, "%s |", output_message); 389 }
411 xasprintf (&output_message,"%s %s", output_message, 390 xasprintf(&output_message, "%s |", output_message);
412 fperfdata (description, counter_value, 391 xasprintf(&output_message, "%s %s", output_message,
413 counter_unit, 1, warning_value, 1, critical_value, 392 fperfdata(description, counter_value, counter_unit, 1,
414 (!(isPercent) && (minval != NULL)), fminval, 393 config.warning_value, 1, config.critical_value,
415 (!(isPercent) && (minval != NULL)), fmaxval)); 394 (!(isPercent) && (minval != NULL)), fminval,
395 (!(isPercent) && (minval != NULL)), fmaxval));
416 } 396 }
417 } 397 }
418 398
419 if (critical_value > warning_value) 399 if (config.critical_value > config.warning_value) { /* Normal thresholds */
420 { /* Normal thresholds */ 400 if (config.check_critical_value && counter_value >= config.critical_value) {
421 if (check_critical_value && counter_value >= critical_value)
422 return_code = STATE_CRITICAL; 401 return_code = STATE_CRITICAL;
423 else if (check_warning_value && counter_value >= warning_value) 402 } else if (config.check_warning_value && counter_value >= config.warning_value) {
424 return_code = STATE_WARNING; 403 return_code = STATE_WARNING;
425 else 404 } else {
426 return_code = STATE_OK; 405 return_code = STATE_OK;
427 } 406 }
428 else 407 } else { /* inverse thresholds */
429 { /* inverse thresholds */
430 return_code = STATE_OK; 408 return_code = STATE_OK;
431 if (check_critical_value && counter_value <= critical_value) 409 if (config.check_critical_value && counter_value <= config.critical_value) {
432 return_code = STATE_CRITICAL; 410 return_code = STATE_CRITICAL;
433 else if (check_warning_value && counter_value <= warning_value) 411 } else if (config.check_warning_value && counter_value <= config.warning_value) {
434 return_code = STATE_WARNING; 412 return_code = STATE_WARNING;
413 }
435 } 414 }
436 break; 415 } break;
437
438 case CHECK_FILEAGE: 416 case CHECK_FILEAGE:
439 417 if (config.value_list == NULL) {
440 if (value_list==NULL) 418 output_message = strdup(_("No counter specified"));
441 output_message = strdup (_("No counter specified")); 419 } else {
442 else { 420 preparelist(
443 preparelist(value_list); /* replace , between services with & to send the request */ 421 config.value_list); /* replace , between services with & to send the request */
444 xasprintf(&send_buffer,"%s&9&%s", req_password,value_list); 422 xasprintf(&send_buffer, "%s&9&%s", config.req_password, config.value_list);
445 fetch_data (server_address, server_port, send_buffer); 423 fetch_data(config.server_address, config.server_port, send_buffer);
446 age_in_minutes = atoi(strtok(recv_buffer,"&")); 424 unsigned long age_in_minutes = atoi(strtok(recv_buffer, "&"));
447 description = strtok(NULL,"&"); 425 description = strtok(NULL, "&");
448 output_message = strdup (description); 426 output_message = strdup(description);
449 427
450 if (critical_value > warning_value) { /* Normal thresholds */ 428 if (config.critical_value > config.warning_value) { /* Normal thresholds */
451 if(check_critical_value && age_in_minutes >= critical_value) 429 if (config.check_critical_value && age_in_minutes >= config.critical_value) {
452 return_code=STATE_CRITICAL; 430 return_code = STATE_CRITICAL;
453 else if (check_warning_value && age_in_minutes >= warning_value) 431 } else if (config.check_warning_value && age_in_minutes >= config.warning_value) {
454 return_code=STATE_WARNING; 432 return_code = STATE_WARNING;
455 else 433 } else {
456 return_code=STATE_OK; 434 return_code = STATE_OK;
457 } 435 }
458 else { /* inverse thresholds */ 436 } else { /* inverse thresholds */
459 if(check_critical_value && age_in_minutes <= critical_value) 437 if (config.check_critical_value && age_in_minutes <= config.critical_value) {
460 return_code=STATE_CRITICAL; 438 return_code = STATE_CRITICAL;
461 else if (check_warning_value && age_in_minutes <= warning_value) 439 } else if (config.check_warning_value && age_in_minutes <= config.warning_value) {
462 return_code=STATE_WARNING; 440 return_code = STATE_WARNING;
463 else 441 } else {
464 return_code=STATE_OK; 442 return_code = STATE_OK;
443 }
465 } 444 }
466 } 445 }
467 break; 446 break;
468 447
469 case CHECK_INSTANCES: 448 case CHECK_INSTANCES:
470 if (value_list==NULL) 449 if (config.value_list == NULL) {
471 output_message = strdup (_("No counter specified")); 450 output_message = strdup(_("No counter specified"));
472 else { 451 } else {
473 xasprintf(&send_buffer,"%s&10&%s", req_password,value_list); 452 xasprintf(&send_buffer, "%s&10&%s", config.req_password, config.value_list);
474 fetch_data (server_address, server_port, send_buffer); 453 fetch_data(config.server_address, config.server_port, send_buffer);
475 if (!strncmp(recv_buffer,"ERROR",5)) { 454 if (!strncmp(recv_buffer, "ERROR", 5)) {
476 printf("NSClient - %s\n",recv_buffer); 455 printf("NSClient - %s\n", recv_buffer);
477 exit(STATE_UNKNOWN); 456 exit(STATE_UNKNOWN);
478 } 457 }
479 xasprintf(&output_message,"%s",recv_buffer); 458 xasprintf(&output_message, "%s", recv_buffer);
480 return_code=STATE_OK; 459 return_code = STATE_OK;
481 } 460 }
482 break; 461 break;
483 462
484 case CHECK_NONE: 463 case CHECK_NONE:
485 default: 464 default:
486 usage4 (_("Please specify a variable to check")); 465 usage4(_("Please specify a variable to check"));
487 break; 466 break;
488
489 } 467 }
490 468
491 /* reset timeout */ 469 /* reset timeout */
492 alarm(0); 470 alarm(0);
493 471
494 if (perfdata==NULL) 472 if (perfdata == NULL) {
495 printf("%s\n",output_message); 473 printf("%s\n", output_message);
496 else 474 } else {
497 printf("%s | %s\n",output_message,perfdata); 475 printf("%s | %s\n", output_message, perfdata);
476 }
498 return return_code; 477 return return_code;
499} 478}
500 479
501
502
503/* process command-line arguments */ 480/* process command-line arguments */
504int process_arguments(int argc, char **argv){ 481check_nt_config_wrapper process_arguments(int argc, char **argv) {
505 int c; 482 static struct option longopts[] = {{"port", required_argument, 0, 'p'},
506 483 {"timeout", required_argument, 0, 't'},
507 int option = 0; 484 {"critical", required_argument, 0, 'c'},
508 static struct option longopts[] = 485 {"warning", required_argument, 0, 'w'},
509 { 486 {"variable", required_argument, 0, 'v'},
510 {"port", required_argument,0,'p'}, 487 {"hostname", required_argument, 0, 'H'},
511 {"timeout", required_argument,0,'t'}, 488 {"params", required_argument, 0, 'l'},
512 {"critical", required_argument,0,'c'}, 489 {"secret", required_argument, 0, 's'},
513 {"warning", required_argument,0,'w'}, 490 {"display", required_argument, 0, 'd'},
514 {"variable", required_argument,0,'v'}, 491 {"unknown-timeout", no_argument, 0, 'u'},
515 {"hostname", required_argument,0,'H'}, 492 {"version", no_argument, 0, 'V'},
516 {"params", required_argument,0,'l'}, 493 {"help", no_argument, 0, 'h'},
517 {"secret", required_argument,0,'s'}, 494 {0, 0, 0, 0}};
518 {"display", required_argument,0,'d'}, 495
519 {"unknown-timeout", no_argument, 0, 'u'}, 496 check_nt_config_wrapper result = {
520 {"version", no_argument, 0,'V'}, 497 .errorcode = OK,
521 {"help", no_argument, 0,'h'}, 498 .config = check_nt_config_init(),
522 {0,0,0,0}
523 }; 499 };
524 500
525 /* no options were supplied */ 501 /* no options were supplied */
526 if(argc<2) return ERROR; 502 if (argc < 2) {
503 result.errorcode = ERROR;
504 return result;
505 }
527 506
528 /* backwards compatibility */ 507 /* backwards compatibility */
529 if (! is_option(argv[1])) { 508 if (!is_option(argv[1])) {
530 server_address = strdup(argv[1]); 509 result.config.server_address = strdup(argv[1]);
531 argv[1]=argv[0]; 510 argv[1] = argv[0];
532 argv=&argv[1]; 511 argv = &argv[1];
533 argc--; 512 argc--;
534 } 513 }
535 514
536 for (c=1;c<argc;c++) { 515 for (int index = 1; index < argc; index++) {
537 if(strcmp("-to",argv[c])==0) 516 if (strcmp("-to", argv[index]) == 0) {
538 strcpy(argv[c],"-t"); 517 strcpy(argv[index], "-t");
539 else if (strcmp("-wv",argv[c])==0) 518 } else if (strcmp("-wv", argv[index]) == 0) {
540 strcpy(argv[c],"-w"); 519 strcpy(argv[index], "-w");
541 else if (strcmp("-cv",argv[c])==0) 520 } else if (strcmp("-cv", argv[index]) == 0) {
542 strcpy(argv[c],"-c"); 521 strcpy(argv[index], "-c");
522 }
543 } 523 }
544 524
545 while (1) { 525 int option = 0;
546 c = getopt_long(argc,argv,"+hVH:t:c:w:p:v:l:s:d:u",longopts,&option); 526 while (true) {
527 int option_index = getopt_long(argc, argv, "+hVH:t:c:w:p:v:l:s:d:u", longopts, &option);
547 528
548 if (c==-1||c==EOF||c==1) 529 if (option_index == -1 || option_index == EOF || option_index == 1) {
549 break; 530 break;
531 }
550 532
551 switch (c) { 533 switch (option_index) {
552 case '?': /* print short usage statement if args not parsable */ 534 case '?': /* print short usage statement if args not parsable */
553 usage5 (); 535 usage5();
554 case 'h': /* help */ 536 case 'h': /* help */
555 print_help(); 537 print_help();
556 exit(STATE_UNKNOWN); 538 exit(STATE_UNKNOWN);
557 case 'V': /* version */ 539 case 'V': /* version */
558 print_revision(progname, NP_VERSION); 540 print_revision(progname, NP_VERSION);
559 exit(STATE_UNKNOWN); 541 exit(STATE_UNKNOWN);
560 case 'H': /* hostname */ 542 case 'H': /* hostname */
561 server_address = optarg; 543 result.config.server_address = optarg;
562 break; 544 break;
563 case 's': /* password */ 545 case 's': /* password */
564 req_password = optarg; 546 result.config.req_password = optarg;
565 break; 547 break;
566 case 'p': /* port */ 548 case 'p': /* port */
567 if (is_intnonneg(optarg)) 549 if (is_intnonneg(optarg)) {
568 server_port=atoi(optarg); 550 result.config.server_port = atoi(optarg);
569 else 551 } else {
570 die(STATE_UNKNOWN,_("Server port must be an integer\n")); 552 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 } 553 }
621 554 break;
555 case 'v':
556 if (strlen(optarg) < 4) {
557 result.errorcode = ERROR;
558 return result;
559 }
560 if (!strcmp(optarg, "CLIENTVERSION")) {
561 result.config.vars_to_check = CHECK_CLIENTVERSION;
562 } else if (!strcmp(optarg, "CPULOAD")) {
563 result.config.vars_to_check = CHECK_CPULOAD;
564 } else if (!strcmp(optarg, "UPTIME")) {
565 result.config.vars_to_check = CHECK_UPTIME;
566 } else if (!strcmp(optarg, "USEDDISKSPACE")) {
567 result.config.vars_to_check = CHECK_USEDDISKSPACE;
568 } else if (!strcmp(optarg, "SERVICESTATE")) {
569 result.config.vars_to_check = CHECK_SERVICESTATE;
570 } else if (!strcmp(optarg, "PROCSTATE")) {
571 result.config.vars_to_check = CHECK_PROCSTATE;
572 } else if (!strcmp(optarg, "MEMUSE")) {
573 result.config.vars_to_check = CHECK_MEMUSE;
574 } else if (!strcmp(optarg, "COUNTER")) {
575 result.config.vars_to_check = CHECK_COUNTER;
576 } else if (!strcmp(optarg, "FILEAGE")) {
577 result.config.vars_to_check = CHECK_FILEAGE;
578 } else if (!strcmp(optarg, "INSTANCES")) {
579 result.config.vars_to_check = CHECK_INSTANCES;
580 } else {
581 result.errorcode = ERROR;
582 return result;
583 }
584 break;
585 case 'l': /* value list */
586 result.config.value_list = optarg;
587 break;
588 case 'w': /* warning threshold */
589 result.config.warning_value = strtoul(optarg, NULL, 10);
590 result.config.check_warning_value = true;
591 break;
592 case 'c': /* critical threshold */
593 result.config.critical_value = strtoul(optarg, NULL, 10);
594 result.config.check_critical_value = true;
595 break;
596 case 'd': /* Display select for services */
597 if (!strcmp(optarg, "SHOWALL")) {
598 result.config.show_all = true;
599 }
600 break;
601 case 'u':
602 socket_timeout_state = STATE_UNKNOWN;
603 break;
604 case 't': /* timeout */
605 socket_timeout = atoi(optarg);
606 if (socket_timeout <= 0) {
607 result.errorcode = ERROR;
608 return result;
609 }
610 }
611 }
612 if (result.config.server_address == NULL) {
613 usage4(_("You must provide a server address or host name"));
622 } 614 }
623 if (server_address == NULL)
624 usage4 (_("You must provide a server address or host name"));
625 615
626 if (vars_to_check==CHECK_NONE) 616 if (result.config.vars_to_check == CHECK_NONE) {
627 return ERROR; 617 result.errorcode = ERROR;
618 return result;
619 }
628 620
629 if (req_password == NULL) 621 if (result.config.req_password == NULL) {
630 req_password = strdup (_("None")); 622 result.config.req_password = strdup(_("None"));
623 }
631 624
632 return OK; 625 return result;
633} 626}
634 627
628void fetch_data(const char *address, int port, const char *sendb) {
629 int result = process_tcp_request(address, port, sendb, recv_buffer, sizeof(recv_buffer));
635 630
631 if (result != STATE_OK) {
632 die(result, _("could not fetch information from server\n"));
633 }
636 634
637void fetch_data (const char *address, int port, const char *sendb) { 635 if (!strncmp(recv_buffer, "ERROR", 5)) {
638 int result; 636 die(STATE_UNKNOWN, "NSClient - %s\n", recv_buffer);
639 637 }
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} 638}
648 639
649bool strtoularray(unsigned long *array, char *string, const char *delim) { 640bool strtoularray(unsigned long *array, char *string, const char *delim) {
650 /* split a <delim> delimited string into a long array */ 641 /* split a <delim> delimited string into a long array */
651 int idx=0; 642 for (int idx = 0; idx < MAX_VALUE_LIST; idx++) {
652 char *t1; 643 array[idx] = 0;
653 644 }
654 for (idx=0;idx<MAX_VALUE_LIST;idx++)
655 array[idx]=0;
656 645
657 idx=0; 646 int idx = 0;
658 for(t1 = strtok(string,delim);t1 != NULL; t1 = strtok(NULL, delim)) { 647 for (char *t1 = strtok(string, delim); t1 != NULL; t1 = strtok(NULL, delim)) {
659 if (is_numeric(t1) && idx<MAX_VALUE_LIST) { 648 if (is_numeric(t1) && idx < MAX_VALUE_LIST) {
660 array[idx]=strtoul(t1,NULL,10); 649 array[idx] = strtoul(t1, NULL, 10);
661 idx++; 650 idx++;
662 } else 651 } else {
663 return false; 652 return false;
653 }
664 } 654 }
665 return true; 655 return true;
666} 656}
667 657
668void preparelist(char *string) { 658void preparelist(char *string) {
669 /* Replace all , with & which is the delimiter for the request */ 659 /* Replace all , with & which is the delimiter for the request */
670 int i; 660 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] == ',') { 661 if (string[i] == ',') {
674 string[i]='&'; 662 string[i] = '&';
675 } 663 }
664 }
676} 665}
677 666
678 667void print_help(void) {
679
680void print_help(void)
681{
682 print_revision(progname, NP_VERSION); 668 print_revision(progname, NP_VERSION);
683 669
684 printf ("Copyright (c) 2000 Yves Rubin (rubiyz@yahoo.com)\n"); 670 printf("Copyright (c) 2000 Yves Rubin (rubiyz@yahoo.com)\n");
685 printf (COPYRIGHT, copyright, email); 671 printf(COPYRIGHT, copyright, email);
686 672
687 printf ("%s\n", _("This plugin collects data from the NSClient service running on a")); 673 printf("%s\n", _("This plugin collects data from the NSClient service running on a"));
688 printf ("%s\n", _("Windows NT/2000/XP/2003 server.")); 674 printf("%s\n", _("Windows NT/2000/XP/2003 server."));
689 675
690 printf ("\n\n"); 676 printf("\n\n");
691 677
692 print_usage(); 678 print_usage();
693 679
694 printf (UT_HELP_VRSN); 680 printf(UT_HELP_VRSN);
695 printf (UT_EXTRA_OPTS); 681 printf(UT_EXTRA_OPTS);
696 682
697 printf ("%s\n", _("Options:")); 683 printf("%s\n", _("Options:"));
698 printf (" %s\n", "-H, --hostname=HOST"); 684 printf(" %s\n", "-H, --hostname=HOST");
699 printf (" %s\n", _("Name of the host to check")); 685 printf(" %s\n", _("Name of the host to check"));
700 printf (" %s\n", "-p, --port=INTEGER"); 686 printf(" %s\n", "-p, --port=INTEGER");
701 printf (" %s", _("Optional port number (default: ")); 687 printf(" %s", _("Optional port number (default: "));
702 printf ("%d)\n", PORT); 688 printf("%d)\n", PORT);
703 printf (" %s\n", "-s, --secret=<password>"); 689 printf(" %s\n", "-s, --secret=<password>");
704 printf (" %s\n", _("Password needed for the request")); 690 printf(" %s\n", _("Password needed for the request"));
705 printf (" %s\n", "-w, --warning=INTEGER"); 691 printf(" %s\n", "-w, --warning=INTEGER");
706 printf (" %s\n", _("Threshold which will result in a warning status")); 692 printf(" %s\n", _("Threshold which will result in a warning status"));
707 printf (" %s\n", "-c, --critical=INTEGER"); 693 printf(" %s\n", "-c, --critical=INTEGER");
708 printf (" %s\n", _("Threshold which will result in a critical status")); 694 printf(" %s\n", _("Threshold which will result in a critical status"));
709 printf (" %s\n", "-t, --timeout=INTEGER"); 695 printf(" %s\n", "-t, --timeout=INTEGER");
710 printf (" %s", _("Seconds before connection attempt times out (default: ")); 696 printf(" %s", _("Seconds before connection attempt times out (default: "));
711 printf (" %s\n", "-l, --params=<parameters>"); 697 printf(" %s\n", "-l, --params=<parameters>");
712 printf (" %s", _("Parameters passed to specified check (see below)")); 698 printf(" %s", _("Parameters passed to specified check (see below)"));
713 printf (" %s\n", "-d, --display={SHOWALL}"); 699 printf(" %s\n", "-d, --display={SHOWALL}");
714 printf (" %s", _("Display options (currently only SHOWALL works)")); 700 printf(" %s", _("Display options (currently only SHOWALL works)"));
715 printf (" %s\n", "-u, --unknown-timeout"); 701 printf(" %s\n", "-u, --unknown-timeout");
716 printf (" %s", _("Return UNKNOWN on timeouts")); 702 printf(" %s", _("Return UNKNOWN on timeouts"));
717 printf ("%d)\n", DEFAULT_SOCKET_TIMEOUT); 703 printf("%d)\n", DEFAULT_SOCKET_TIMEOUT);
718 printf (" %s\n", "-h, --help"); 704 printf(" %s\n", "-h, --help");
719 printf (" %s\n", _("Print this help screen")); 705 printf(" %s\n", _("Print this help screen"));
720 printf (" %s\n", "-V, --version"); 706 printf(" %s\n", "-V, --version");
721 printf (" %s\n", _("Print version information")); 707 printf(" %s\n", _("Print version information"));
722 printf (" %s\n", "-v, --variable=STRING"); 708 printf(" %s\n", "-v, --variable=STRING");
723 printf (" %s\n\n", _("Variable to check")); 709 printf(" %s\n\n", _("Variable to check"));
724 printf ("%s\n", _("Valid variables are:")); 710 printf("%s\n", _("Valid variables are:"));
725 printf (" %s", "CLIENTVERSION ="); 711 printf(" %s", "CLIENTVERSION =");
726 printf (" %s\n", _("Get the NSClient version")); 712 printf(" %s\n", _("Get the NSClient version"));
727 printf (" %s\n", _("If -l <version> is specified, will return warning if versions differ.")); 713 printf(" %s\n", _("If -l <version> is specified, will return warning if versions differ."));
728 printf (" %s\n", "CPULOAD ="); 714 printf(" %s\n", "CPULOAD =");
729 printf (" %s\n", _("Average CPU load on last x minutes.")); 715 printf(" %s\n", _("Average CPU load on last x minutes."));
730 printf (" %s\n", _("Request a -l parameter with the following syntax:")); 716 printf(" %s\n", _("Request a -l parameter with the following syntax:"));
731 printf (" %s\n", _("-l <minutes range>,<warning threshold>,<critical threshold>.")); 717 printf(" %s\n", _("-l <minutes range>,<warning threshold>,<critical threshold>."));
732 printf (" %s\n", _("<minute range> should be less than 24*60.")); 718 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.")); 719 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"); 720 printf(" %s\n", "ie: -l 60,90,95,120,90,95");
735 printf (" %s\n", "UPTIME ="); 721 printf(" %s\n", "UPTIME =");
736 printf (" %s\n", _("Get the uptime of the machine.")); 722 printf(" %s\n", _("Get the uptime of the machine."));
737 printf (" %s\n", _("-l <unit> ")); 723 printf(" %s\n", _("-l <unit> "));
738 printf (" %s\n", _("<unit> = seconds, minutes, hours, or days. (default: minutes)")); 724 printf(" %s\n", _("<unit> = seconds, minutes, hours, or days. (default: minutes)"));
739 printf (" %s\n", _("Thresholds will use the unit specified above.")); 725 printf(" %s\n", _("Thresholds will use the unit specified above."));
740 printf (" %s\n", "USEDDISKSPACE ="); 726 printf(" %s\n", "USEDDISKSPACE =");
741 printf (" %s\n", _("Size and percentage of disk use.")); 727 printf(" %s\n", _("Size and percentage of disk use."));
742 printf (" %s\n", _("Request a -l parameter containing the drive letter only.")); 728 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.")); 729 printf(" %s\n", _("Warning and critical thresholds can be specified with -w and -c."));
744 printf (" %s\n", "MEMUSE ="); 730 printf(" %s\n", "MEMUSE =");
745 printf (" %s\n", _("Memory use.")); 731 printf(" %s\n", _("Memory use."));
746 printf (" %s\n", _("Warning and critical thresholds can be specified with -w and -c.")); 732 printf(" %s\n", _("Warning and critical thresholds can be specified with -w and -c."));
747 printf (" %s\n", "SERVICESTATE ="); 733 printf(" %s\n", "SERVICESTATE =");
748 printf (" %s\n", _("Check the state of one or several services.")); 734 printf(" %s\n", _("Check the state of one or several services."));
749 printf (" %s\n", _("Request a -l parameters with the following syntax:")); 735 printf(" %s\n", _("Request a -l parameters with the following syntax:"));
750 printf (" %s\n", _("-l <service1>,<service2>,<service3>,...")); 736 printf(" %s\n", _("-l <service1>,<service2>,<service3>,..."));
751 printf (" %s\n", _("You can specify -d SHOWALL in case you want to see working services")); 737 printf(" %s\n", _("You can specify -d SHOWALL in case you want to see working services"));
752 printf (" %s\n", _("in the returned string.")); 738 printf(" %s\n", _("in the returned string."));
753 printf (" %s\n", "PROCSTATE ="); 739 printf(" %s\n", "PROCSTATE =");
754 printf (" %s\n", _("Check if one or several process are running.")); 740 printf(" %s\n", _("Check if one or several process are running."));
755 printf (" %s\n", _("Same syntax as SERVICESTATE.")); 741 printf(" %s\n", _("Same syntax as SERVICESTATE."));
756 printf (" %s\n", "COUNTER ="); 742 printf(" %s\n", "COUNTER =");
757 printf (" %s\n", _("Check any performance counter of Windows NT/2000.")); 743 printf(" %s\n", _("Check any performance counter of Windows NT/2000."));
758 printf (" %s\n", _("Request a -l parameters with the following syntax:")); 744 printf(" %s\n", _("Request a -l parameters with the following syntax:"));
759 printf (" %s\n", _("-l \"\\\\<performance object>\\\\counter\",\"<description>")); 745 printf(" %s\n", _("-l \"\\\\<performance object>\\\\counter\",\"<description>"));
760 printf (" %s\n", _("The <description> parameter is optional and is given to a printf ")); 746 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.")); 747 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.")); 748 printf(" %s\n", _("If <description> does not include \"%%\", it is used as a label."));
763 printf (" %s\n", _("Some examples:")); 749 printf(" %s\n", _("Some examples:"));
764 printf (" %s\n", "\"Paging file usage is %%.2f %%%%\""); 750 printf(" %s\n", "\"Paging file usage is %%.2f %%%%\"");
765 printf (" %s\n", "\"%%.f %%%% paging file used.\""); 751 printf(" %s\n", "\"%%.f %%%% paging file used.\"");
766 printf (" %s\n", "INSTANCES ="); 752 printf(" %s\n", "INSTANCES =");
767 printf (" %s\n", _("Check any performance counter object of Windows NT/2000.")); 753 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>")); 754 printf(" %s\n",
769 printf (" %s\n", _("<counter object> is a Windows Perfmon Counter object (eg. Process),")); 755 _("Syntax: check_nt -H <hostname> -p <port> -v INSTANCES -l <counter object>"));
770 printf (" %s\n", _("if it is two words, it should be enclosed in quotes")); 756 printf(" %s\n", _("<counter object> is a Windows Perfmon Counter object (eg. Process),"));
771 printf (" %s\n", _("The returned results will be a comma-separated list of instances on ")); 757 printf(" %s\n", _("if it is two words, it should be enclosed in quotes"));
772 printf (" %s\n", _(" the selected computer for that object.")); 758 printf(" %s\n", _("The returned results will be a comma-separated list of instances on "));
773 printf (" %s\n", _("The purpose of this is to be run from command line to determine what instances")); 759 printf(" %s\n", _(" the selected computer for that object."));
774 printf (" %s\n", _(" are available for monitoring without having to log onto the Windows server")); 760 printf(" %s\n",
775 printf (" %s\n", _(" to run Perfmon directly.")); 761 _("The purpose of this is to be run from command line to determine what instances"));
776 printf (" %s\n", _("It can also be used in scripts that automatically create the monitoring service")); 762 printf(" %s\n",
777 printf (" %s\n", _(" configuration files.")); 763 _(" are available for monitoring without having to log onto the Windows server"));
778 printf (" %s\n", _("Some examples:")); 764 printf(" %s\n", _(" to run Perfmon directly."));
779 printf (" %s\n\n", _("check_nt -H 192.168.1.1 -p 1248 -v INSTANCES -l Process")); 765 printf(" %s\n",
780 766 _("It can also be used in scripts that automatically create the monitoring service"));
781 printf ("%s\n", _("Notes:")); 767 printf(" %s\n", _(" configuration files."));
782 printf (" %s\n", _("- The NSClient service should be running on the server to get any information")); 768 printf(" %s\n", _("Some examples:"));
783 printf (" %s\n", "(http://nsclient.ready2run.nl)."); 769 printf(" %s\n\n", _("check_nt -H 192.168.1.1 -p 1248 -v INSTANCES -l Process"));
784 printf (" %s\n", _("- Critical thresholds should be lower than warning thresholds")); 770
785 printf (" %s\n", _("- Default port 1248 is sometimes in use by other services. The error")); 771 printf("%s\n", _("Notes:"));
786 printf (" %s\n", _("output when this happens contains \"Cannot map xxxxx to protocol number\".")); 772 printf(" %s\n",
787 printf (" %s\n", _("One fix for this is to change the port to something else on check_nt ")); 773 _("- The NSClient service should be running on the server to get any information"));
788 printf (" %s\n", _("and on the client service it\'s connecting to.")); 774 printf(" %s\n", "(http://nsclient.ready2run.nl).");
789 775 printf(" %s\n", _("- Critical thresholds should be lower than warning thresholds"));
790 printf (UT_SUPPORT); 776 printf(" %s\n", _("- Default port 1248 is sometimes in use by other services. The error"));
777 printf(" %s\n",
778 _("output when this happens contains \"Cannot map xxxxx to protocol number\"."));
779 printf(" %s\n", _("One fix for this is to change the port to something else on check_nt "));
780 printf(" %s\n", _("and on the client service it\'s connecting to."));
781
782 printf(UT_SUPPORT);
791} 783}
792 784
793 785void print_usage(void) {
794 786 printf("%s\n", _("Usage:"));
795void print_usage(void) 787 printf("%s -H host -v variable [-p port] [-w warning] [-c critical]\n", progname);
796{ 788 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} 789}
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..b22cc3c1 100644
--- a/plugins/check_ntp.c
+++ b/plugins/check_ntp.c
@@ -1,61 +1,61 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_ntp plugin 3 * Monitoring check_ntp 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 plugin 11 * This file contains the check_ntp plugin
12* 12 *
13* This plugin to check ntp servers independent of any commandline 13 * This plugin to check ntp servers independent of any commandline
14* programs or external libraries. 14 * programs or external libraries.
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_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"
38#include "netutils.h" 38#include "netutils.h"
39#include "utils.h" 39#include "utils.h"
40 40
41static char *server_address=NULL; 41static char *server_address = NULL;
42static int verbose=0; 42static int verbose = 0;
43static bool do_offset = false; 43static bool do_offset = false;
44static char *owarn="60"; 44static char *owarn = "60";
45static char *ocrit="120"; 45static char *ocrit = "120";
46static bool do_jitter = false; 46static 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. */
57#ifndef AVG_NUM 57#ifndef AVG_NUM
58#define AVG_NUM 4 58# define AVG_NUM 4
59#endif 59#endif
60 60
61/* max size of control message data */ 61/* max size of control message data */
@@ -63,17 +63,17 @@ void print_usage (void);
63 63
64/* this structure holds everything in an ntp request/response as per rfc1305 */ 64/* this structure holds everything in an ntp request/response as per rfc1305 */
65typedef struct { 65typedef struct {
66 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ 66 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
67 uint8_t stratum; /* clock stratum */ 67 uint8_t stratum; /* clock stratum */
68 int8_t poll; /* polling interval */ 68 int8_t poll; /* polling interval */
69 int8_t precision; /* precision of the local clock */ 69 int8_t precision; /* precision of the local clock */
70 int32_t rtdelay; /* total rt delay, as a fixed point num. see macros */ 70 int32_t rtdelay; /* total rt delay, as a fixed point num. see macros */
71 uint32_t rtdisp; /* like above, but for max err to primary src */ 71 uint32_t rtdisp; /* like above, but for max err to primary src */
72 uint32_t refid; /* ref clock identifier */ 72 uint32_t refid; /* ref clock identifier */
73 uint64_t refts; /* reference timestamp. local time local clock */ 73 uint64_t refts; /* reference timestamp. local time local clock */
74 uint64_t origts; /* time at which request departed client */ 74 uint64_t origts; /* time at which request departed client */
75 uint64_t rxts; /* time at which request arrived at server */ 75 uint64_t rxts; /* time at which request arrived at server */
76 uint64_t txts; /* time at which request departed server */ 76 uint64_t txts; /* time at which request departed server */
77} ntp_message; 77} ntp_message;
78 78
79/* this structure holds data about results from querying offset from a peer */ 79/* this structure holds data about results from querying offset from a peer */
@@ -84,20 +84,20 @@ typedef struct {
84 double rtdelay; /* converted from the ntp_message */ 84 double rtdelay; /* converted from the ntp_message */
85 double rtdisp; /* converted from the ntp_message */ 85 double rtdisp; /* converted from the ntp_message */
86 double offset[AVG_NUM]; /* offsets from each response */ 86 double offset[AVG_NUM]; /* offsets from each response */
87 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ 87 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
88} ntp_server_results; 88} ntp_server_results;
89 89
90/* this structure holds everything in an ntp control message as per rfc1305 */ 90/* this structure holds everything in an ntp control message as per rfc1305 */
91typedef struct { 91typedef struct {
92 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ 92 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
93 uint8_t op; /* R,E,M bits and Opcode */ 93 uint8_t op; /* R,E,M bits and Opcode */
94 uint16_t seq; /* Packet sequence */ 94 uint16_t seq; /* Packet sequence */
95 uint16_t status; /* Clock status */ 95 uint16_t status; /* Clock status */
96 uint16_t assoc; /* Association */ 96 uint16_t assoc; /* Association */
97 uint16_t offset; /* Similar to TCP sequence # */ 97 uint16_t offset; /* Similar to TCP sequence # */
98 uint16_t count; /* # bytes of data */ 98 uint16_t count; /* # bytes of data */
99 char data[MAX_CM_SIZE]; /* ASCII data of the request */ 99 char data[MAX_CM_SIZE]; /* ASCII data of the request */
100 /* NB: not necessarily NULL terminated! */ 100 /* NB: not necessarily NULL terminated! */
101} ntp_control_message; 101} ntp_control_message;
102 102
103/* this is an association/status-word pair found in control packet responses */ 103/* this is an association/status-word pair found in control packet responses */
@@ -108,38 +108,50 @@ typedef struct {
108 108
109/* bits 1,2 are the leap indicator */ 109/* bits 1,2 are the leap indicator */
110#define LI_MASK 0xc0 110#define LI_MASK 0xc0
111#define LI(x) ((x&LI_MASK)>>6) 111#define LI(x) ((x & LI_MASK) >> 6)
112#define LI_SET(x,y) do{ x |= ((y<<6)&LI_MASK); }while(0) 112#define LI_SET(x, y) \
113 do { \
114 x |= ((y << 6) & LI_MASK); \
115 } while (0)
113/* and these are the values of the leap indicator */ 116/* and these are the values of the leap indicator */
114#define LI_NOWARNING 0x00 117#define LI_NOWARNING 0x00
115#define LI_EXTRASEC 0x01 118#define LI_EXTRASEC 0x01
116#define LI_MISSINGSEC 0x02 119#define LI_MISSINGSEC 0x02
117#define LI_ALARM 0x03 120#define LI_ALARM 0x03
118/* bits 3,4,5 are the ntp version */ 121/* bits 3,4,5 are the ntp version */
119#define VN_MASK 0x38 122#define VN_MASK 0x38
120#define VN(x) ((x&VN_MASK)>>3) 123#define VN(x) ((x & VN_MASK) >> 3)
121#define VN_SET(x,y) do{ x |= ((y<<3)&VN_MASK); }while(0) 124#define VN_SET(x, y) \
125 do { \
126 x |= ((y << 3) & VN_MASK); \
127 } while (0)
122#define VN_RESERVED 0x02 128#define VN_RESERVED 0x02
123/* bits 6,7,8 are the ntp mode */ 129/* bits 6,7,8 are the ntp mode */
124#define MODE_MASK 0x07 130#define MODE_MASK 0x07
125#define MODE(x) (x&MODE_MASK) 131#define MODE(x) (x & MODE_MASK)
126#define MODE_SET(x,y) do{ x |= (y&MODE_MASK); }while(0) 132#define MODE_SET(x, y) \
133 do { \
134 x |= (y & MODE_MASK); \
135 } while (0)
127/* here are some values */ 136/* here are some values */
128#define MODE_CLIENT 0x03 137#define MODE_CLIENT 0x03
129#define MODE_CONTROLMSG 0x06 138#define MODE_CONTROLMSG 0x06
130/* In control message, bits 8-10 are R,E,M bits */ 139/* In control message, bits 8-10 are R,E,M bits */
131#define REM_MASK 0xe0 140#define REM_MASK 0xe0
132#define REM_RESP 0x80 141#define REM_RESP 0x80
133#define REM_ERROR 0x40 142#define REM_ERROR 0x40
134#define REM_MORE 0x20 143#define REM_MORE 0x20
135/* In control message, bits 11 - 15 are opcode */ 144/* In control message, bits 11 - 15 are opcode */
136#define OP_MASK 0x1f 145#define OP_MASK 0x1f
137#define OP_SET(x,y) do{ x |= (y&OP_MASK); }while(0) 146#define OP_SET(x, y) \
147 do { \
148 x |= (y & OP_MASK); \
149 } while (0)
138#define OP_READSTAT 0x01 150#define OP_READSTAT 0x01
139#define OP_READVAR 0x02 151#define OP_READVAR 0x02
140/* In peer status bytes, bits 6,7,8 determine clock selection status */ 152/* In peer status bytes, bits 6,7,8 determine clock selection status */
141#define PEER_SEL(x) ((ntohs(x)>>8)&0x07) 153#define PEER_SEL(x) ((ntohs(x) >> 8) & 0x07)
142#define PEER_INCLUDED 0x04 154#define PEER_INCLUDED 0x04
143#define PEER_SYNCSOURCE 0x06 155#define PEER_SYNCSOURCE 0x06
144 156
145/** 157/**
@@ -153,82 +165,92 @@ typedef struct {
153 165
154/* macros to access the left/right 16 bits of a 32-bit ntp "fixed point" 166/* macros to access the left/right 16 bits of a 32-bit ntp "fixed point"
155 number. note that these can be used as lvalues too */ 167 number. note that these can be used as lvalues too */
156#define L16(x) (((uint16_t*)&x)[0]) 168#define L16(x) (((uint16_t *)&x)[0])
157#define R16(x) (((uint16_t*)&x)[1]) 169#define R16(x) (((uint16_t *)&x)[1])
158/* macros to access the left/right 32 bits of a 64-bit ntp "fixed point" 170/* macros to access the left/right 32 bits of a 64-bit ntp "fixed point"
159 number. these too can be used as lvalues */ 171 number. these too can be used as lvalues */
160#define L32(x) (((uint32_t*)&x)[0]) 172#define L32(x) (((uint32_t *)&x)[0])
161#define R32(x) (((uint32_t*)&x)[1]) 173#define R32(x) (((uint32_t *)&x)[1])
162 174
163/* ntp wants seconds since 1/1/00, epoch is 1/1/70. this is the difference */ 175/* ntp wants seconds since 1/1/00, epoch is 1/1/70. this is the difference */
164#define EPOCHDIFF 0x83aa7e80UL 176#define EPOCHDIFF 0x83aa7e80UL
165 177
166/* extract a 32-bit ntp fixed point number into a double */ 178/* extract a 32-bit ntp fixed point number into a double */
167#define NTP32asDOUBLE(x) (ntohs(L16(x)) + (double)ntohs(R16(x))/65536.0) 179#define NTP32asDOUBLE(x) (ntohs(L16(x)) + (double)ntohs(R16(x)) / 65536.0)
168 180
169/* likewise for a 64-bit ntp fp number */ 181/* likewise for a 64-bit ntp fp number */
170#define NTP64asDOUBLE(n) (double)(((uint64_t)n)?\ 182#define NTP64asDOUBLE(n) \
171 (ntohl(L32(n))-EPOCHDIFF) + \ 183 (double)(((uint64_t)n) ? (ntohl(L32(n)) - EPOCHDIFF) + \
172 (.00000001*(0.5+(double)(ntohl(R32(n))/42.94967296))):\ 184 (.00000001 * (0.5 + (double)(ntohl(R32(n)) / 42.94967296))) \
173 0) 185 : 0)
174 186
175/* convert a struct timeval to a double */ 187/* convert a struct timeval to a double */
176#define TVasDOUBLE(x) (double)(x.tv_sec+(0.000001*x.tv_usec)) 188#define TVasDOUBLE(x) (double)(x.tv_sec + (0.000001 * x.tv_usec))
177 189
178/* convert an ntp 64-bit fp number to a struct timeval */ 190/* convert an ntp 64-bit fp number to a struct timeval */
179#define NTP64toTV(n,t) \ 191#define NTP64toTV(n, t) \
180 do{ if(!n) t.tv_sec = t.tv_usec = 0; \ 192 do { \
181 else { \ 193 if (!n) \
182 t.tv_sec=ntohl(L32(n))-EPOCHDIFF; \ 194 t.tv_sec = t.tv_usec = 0; \
183 t.tv_usec=(int)(0.5+(double)(ntohl(R32(n))/4294.967296)); \ 195 else { \
184 } \ 196 t.tv_sec = ntohl(L32(n)) - EPOCHDIFF; \
185 }while(0) 197 t.tv_usec = (int)(0.5 + (double)(ntohl(R32(n)) / 4294.967296)); \
198 } \
199 } while (0)
186 200
187/* convert a struct timeval to an ntp 64-bit fp number */ 201/* convert a struct timeval to an ntp 64-bit fp number */
188#define TVtoNTP64(t,n) \ 202#define TVtoNTP64(t, n) \
189 do{ if(!t.tv_usec && !t.tv_sec) n=0x0UL; \ 203 do { \
190 else { \ 204 if (!t.tv_usec && !t.tv_sec) \
191 L32(n)=htonl(t.tv_sec + EPOCHDIFF); \ 205 n = 0x0UL; \
192 R32(n)=htonl((uint64_t)((4294.967296*t.tv_usec)+.5)); \ 206 else { \
193 } \ 207 L32(n) = htonl(t.tv_sec + EPOCHDIFF); \
194 } while(0) 208 R32(n) = htonl((uint64_t)((4294.967296 * t.tv_usec) + .5)); \
209 } \
210 } while (0)
195 211
196/* NTP control message header is 12 bytes, plus any data in the data 212/* NTP control message header is 12 bytes, plus any data in the data
197 * field, plus null padding to the nearest 32-bit boundary per rfc. 213 * field, plus null padding to the nearest 32-bit boundary per rfc.
198 */ 214 */
199#define SIZEOF_NTPCM(m) (12+ntohs(m.count)+((ntohs(m.count)%4)?4-(ntohs(m.count)%4):0)) 215#define SIZEOF_NTPCM(m) \
216 (12 + ntohs(m.count) + ((ntohs(m.count) % 4) ? 4 - (ntohs(m.count) % 4) : 0))
200 217
201/* finally, a little helper or two for debugging: */ 218/* finally, a little helper or two for debugging: */
202#define DBG(x) do{if(verbose>1){ x; }}while(0); 219#define DBG(x) \
203#define PRINTSOCKADDR(x) \ 220 do { \
204 do{ \ 221 if (verbose > 1) { \
205 printf("%u.%u.%u.%u", (x>>24)&0xff, (x>>16)&0xff, (x>>8)&0xff, x&0xff);\ 222 x; \
206 }while(0); 223 } \
224 } while (0);
225#define PRINTSOCKADDR(x) \
226 do { \
227 printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \
228 } while (0);
207 229
208/* calculate the offset of the local clock */ 230/* calculate the offset of the local clock */
209static inline double calc_offset(const ntp_message *m, const struct timeval *t){ 231static inline double calc_offset(const ntp_message *m, const struct timeval *t) {
210 double client_tx, peer_rx, peer_tx, client_rx; 232 double client_tx, peer_rx, peer_tx, client_rx;
211 client_tx = NTP64asDOUBLE(m->origts); 233 client_tx = NTP64asDOUBLE(m->origts);
212 peer_rx = NTP64asDOUBLE(m->rxts); 234 peer_rx = NTP64asDOUBLE(m->rxts);
213 peer_tx = NTP64asDOUBLE(m->txts); 235 peer_tx = NTP64asDOUBLE(m->txts);
214 client_rx=TVasDOUBLE((*t)); 236 client_rx = TVasDOUBLE((*t));
215 return (.5*((peer_tx-client_rx)+(peer_rx-client_tx))); 237 return (.5 * ((peer_tx - client_rx) + (peer_rx - client_tx)));
216} 238}
217 239
218/* print out a ntp packet in human readable/debuggable format */ 240/* print out a ntp packet in human readable/debuggable format */
219void print_ntp_message(const ntp_message *p){ 241void print_ntp_message(const ntp_message *p) {
220 struct timeval ref, orig, rx, tx; 242 struct timeval ref, orig, rx, tx;
221 243
222 NTP64toTV(p->refts,ref); 244 NTP64toTV(p->refts, ref);
223 NTP64toTV(p->origts,orig); 245 NTP64toTV(p->origts, orig);
224 NTP64toTV(p->rxts,rx); 246 NTP64toTV(p->rxts, rx);
225 NTP64toTV(p->txts,tx); 247 NTP64toTV(p->txts, tx);
226 248
227 printf("packet contents:\n"); 249 printf("packet contents:\n");
228 printf("\tflags: 0x%.2x\n", p->flags); 250 printf("\tflags: 0x%.2x\n", p->flags);
229 printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags&LI_MASK); 251 printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags & LI_MASK);
230 printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags&VN_MASK); 252 printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags & VN_MASK);
231 printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags&MODE_MASK); 253 printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags & MODE_MASK);
232 printf("\tstratum = %d\n", p->stratum); 254 printf("\tstratum = %d\n", p->stratum);
233 printf("\tpoll = %g\n", pow(2, p->poll)); 255 printf("\tpoll = %g\n", pow(2, p->poll));
234 printf("\tprecision = %g\n", pow(2, p->precision)); 256 printf("\tprecision = %g\n", pow(2, p->precision));
@@ -241,32 +263,31 @@ void print_ntp_message(const ntp_message *p){
241 printf("\ttxts = %-.16g\n", NTP64asDOUBLE(p->txts)); 263 printf("\ttxts = %-.16g\n", NTP64asDOUBLE(p->txts));
242} 264}
243 265
244void print_ntp_control_message(const ntp_control_message *p){ 266void print_ntp_control_message(const ntp_control_message *p) {
245 int i=0, numpeers=0; 267 int i = 0, numpeers = 0;
246 const ntp_assoc_status_pair *peer=NULL; 268 const ntp_assoc_status_pair *peer = NULL;
247 269
248 printf("control packet contents:\n"); 270 printf("control packet contents:\n");
249 printf("\tflags: 0x%.2x , 0x%.2x\n", p->flags, p->op); 271 printf("\tflags: 0x%.2x , 0x%.2x\n", p->flags, p->op);
250 printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags&LI_MASK); 272 printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags & LI_MASK);
251 printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags&VN_MASK); 273 printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags & VN_MASK);
252 printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags&MODE_MASK); 274 printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags & MODE_MASK);
253 printf("\t response=%d (0x%.2x)\n", (p->op&REM_RESP)>0, p->op&REM_RESP); 275 printf("\t response=%d (0x%.2x)\n", (p->op & REM_RESP) > 0, p->op & REM_RESP);
254 printf("\t more=%d (0x%.2x)\n", (p->op&REM_MORE)>0, p->op&REM_MORE); 276 printf("\t more=%d (0x%.2x)\n", (p->op & REM_MORE) > 0, p->op & REM_MORE);
255 printf("\t error=%d (0x%.2x)\n", (p->op&REM_ERROR)>0, p->op&REM_ERROR); 277 printf("\t error=%d (0x%.2x)\n", (p->op & REM_ERROR) > 0, p->op & REM_ERROR);
256 printf("\t op=%d (0x%.2x)\n", p->op&OP_MASK, p->op&OP_MASK); 278 printf("\t op=%d (0x%.2x)\n", p->op & OP_MASK, p->op & OP_MASK);
257 printf("\tsequence: %d (0x%.2x)\n", ntohs(p->seq), ntohs(p->seq)); 279 printf("\tsequence: %d (0x%.2x)\n", ntohs(p->seq), ntohs(p->seq));
258 printf("\tstatus: %d (0x%.2x)\n", ntohs(p->status), ntohs(p->status)); 280 printf("\tstatus: %d (0x%.2x)\n", ntohs(p->status), ntohs(p->status));
259 printf("\tassoc: %d (0x%.2x)\n", ntohs(p->assoc), ntohs(p->assoc)); 281 printf("\tassoc: %d (0x%.2x)\n", ntohs(p->assoc), ntohs(p->assoc));
260 printf("\toffset: %d (0x%.2x)\n", ntohs(p->offset), ntohs(p->offset)); 282 printf("\toffset: %d (0x%.2x)\n", ntohs(p->offset), ntohs(p->offset));
261 printf("\tcount: %d (0x%.2x)\n", ntohs(p->count), ntohs(p->count)); 283 printf("\tcount: %d (0x%.2x)\n", ntohs(p->count), ntohs(p->count));
262 numpeers=ntohs(p->count)/(sizeof(ntp_assoc_status_pair)); 284 numpeers = ntohs(p->count) / (sizeof(ntp_assoc_status_pair));
263 if(p->op&REM_RESP && p->op&OP_READSTAT){ 285 if (p->op & REM_RESP && p->op & OP_READSTAT) {
264 peer=(ntp_assoc_status_pair*)p->data; 286 peer = (ntp_assoc_status_pair *)p->data;
265 for(i=0;i<numpeers;i++){ 287 for (i = 0; i < numpeers; i++) {
266 printf("\tpeer id %.2x status %.2x", 288 printf("\tpeer id %.2x status %.2x", ntohs(peer[i].assoc), ntohs(peer[i].status));
267 ntohs(peer[i].assoc), ntohs(peer[i].status)); 289 if (PEER_SEL(peer[i].status) >= PEER_INCLUDED) {
268 if (PEER_SEL(peer[i].status) >= PEER_INCLUDED){ 290 if (PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE) {
269 if(PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE){
270 printf(" <-- current sync source"); 291 printf(" <-- current sync source");
271 } else { 292 } else {
272 printf(" <-- current sync candidate"); 293 printf(" <-- current sync candidate");
@@ -277,41 +298,45 @@ void print_ntp_control_message(const ntp_control_message *p){
277 } 298 }
278} 299}
279 300
280void setup_request(ntp_message *p){ 301void setup_request(ntp_message *p) {
281 struct timeval t; 302 struct timeval t;
282 303
283 memset(p, 0, sizeof(ntp_message)); 304 memset(p, 0, sizeof(ntp_message));
284 LI_SET(p->flags, LI_ALARM); 305 LI_SET(p->flags, LI_ALARM);
285 VN_SET(p->flags, 4); 306 VN_SET(p->flags, 4);
286 MODE_SET(p->flags, MODE_CLIENT); 307 MODE_SET(p->flags, MODE_CLIENT);
287 p->poll=4; 308 p->poll = 4;
288 p->precision=(int8_t)0xfa; 309 p->precision = (int8_t)0xfa;
289 L16(p->rtdelay)=htons(1); 310 L16(p->rtdelay) = htons(1);
290 L16(p->rtdisp)=htons(1); 311 L16(p->rtdisp) = htons(1);
291 312
292 gettimeofday(&t, NULL); 313 gettimeofday(&t, NULL);
293 TVtoNTP64(t,p->txts); 314 TVtoNTP64(t, p->txts);
294} 315}
295 316
296/* select the "best" server from a list of servers, and return its index. 317/* select the "best" server from a list of servers, and return its index.
297 * this is done by filtering servers based on stratum, dispersion, and 318 * this is done by filtering servers based on stratum, dispersion, and
298 * finally round-trip delay. */ 319 * finally round-trip delay. */
299int best_offset_server(const ntp_server_results *slist, int nservers){ 320int best_offset_server(const ntp_server_results *slist, int nservers) {
300 int cserver=0, best_server=-1; 321 int cserver = 0, best_server = -1;
301 322
302 /* for each server */ 323 /* for each server */
303 for(cserver=0; cserver<nservers; cserver++){ 324 for (cserver = 0; cserver < nservers; cserver++) {
304 /* We don't want any servers that fails these tests */ 325 /* We don't want any servers that fails these tests */
305 /* Sort out servers that didn't respond or responede with a 0 stratum; 326 /* Sort out servers that didn't respond or responede with a 0 stratum;
306 * stratum 0 is for reference clocks so no NTP server should ever report 327 * stratum 0 is for reference clocks so no NTP server should ever report
307 * a stratum 0 */ 328 * a stratum 0 */
308 if ( slist[cserver].stratum == 0){ 329 if (slist[cserver].stratum == 0) {
309 if (verbose) printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum); 330 if (verbose) {
331 printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum);
332 }
310 continue; 333 continue;
311 } 334 }
312 /* Sort out servers with error flags */ 335 /* Sort out servers with error flags */
313 if ( LI(slist[cserver].flags) == LI_ALARM ){ 336 if (LI(slist[cserver].flags) == LI_ALARM) {
314 if (verbose) printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags)); 337 if (verbose) {
338 printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags));
339 }
315 continue; 340 continue;
316 } 341 }
317 342
@@ -325,13 +350,13 @@ int best_offset_server(const ntp_server_results *slist, int nservers){
325 /* compare the server to the best one we've seen so far */ 350 /* compare the server to the best one we've seen so far */
326 /* does it have an equal or better stratum? */ 351 /* does it have an equal or better stratum? */
327 DBG(printf("comparing peer %d with peer %d\n", cserver, best_server)); 352 DBG(printf("comparing peer %d with peer %d\n", cserver, best_server));
328 if(slist[cserver].stratum <= slist[best_server].stratum){ 353 if (slist[cserver].stratum <= slist[best_server].stratum) {
329 DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server)); 354 DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server));
330 /* does it have an equal or better dispersion? */ 355 /* does it have an equal or better dispersion? */
331 if(slist[cserver].rtdisp <= slist[best_server].rtdisp){ 356 if (slist[cserver].rtdisp <= slist[best_server].rtdisp) {
332 DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server)); 357 DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server));
333 /* does it have a better rtdelay? */ 358 /* does it have a better rtdelay? */
334 if(slist[cserver].rtdelay < slist[best_server].rtdelay){ 359 if (slist[cserver].rtdelay < slist[best_server].rtdelay) {
335 DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server)); 360 DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server));
336 best_server = cserver; 361 best_server = cserver;
337 DBG(printf("peer %d is now our best candidate\n", best_server)); 362 DBG(printf("peer %d is now our best candidate\n", best_server));
@@ -340,7 +365,7 @@ int best_offset_server(const ntp_server_results *slist, int nservers){
340 } 365 }
341 } 366 }
342 367
343 if(best_server >= 0) { 368 if (best_server >= 0) {
344 DBG(printf("best server selected: peer %d\n", best_server)); 369 DBG(printf("best server selected: peer %d\n", best_server));
345 return best_server; 370 return best_server;
346 } else { 371 } else {
@@ -354,16 +379,16 @@ int best_offset_server(const ntp_server_results *slist, int nservers){
354 * we don't waste time sitting around waiting for single packets. 379 * we don't waste time sitting around waiting for single packets.
355 * - we also "manually" handle resolving host names and connecting, because 380 * - we also "manually" handle resolving host names and connecting, because
356 * we have to do it in a way that our lazy macros don't handle currently :( */ 381 * we have to do it in a way that our lazy macros don't handle currently :( */
357double offset_request(const char *host, int *status){ 382double offset_request(const char *host, int *status) {
358 int i=0, ga_result=0, num_hosts=0, *socklist=NULL, respnum=0; 383 int i = 0, ga_result = 0, num_hosts = 0, *socklist = NULL, respnum = 0;
359 int servers_completed=0, one_read=0, servers_readable=0, best_index=-1; 384 int servers_completed = 0, one_read = 0, servers_readable = 0, best_index = -1;
360 time_t now_time=0, start_ts=0; 385 time_t now_time = 0, start_ts = 0;
361 ntp_message *req=NULL; 386 ntp_message *req = NULL;
362 double avg_offset=0.; 387 double avg_offset = 0.;
363 struct timeval recv_time; 388 struct timeval recv_time;
364 struct addrinfo *ai=NULL, *ai_tmp=NULL, hints; 389 struct addrinfo *ai = NULL, *ai_tmp = NULL, hints;
365 struct pollfd *ufds=NULL; 390 struct pollfd *ufds = NULL;
366 ntp_server_results *servers=NULL; 391 ntp_server_results *servers = NULL;
367 392
368 /* setup hints to only return results from getaddrinfo that we'd like */ 393 /* setup hints to only return results from getaddrinfo that we'd like */
369 memset(&hints, 0, sizeof(struct addrinfo)); 394 memset(&hints, 0, sizeof(struct addrinfo));
@@ -373,97 +398,112 @@ double offset_request(const char *host, int *status){
373 398
374 /* fill in ai with the list of hosts resolved by the host name */ 399 /* fill in ai with the list of hosts resolved by the host name */
375 ga_result = getaddrinfo(host, "123", &hints, &ai); 400 ga_result = getaddrinfo(host, "123", &hints, &ai);
376 if(ga_result!=0){ 401 if (ga_result != 0) {
377 die(STATE_UNKNOWN, "error getting address for %s: %s\n", 402 die(STATE_UNKNOWN, "error getting address for %s: %s\n", host, gai_strerror(ga_result));
378 host, gai_strerror(ga_result));
379 } 403 }
380 404
381 /* count the number of returned hosts, and allocate stuff accordingly */ 405 /* count the number of returned hosts, and allocate stuff accordingly */
382 for(ai_tmp=ai; ai_tmp!=NULL; ai_tmp=ai_tmp->ai_next){ num_hosts++; } 406 for (ai_tmp = ai; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) {
383 req=(ntp_message*)malloc(sizeof(ntp_message)*num_hosts); 407 num_hosts++;
384 if(req==NULL) die(STATE_UNKNOWN, "can not allocate ntp message array"); 408 }
385 socklist=(int*)malloc(sizeof(int)*num_hosts); 409 req = (ntp_message *)malloc(sizeof(ntp_message) * num_hosts);
386 if(socklist==NULL) die(STATE_UNKNOWN, "can not allocate socket array"); 410 if (req == NULL) {
387 ufds=(struct pollfd*)malloc(sizeof(struct pollfd)*num_hosts); 411 die(STATE_UNKNOWN, "can not allocate ntp message array");
388 if(ufds==NULL) die(STATE_UNKNOWN, "can not allocate socket array"); 412 }
389 servers=(ntp_server_results*)malloc(sizeof(ntp_server_results)*num_hosts); 413 socklist = (int *)malloc(sizeof(int) * num_hosts);
390 if(servers==NULL) die(STATE_UNKNOWN, "can not allocate server array"); 414 if (socklist == NULL) {
391 memset(servers, 0, sizeof(ntp_server_results)*num_hosts); 415 die(STATE_UNKNOWN, "can not allocate socket array");
416 }
417 ufds = (struct pollfd *)malloc(sizeof(struct pollfd) * num_hosts);
418 if (ufds == NULL) {
419 die(STATE_UNKNOWN, "can not allocate socket array");
420 }
421 servers = (ntp_server_results *)malloc(sizeof(ntp_server_results) * num_hosts);
422 if (servers == NULL) {
423 die(STATE_UNKNOWN, "can not allocate server array");
424 }
425 memset(servers, 0, sizeof(ntp_server_results) * num_hosts);
392 DBG(printf("Found %d peers to check\n", num_hosts)); 426 DBG(printf("Found %d peers to check\n", num_hosts));
393 427
394 /* setup each socket for writing, and the corresponding struct pollfd */ 428 /* setup each socket for writing, and the corresponding struct pollfd */
395 ai_tmp=ai; 429 ai_tmp = ai;
396 for(i=0;ai_tmp;i++){ 430 for (i = 0; ai_tmp; i++) {
397 socklist[i]=socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP); 431 socklist[i] = socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP);
398 if(socklist[i] == -1) { 432 if (socklist[i] == -1) {
399 perror(NULL); 433 perror(NULL);
400 die(STATE_UNKNOWN, "can not create new socket"); 434 die(STATE_UNKNOWN, "can not create new socket");
401 } 435 }
402 if(connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)){ 436 if (connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)) {
403 /* don't die here, because it is enough if there is one server 437 /* don't die here, because it is enough if there is one server
404 answering in time. This also would break for dual ipv4/6 stacked 438 answering in time. This also would break for dual ipv4/6 stacked
405 ntp servers when the client only supports on of them. 439 ntp servers when the client only supports on of them.
406 */ 440 */
407 DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno))); 441 DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno)));
408 } else { 442 } else {
409 ufds[i].fd=socklist[i]; 443 ufds[i].fd = socklist[i];
410 ufds[i].events=POLLIN; 444 ufds[i].events = POLLIN;
411 ufds[i].revents=0; 445 ufds[i].revents = 0;
412 } 446 }
413 ai_tmp = ai_tmp->ai_next; 447 ai_tmp = ai_tmp->ai_next;
414 } 448 }
415 449
416 /* now do AVG_NUM checks to each host. we stop before timeout/2 seconds 450 /* now do AVG_NUM checks to each host. we stop before timeout/2 seconds
417 * have passed in order to ensure post-processing and jitter time. */ 451 * have passed in order to ensure post-processing and jitter time. */
418 now_time=start_ts=time(NULL); 452 now_time = start_ts = time(NULL);
419 while(servers_completed<num_hosts && now_time-start_ts <= socket_timeout/2){ 453 while (servers_completed < num_hosts && now_time - start_ts <= socket_timeout / 2) {
420 /* loop through each server and find each one which hasn't 454 /* loop through each server and find each one which hasn't
421 * been touched in the past second or so and is still lacking 455 * been touched in the past second or so and is still lacking
422 * some responses. for each of these servers, send a new request, 456 * some responses. for each of these servers, send a new request,
423 * and update the "waiting" timestamp with the current time. */ 457 * and update the "waiting" timestamp with the current time. */
424 now_time=time(NULL); 458 now_time = time(NULL);
425 459
426 for(i=0; i<num_hosts; i++){ 460 for (i = 0; i < num_hosts; i++) {
427 if(servers[i].waiting<now_time && servers[i].num_responses<AVG_NUM){ 461 if (servers[i].waiting < now_time && servers[i].num_responses < AVG_NUM) {
428 if(verbose && servers[i].waiting != 0) printf("re-"); 462 if (verbose && servers[i].waiting != 0) {
429 if(verbose) printf("sending request to peer %d\n", i); 463 printf("re-");
464 }
465 if (verbose) {
466 printf("sending request to peer %d\n", i);
467 }
430 setup_request(&req[i]); 468 setup_request(&req[i]);
431 write(socklist[i], &req[i], sizeof(ntp_message)); 469 write(socklist[i], &req[i], sizeof(ntp_message));
432 servers[i].waiting=now_time; 470 servers[i].waiting = now_time;
433 break; 471 break;
434 } 472 }
435 } 473 }
436 474
437 /* quickly poll for any sockets with pending data */ 475 /* quickly poll for any sockets with pending data */
438 servers_readable=poll(ufds, num_hosts, 100); 476 servers_readable = poll(ufds, num_hosts, 100);
439 if(servers_readable==-1){ 477 if (servers_readable == -1) {
440 perror("polling ntp sockets"); 478 perror("polling ntp sockets");
441 die(STATE_UNKNOWN, "communication errors"); 479 die(STATE_UNKNOWN, "communication errors");
442 } 480 }
443 481
444 /* read from any sockets with pending data */ 482 /* read from any sockets with pending data */
445 for(i=0; servers_readable && i<num_hosts; i++){ 483 for (i = 0; servers_readable && i < num_hosts; i++) {
446 if(ufds[i].revents&POLLIN && servers[i].num_responses < AVG_NUM){ 484 if (ufds[i].revents & POLLIN && servers[i].num_responses < AVG_NUM) {
447 if(verbose) { 485 if (verbose) {
448 printf("response from peer %d: ", i); 486 printf("response from peer %d: ", i);
449 } 487 }
450 488
451 read(ufds[i].fd, &req[i], sizeof(ntp_message)); 489 read(ufds[i].fd, &req[i], sizeof(ntp_message));
452 gettimeofday(&recv_time, NULL); 490 gettimeofday(&recv_time, NULL);
453 DBG(print_ntp_message(&req[i])); 491 DBG(print_ntp_message(&req[i]));
454 respnum=servers[i].num_responses++; 492 respnum = servers[i].num_responses++;
455 servers[i].offset[respnum]=calc_offset(&req[i], &recv_time); 493 servers[i].offset[respnum] = calc_offset(&req[i], &recv_time);
456 if(verbose) { 494 if (verbose) {
457 printf("offset %.10g\n", servers[i].offset[respnum]); 495 printf("offset %.10g\n", servers[i].offset[respnum]);
458 } 496 }
459 servers[i].stratum=req[i].stratum; 497 servers[i].stratum = req[i].stratum;
460 servers[i].rtdisp=NTP32asDOUBLE(req[i].rtdisp); 498 servers[i].rtdisp = NTP32asDOUBLE(req[i].rtdisp);
461 servers[i].rtdelay=NTP32asDOUBLE(req[i].rtdelay); 499 servers[i].rtdelay = NTP32asDOUBLE(req[i].rtdelay);
462 servers[i].waiting=0; 500 servers[i].waiting = 0;
463 servers[i].flags=req[i].flags; 501 servers[i].flags = req[i].flags;
464 servers_readable--; 502 servers_readable--;
465 one_read = 1; 503 one_read = 1;
466 if(servers[i].num_responses==AVG_NUM) servers_completed++; 504 if (servers[i].num_responses == AVG_NUM) {
505 servers_completed++;
506 }
467 } 507 }
468 } 508 }
469 /* lather, rinse, repeat. */ 509 /* lather, rinse, repeat. */
@@ -474,15 +514,15 @@ double offset_request(const char *host, int *status){
474 } 514 }
475 515
476 /* now, pick the best server from the list */ 516 /* now, pick the best server from the list */
477 best_index=best_offset_server(servers, num_hosts); 517 best_index = best_offset_server(servers, num_hosts);
478 if(best_index < 0){ 518 if (best_index < 0) {
479 *status=STATE_UNKNOWN; 519 *status = STATE_UNKNOWN;
480 } else { 520 } else {
481 /* finally, calculate the average offset */ 521 /* finally, calculate the average offset */
482 for(i=0; i<servers[best_index].num_responses;i++){ 522 for (i = 0; i < servers[best_index].num_responses; i++) {
483 avg_offset+=servers[best_index].offset[i]; 523 avg_offset += servers[best_index].offset[i];
484 } 524 }
485 avg_offset/=servers[best_index].num_responses; 525 avg_offset /= servers[best_index].num_responses;
486 } 526 }
487 527
488 /* cleanup */ 528 /* cleanup */
@@ -496,12 +536,13 @@ double offset_request(const char *host, int *status){
496 free(req); 536 free(req);
497 freeaddrinfo(ai); 537 freeaddrinfo(ai);
498 538
499 if(verbose) printf("overall average offset: %.10g\n", avg_offset); 539 if (verbose) {
540 printf("overall average offset: %.10g\n", avg_offset);
541 }
500 return avg_offset; 542 return avg_offset;
501} 543}
502 544
503void 545void setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq) {
504setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq){
505 memset(p, 0, sizeof(ntp_control_message)); 546 memset(p, 0, sizeof(ntp_control_message));
506 LI_SET(p->flags, LI_NOWARNING); 547 LI_SET(p->flags, LI_NOWARNING);
507 VN_SET(p->flags, VN_RESERVED); 548 VN_SET(p->flags, VN_RESERVED);
@@ -512,16 +553,16 @@ setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq){
512} 553}
513 554
514/* XXX handle responses with the error bit set */ 555/* XXX handle responses with the error bit set */
515double jitter_request(int *status){ 556double jitter_request(int *status) {
516 int conn=-1, i, npeers=0, num_candidates=0; 557 int conn = -1, i, npeers = 0, num_candidates = 0;
517 bool syncsource_found = false; 558 bool syncsource_found = false;
518 int run=0, min_peer_sel=PEER_INCLUDED, num_selected=0, num_valid=0; 559 int run = 0, min_peer_sel = PEER_INCLUDED, num_selected = 0, num_valid = 0;
519 int peers_size=0, peer_offset=0; 560 int peers_size = 0, peer_offset = 0;
520 ntp_assoc_status_pair *peers=NULL; 561 ntp_assoc_status_pair *peers = NULL;
521 ntp_control_message req; 562 ntp_control_message req;
522 const char *getvar = "jitter"; 563 const char *getvar = "jitter";
523 double rval = 0.0, jitter = -1.0; 564 double rval = 0.0, jitter = -1.0;
524 char *startofvalue=NULL, *nptr=NULL; 565 char *startofvalue = NULL, *nptr = NULL;
525 void *tmp; 566 void *tmp;
526 567
527 /* Long-winded explanation: 568 /* Long-winded explanation:
@@ -542,54 +583,62 @@ double jitter_request(int *status){
542 583
543 /* keep sending requests until the server stops setting the 584 /* keep sending requests until the server stops setting the
544 * REM_MORE bit, though usually this is only 1 packet. */ 585 * REM_MORE bit, though usually this is only 1 packet. */
545 do{ 586 do {
546 setup_control_request(&req, OP_READSTAT, 1); 587 setup_control_request(&req, OP_READSTAT, 1);
547 DBG(printf("sending READSTAT request")); 588 DBG(printf("sending READSTAT request"));
548 write(conn, &req, SIZEOF_NTPCM(req)); 589 write(conn, &req, SIZEOF_NTPCM(req));
549 DBG(print_ntp_control_message(&req)); 590 DBG(print_ntp_control_message(&req));
550 /* Attempt to read the largest size packet possible */ 591 /* Attempt to read the largest size packet possible */
551 req.count=htons(MAX_CM_SIZE); 592 req.count = htons(MAX_CM_SIZE);
552 DBG(printf("receiving READSTAT response")) 593 DBG(printf("receiving READSTAT response"))
553 read(conn, &req, SIZEOF_NTPCM(req)); 594 read(conn, &req, SIZEOF_NTPCM(req));
554 DBG(print_ntp_control_message(&req)); 595 DBG(print_ntp_control_message(&req));
555 /* Each peer identifier is 4 bytes in the data section, which 596 /* Each peer identifier is 4 bytes in the data section, which
556 * we represent as a ntp_assoc_status_pair datatype. 597 * we represent as a ntp_assoc_status_pair datatype.
557 */ 598 */
558 peers_size+=ntohs(req.count); 599 peers_size += ntohs(req.count);
559 if((tmp=realloc(peers, peers_size)) == NULL) 600 if ((tmp = realloc(peers, peers_size)) == NULL) {
560 free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n"); 601 free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n");
561 peers=tmp; 602 }
562 memcpy((void*)((ptrdiff_t)peers+peer_offset), (void*)req.data, ntohs(req.count)); 603 peers = tmp;
563 npeers=peers_size/sizeof(ntp_assoc_status_pair); 604 memcpy((void *)((ptrdiff_t)peers + peer_offset), (void *)req.data, ntohs(req.count));
564 peer_offset+=ntohs(req.count); 605 npeers = peers_size / sizeof(ntp_assoc_status_pair);
565 } while(req.op&REM_MORE); 606 peer_offset += ntohs(req.count);
607 } while (req.op & REM_MORE);
566 608
567 /* first, let's find out if we have a sync source, or if there are 609 /* first, let's find out if we have a sync source, or if there are
568 * at least some candidates. in the case of the latter we'll issue 610 * at least some candidates. in the case of the latter we'll issue
569 * a warning but go ahead with the check on them. */ 611 * a warning but go ahead with the check on them. */
570 for (i = 0; i < npeers; i++){ 612 for (i = 0; i < npeers; i++) {
571 if (PEER_SEL(peers[i].status) >= PEER_INCLUDED){ 613 if (PEER_SEL(peers[i].status) >= PEER_INCLUDED) {
572 num_candidates++; 614 num_candidates++;
573 if(PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE){ 615 if (PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE) {
574 syncsource_found = true; 616 syncsource_found = true;
575 min_peer_sel=PEER_SYNCSOURCE; 617 min_peer_sel = PEER_SYNCSOURCE;
576 } 618 }
577 } 619 }
578 } 620 }
579 if(verbose) printf("%d candidate peers available\n", num_candidates); 621 if (verbose) {
580 if(verbose && syncsource_found) printf("synchronization source found\n"); 622 printf("%d candidate peers available\n", num_candidates);
581 if(! syncsource_found){ 623 }
624 if (verbose && syncsource_found) {
625 printf("synchronization source found\n");
626 }
627 if (!syncsource_found) {
582 *status = STATE_UNKNOWN; 628 *status = STATE_UNKNOWN;
583 if(verbose) printf("warning: no synchronization source found\n"); 629 if (verbose) {
630 printf("warning: no synchronization source found\n");
631 }
584 } 632 }
585 633
586 634 for (run = 0; run < AVG_NUM; run++) {
587 for (run=0; run<AVG_NUM; run++){ 635 if (verbose) {
588 if(verbose) printf("jitter run %d of %d\n", run+1, AVG_NUM); 636 printf("jitter run %d of %d\n", run + 1, AVG_NUM);
589 for (i = 0; i < npeers; i++){ 637 }
638 for (i = 0; i < npeers; i++) {
590 /* Only query this server if it is the current sync source */ 639 /* Only query this server if it is the current sync source */
591 if (PEER_SEL(peers[i].status) >= min_peer_sel){ 640 if (PEER_SEL(peers[i].status) >= min_peer_sel) {
592 char jitter_data[MAX_CM_SIZE+1]; 641 char jitter_data[MAX_CM_SIZE + 1];
593 size_t jitter_data_count; 642 size_t jitter_data_count;
594 643
595 num_selected++; 644 num_selected++;
@@ -602,7 +651,7 @@ double jitter_request(int *status){
602 */ 651 */
603 /* Older servers doesn't know what jitter is, so if we get an 652 /* Older servers doesn't know what jitter is, so if we get an
604 * error on the first pass we redo it with "dispersion" */ 653 * error on the first pass we redo it with "dispersion" */
605 strncpy(req.data, getvar, MAX_CM_SIZE-1); 654 strncpy(req.data, getvar, MAX_CM_SIZE - 1);
606 req.count = htons(strlen(getvar)); 655 req.count = htons(strlen(getvar));
607 DBG(printf("sending READVAR request...\n")); 656 DBG(printf("sending READVAR request...\n"));
608 write(conn, &req, SIZEOF_NTPCM(req)); 657 write(conn, &req, SIZEOF_NTPCM(req));
@@ -613,8 +662,11 @@ double jitter_request(int *status){
613 read(conn, &req, SIZEOF_NTPCM(req)); 662 read(conn, &req, SIZEOF_NTPCM(req));
614 DBG(print_ntp_control_message(&req)); 663 DBG(print_ntp_control_message(&req));
615 664
616 if(req.op&REM_ERROR && strstr(getvar, "jitter")) { 665 if (req.op & REM_ERROR && strstr(getvar, "jitter")) {
617 if(verbose) printf("The 'jitter' command failed (old ntp server?)\nRestarting with 'dispersion'...\n"); 666 if (verbose) {
667 printf("The 'jitter' command failed (old ntp server?)\nRestarting with "
668 "'dispersion'...\n");
669 }
618 getvar = "dispersion"; 670 getvar = "dispersion";
619 num_selected--; 671 num_selected--;
620 i--; 672 i--;
@@ -622,32 +674,33 @@ double jitter_request(int *status){
622 } 674 }
623 675
624 /* get to the float value */ 676 /* get to the float value */
625 if(verbose) { 677 if (verbose) {
626 printf("parsing jitter from peer %.2x: ", ntohs(peers[i].assoc)); 678 printf("parsing jitter from peer %.2x: ", ntohs(peers[i].assoc));
627 } 679 }
628 if((jitter_data_count = ntohs(req.count)) >= sizeof(jitter_data)){ 680 if ((jitter_data_count = ntohs(req.count)) >= sizeof(jitter_data)) {
629 die(STATE_UNKNOWN, 681 die(STATE_UNKNOWN, _("jitter response too large (%lu bytes)\n"),
630 _("jitter response too large (%lu bytes)\n"), 682 (unsigned long)jitter_data_count);
631 (unsigned long)jitter_data_count);
632 } 683 }
633 memcpy(jitter_data, req.data, jitter_data_count); 684 memcpy(jitter_data, req.data, jitter_data_count);
634 jitter_data[jitter_data_count] = '\0'; 685 jitter_data[jitter_data_count] = '\0';
635 startofvalue = strchr(jitter_data, '='); 686 startofvalue = strchr(jitter_data, '=');
636 if(startofvalue != NULL) { 687 if (startofvalue != NULL) {
637 startofvalue++; 688 startofvalue++;
638 jitter = strtod(startofvalue, &nptr); 689 jitter = strtod(startofvalue, &nptr);
639 } 690 }
640 if(startofvalue == NULL || startofvalue==nptr){ 691 if (startofvalue == NULL || startofvalue == nptr) {
641 printf("warning: unable to read server jitter response.\n"); 692 printf("warning: unable to read server jitter response.\n");
642 *status = STATE_UNKNOWN; 693 *status = STATE_UNKNOWN;
643 } else { 694 } else {
644 if(verbose) printf("%g\n", jitter); 695 if (verbose) {
696 printf("%g\n", jitter);
697 }
645 num_valid++; 698 num_valid++;
646 rval += jitter; 699 rval += jitter;
647 } 700 }
648 } 701 }
649 } 702 }
650 if(verbose){ 703 if (verbose) {
651 printf("jitter parsed from %d/%d peers\n", num_valid, num_selected); 704 printf("jitter parsed from %d/%d peers\n", num_valid, num_selected);
652 } 705 }
653 } 706 }
@@ -655,37 +708,33 @@ double jitter_request(int *status){
655 rval = num_valid ? rval / num_valid : -1.0; 708 rval = num_valid ? rval / num_valid : -1.0;
656 709
657 close(conn); 710 close(conn);
658 if(peers!=NULL) free(peers); 711 if (peers != NULL) {
712 free(peers);
713 }
659 /* If we return -1.0, it means no synchronization source was found */ 714 /* If we return -1.0, it means no synchronization source was found */
660 return rval; 715 return rval;
661} 716}
662 717
663int process_arguments(int argc, char **argv){ 718int process_arguments(int argc, char **argv) {
664 int c; 719 int c;
665 int option=0; 720 int option = 0;
666 static struct option longopts[] = { 721 static struct option longopts[] = {
667 {"version", no_argument, 0, 'V'}, 722 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'},
668 {"help", no_argument, 0, 'h'}, 723 {"verbose", no_argument, 0, 'v'}, {"use-ipv4", no_argument, 0, '4'},
669 {"verbose", no_argument, 0, 'v'}, 724 {"use-ipv6", no_argument, 0, '6'}, {"warning", required_argument, 0, 'w'},
670 {"use-ipv4", no_argument, 0, '4'}, 725 {"critical", required_argument, 0, 'c'}, {"jwarn", required_argument, 0, 'j'},
671 {"use-ipv6", no_argument, 0, '6'}, 726 {"jcrit", required_argument, 0, 'k'}, {"timeout", required_argument, 0, 't'},
672 {"warning", required_argument, 0, 'w'}, 727 {"hostname", required_argument, 0, 'H'}, {0, 0, 0, 0}};
673 {"critical", required_argument, 0, 'c'}, 728
674 {"jwarn", required_argument, 0, 'j'}, 729 if (argc < 2) {
675 {"jcrit", required_argument, 0, 'k'}, 730 usage("\n");
676 {"timeout", required_argument, 0, 't'}, 731 }
677 {"hostname", required_argument, 0, 'H'},
678 {0, 0, 0, 0}
679 };
680
681
682 if (argc < 2)
683 usage ("\n");
684 732
685 while (1) { 733 while (1) {
686 c = getopt_long (argc, argv, "Vhv46w:c:j:k:t:H:", longopts, &option); 734 c = getopt_long(argc, argv, "Vhv46w:c:j:k:t:H:", longopts, &option);
687 if (c == -1 || c == EOF || c == 1) 735 if (c == -1 || c == EOF || c == 1) {
688 break; 736 break;
737 }
689 738
690 switch (c) { 739 switch (c) {
691 case 'h': 740 case 'h':
@@ -716,12 +765,13 @@ int process_arguments(int argc, char **argv){
716 jcrit = optarg; 765 jcrit = optarg;
717 break; 766 break;
718 case 'H': 767 case 'H':
719 if(!is_host(optarg)) 768 if (!is_host(optarg)) {
720 usage2(_("Invalid hostname/address"), optarg); 769 usage2(_("Invalid hostname/address"), optarg);
770 }
721 server_address = strdup(optarg); 771 server_address = strdup(optarg);
722 break; 772 break;
723 case 't': 773 case 't':
724 socket_timeout=atoi(optarg); 774 socket_timeout = atoi(optarg);
725 break; 775 break;
726 case '4': 776 case '4':
727 address_family = AF_INET; 777 address_family = AF_INET;
@@ -730,64 +780,59 @@ int process_arguments(int argc, char **argv){
730#ifdef USE_IPV6 780#ifdef USE_IPV6
731 address_family = AF_INET6; 781 address_family = AF_INET6;
732#else 782#else
733 usage4 (_("IPv6 support not available")); 783 usage4(_("IPv6 support not available"));
734#endif 784#endif
735 break; 785 break;
736 case '?': 786 case '?':
737 /* print short usage statement if args not parsable */ 787 /* print short usage statement if args not parsable */
738 usage5 (); 788 usage5();
739 break; 789 break;
740 } 790 }
741 } 791 }
742 792
743 if(server_address == NULL){ 793 if (server_address == NULL) {
744 usage4(_("Hostname was not supplied")); 794 usage4(_("Hostname was not supplied"));
745 } 795 }
746 796
747 return 0; 797 return 0;
748} 798}
749 799
750char *perfd_offset (double offset) 800char *perfd_offset(double offset) {
751{ 801 return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true,
752 return fperfdata ("offset", offset, "s", 802 offset_thresholds->critical->end, false, 0, false, 0);
753 true, offset_thresholds->warning->end,
754 true, offset_thresholds->critical->end,
755 false, 0, false, 0);
756} 803}
757 804
758char *perfd_jitter (double jitter) 805char *perfd_jitter(double jitter) {
759{ 806 return fperfdata("jitter", jitter, "s", do_jitter, jitter_thresholds->warning->end, do_jitter,
760 return fperfdata ("jitter", jitter, "s", 807 jitter_thresholds->critical->end, true, 0, false, 0);
761 do_jitter, jitter_thresholds->warning->end,
762 do_jitter, jitter_thresholds->critical->end,
763 true, 0, false, 0);
764} 808}
765 809
766int main(int argc, char *argv[]){ 810int main(int argc, char *argv[]) {
767 int result, offset_result, jitter_result; 811 int result, offset_result, jitter_result;
768 double offset=0, jitter=0; 812 double offset = 0, jitter = 0;
769 char *result_line, *perfdata_line; 813 char *result_line, *perfdata_line;
770 814
771 setlocale (LC_ALL, ""); 815 setlocale(LC_ALL, "");
772 bindtextdomain (PACKAGE, LOCALEDIR); 816 bindtextdomain(PACKAGE, LOCALEDIR);
773 textdomain (PACKAGE); 817 textdomain(PACKAGE);
774 818
775 result = offset_result = jitter_result = STATE_OK; 819 result = offset_result = jitter_result = STATE_OK;
776 820
777 /* Parse extra opts if any */ 821 /* Parse extra opts if any */
778 argv=np_extra_opts (&argc, argv, progname); 822 argv = np_extra_opts(&argc, argv, progname);
779 823
780 if (process_arguments (argc, argv) == ERROR) 824 if (process_arguments(argc, argv) == ERROR) {
781 usage4 (_("Could not parse arguments")); 825 usage4(_("Could not parse arguments"));
826 }
782 827
783 set_thresholds(&offset_thresholds, owarn, ocrit); 828 set_thresholds(&offset_thresholds, owarn, ocrit);
784 set_thresholds(&jitter_thresholds, jwarn, jcrit); 829 set_thresholds(&jitter_thresholds, jwarn, jcrit);
785 830
786 /* initialize alarm signal handling */ 831 /* initialize alarm signal handling */
787 signal (SIGALRM, socket_timeout_alarm_handler); 832 signal(SIGALRM, socket_timeout_alarm_handler);
788 833
789 /* set socket timeout */ 834 /* set socket timeout */
790 alarm (socket_timeout); 835 alarm(socket_timeout);
791 836
792 offset = offset_request(server_address, &offset_result); 837 offset = offset_request(server_address, &offset_result);
793 /* check_ntp used to always return CRITICAL if offset_result == STATE_UNKNOWN. 838 /* check_ntp used to always return CRITICAL if offset_result == STATE_UNKNOWN.
@@ -803,31 +848,32 @@ int main(int argc, char *argv[]){
803 * servers recognize. Trying to check the jitter on OpenNTPD 848 * servers recognize. Trying to check the jitter on OpenNTPD
804 * (for example) will result in an error 849 * (for example) will result in an error
805 */ 850 */
806 if(do_jitter){ 851 if (do_jitter) {
807 jitter=jitter_request(&jitter_result); 852 jitter = jitter_request(&jitter_result);
808 result = max_state_alt(result, get_status(jitter, jitter_thresholds)); 853 result = max_state_alt(result, get_status(jitter, jitter_thresholds));
809 /* -1 indicates that we couldn't calculate the jitter 854 /* -1 indicates that we couldn't calculate the jitter
810 * Only overrides STATE_OK from the offset */ 855 * Only overrides STATE_OK from the offset */
811 if(jitter == -1.0 && result == STATE_OK) 856 if (jitter == -1.0 && result == STATE_OK) {
812 result = STATE_UNKNOWN; 857 result = STATE_UNKNOWN;
858 }
813 } 859 }
814 result = max_state_alt(result, jitter_result); 860 result = max_state_alt(result, jitter_result);
815 861
816 switch (result) { 862 switch (result) {
817 case STATE_CRITICAL : 863 case STATE_CRITICAL:
818 xasprintf(&result_line, _("NTP CRITICAL:")); 864 xasprintf(&result_line, _("NTP CRITICAL:"));
819 break; 865 break;
820 case STATE_WARNING : 866 case STATE_WARNING:
821 xasprintf(&result_line, _("NTP WARNING:")); 867 xasprintf(&result_line, _("NTP WARNING:"));
822 break; 868 break;
823 case STATE_OK : 869 case STATE_OK:
824 xasprintf(&result_line, _("NTP OK:")); 870 xasprintf(&result_line, _("NTP OK:"));
825 break; 871 break;
826 default : 872 default:
827 xasprintf(&result_line, _("NTP UNKNOWN:")); 873 xasprintf(&result_line, _("NTP UNKNOWN:"));
828 break; 874 break;
829 } 875 }
830 if(offset_result == STATE_UNKNOWN){ 876 if (offset_result == STATE_UNKNOWN) {
831 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown")); 877 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
832 xasprintf(&perfdata_line, ""); 878 xasprintf(&perfdata_line, "");
833 } else { 879 } else {
@@ -836,41 +882,41 @@ int main(int argc, char *argv[]){
836 } 882 }
837 if (do_jitter) { 883 if (do_jitter) {
838 xasprintf(&result_line, "%s, jitter=%f", result_line, jitter); 884 xasprintf(&result_line, "%s, jitter=%f", result_line, jitter);
839 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_jitter(jitter)); 885 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_jitter(jitter));
840 } 886 }
841 printf("%s|%s\n", result_line, perfdata_line); 887 printf("%s|%s\n", result_line, perfdata_line);
842 888
843 if(server_address!=NULL) free(server_address); 889 if (server_address != NULL) {
890 free(server_address);
891 }
844 return result; 892 return result;
845} 893}
846 894
847 895void print_help(void) {
848
849void print_help(void){
850 print_revision(progname, NP_VERSION); 896 print_revision(progname, NP_VERSION);
851 897
852 printf ("Copyright (c) 2006 Sean Finney\n"); 898 printf("Copyright (c) 2006 Sean Finney\n");
853 printf (COPYRIGHT, copyright, email); 899 printf(COPYRIGHT, copyright, email);
854 900
855 printf ("%s\n", _("This plugin checks the selected ntp server")); 901 printf("%s\n", _("This plugin checks the selected ntp server"));
856 902
857 printf ("\n\n"); 903 printf("\n\n");
858 904
859 print_usage(); 905 print_usage();
860 printf (UT_HELP_VRSN); 906 printf(UT_HELP_VRSN);
861 printf (UT_EXTRA_OPTS); 907 printf(UT_EXTRA_OPTS);
862 printf (UT_HOST_PORT, 'p', "123"); 908 printf(UT_HOST_PORT, 'p', "123");
863 printf (UT_IPv46); 909 printf(UT_IPv46);
864 printf (" %s\n", "-w, --warning=THRESHOLD"); 910 printf(" %s\n", "-w, --warning=THRESHOLD");
865 printf (" %s\n", _("Offset to result in warning status (seconds)")); 911 printf(" %s\n", _("Offset to result in warning status (seconds)"));
866 printf (" %s\n", "-c, --critical=THRESHOLD"); 912 printf(" %s\n", "-c, --critical=THRESHOLD");
867 printf (" %s\n", _("Offset to result in critical status (seconds)")); 913 printf(" %s\n", _("Offset to result in critical status (seconds)"));
868 printf (" %s\n", "-j, --jwarn=THRESHOLD"); 914 printf(" %s\n", "-j, --jwarn=THRESHOLD");
869 printf (" %s\n", _("Warning threshold for jitter")); 915 printf(" %s\n", _("Warning threshold for jitter"));
870 printf (" %s\n", "-k, --jcrit=THRESHOLD"); 916 printf(" %s\n", "-k, --jcrit=THRESHOLD");
871 printf (" %s\n", _("Critical threshold for jitter")); 917 printf(" %s\n", _("Critical threshold for jitter"));
872 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 918 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
873 printf (UT_VERBOSE); 919 printf(UT_VERBOSE);
874 920
875 printf("\n"); 921 printf("\n");
876 printf("%s\n", _("Notes:")); 922 printf("%s\n", _("Notes:"));
@@ -881,21 +927,21 @@ void print_help(void){
881 printf(" %s\n", _("Normal offset check:")); 927 printf(" %s\n", _("Normal offset check:"));
882 printf(" %s\n", ("./check_ntp -H ntpserv -w 0.5 -c 1")); 928 printf(" %s\n", ("./check_ntp -H ntpserv -w 0.5 -c 1"));
883 printf("\n"); 929 printf("\n");
884 printf(" %s\n", _("Check jitter too, avoiding critical notifications if jitter isn't available")); 930 printf(" %s\n",
931 _("Check jitter too, avoiding critical notifications if jitter isn't available"));
885 printf(" %s\n", _("(See Notes above for more details on thresholds formats):")); 932 printf(" %s\n", _("(See Notes above for more details on thresholds formats):"));
886 printf(" %s\n", ("./check_ntp -H ntpserv -w 0.5 -c 1 -j -1:100 -k -1:200")); 933 printf(" %s\n", ("./check_ntp -H ntpserv -w 0.5 -c 1 -j -1:100 -k -1:200"));
887 934
888 printf (UT_SUPPORT); 935 printf(UT_SUPPORT);
889 936
890 printf ("%s\n", _("WARNING: check_ntp is deprecated. Please use check_ntp_peer or")); 937 printf("%s\n", _("WARNING: check_ntp is deprecated. Please use check_ntp_peer or"));
891 printf ("%s\n\n", _("check_ntp_time instead.")); 938 printf("%s\n\n", _("check_ntp_time instead."));
892} 939}
893 940
894void 941void print_usage(void) {
895print_usage(void) 942 printf("%s\n", _("WARNING: check_ntp is deprecated. Please use check_ntp_peer or"));
896{ 943 printf("%s\n\n", _("check_ntp_time instead."));
897 printf ("%s\n", _("WARNING: check_ntp is deprecated. Please use check_ntp_peer or")); 944 printf("%s\n", _("Usage:"));
898 printf ("%s\n\n", _("check_ntp_time instead.")); 945 printf(" %s -H <host> [-w <warn>] [-c <crit>] [-j <warn>] [-k <crit>] [-4|-6] [-v verbose]\n",
899 printf ("%s\n", _("Usage:")); 946 progname);
900 printf(" %s -H <host> [-w <warn>] [-c <crit>] [-j <warn>] [-k <crit>] [-4|-6] [-v verbose]\n", progname);
901} 947}
diff --git a/plugins/check_ntp_peer.c b/plugins/check_ntp_peer.c
index 464a9e10..24d1c9b5 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,97 @@ 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) \
136 (12 + ntohs(m.count) + ((ntohs(m.count) % 4) ? 4 - (ntohs(m.count) % 4) : 0))
135 137
136/* finally, a little helper or two for debugging: */ 138/* finally, a little helper or two for debugging: */
137#define DBG(x) do{if(verbose>1){ x; }}while(0); 139#define DBG(x) \
138#define PRINTSOCKADDR(x) \ 140 do { \
139 do{ \ 141 if (verbose > 1) { \
140 printf("%u.%u.%u.%u", (x>>24)&0xff, (x>>16)&0xff, (x>>8)&0xff, x&0xff);\ 142 x; \
141 }while(0); 143 } \
142 144 } while (0);
143void print_ntp_control_message(const ntp_control_message *p){ 145#define PRINTSOCKADDR(x) \
144 int i=0, numpeers=0; 146 do { \
145 const ntp_assoc_status_pair *peer=NULL; 147 printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \
146 148 } while (0);
149
150void print_ntp_control_message(const ntp_control_message *message) {
147 printf("control packet contents:\n"); 151 printf("control packet contents:\n");
148 printf("\tflags: 0x%.2x , 0x%.2x\n", p->flags, p->op); 152 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); 153 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); 154 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); 155 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); 156 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); 157 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); 158 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); 159 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)); 160 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)); 161 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)); 162 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)); 163 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)); 164 printf("\tcount: %d (0x%.2x)\n", ntohs(message->count), ntohs(message->count));
161 numpeers=ntohs(p->count)/(sizeof(ntp_assoc_status_pair)); 165
162 if(p->op&REM_RESP && p->op&OP_READSTAT){ 166 int numpeers = ntohs(message->count) / (sizeof(ntp_assoc_status_pair));
163 peer=(ntp_assoc_status_pair*)p->data; 167 if (message->op & REM_RESP && message->op & OP_READSTAT) {
164 for(i=0;i<numpeers;i++){ 168 const ntp_assoc_status_pair *peer = (ntp_assoc_status_pair *)message->data;
165 printf("\tpeer id %.2x status %.2x", 169 for (int i = 0; i < numpeers; i++) {
166 ntohs(peer[i].assoc), ntohs(peer[i].status)); 170 printf("\tpeer id %.2x status %.2x", ntohs(peer[i].assoc), ntohs(peer[i].status));
167 if(PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE){ 171 if (PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE) {
168 printf(" <-- current sync source"); 172 printf(" <-- current sync source");
169 } else if(PEER_SEL(peer[i].status) >= PEER_INCLUDED){ 173 } else if (PEER_SEL(peer[i].status) >= PEER_INCLUDED) {
170 printf(" <-- current sync candidate"); 174 printf(" <-- current sync candidate");
171 } else if(PEER_SEL(peer[i].status) >= PEER_TRUECHIMER){ 175 } else if (PEER_SEL(peer[i].status) >= PEER_TRUECHIMER) {
172 printf(" <-- outlyer, but truechimer"); 176 printf(" <-- outlyer, but truechimer");
173 } 177 }
174 printf("\n"); 178 printf("\n");
@@ -176,14 +180,13 @@ void print_ntp_control_message(const ntp_control_message *p){
176 } 180 }
177} 181}
178 182
179void 183void 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){ 184 memset(message, 0, sizeof(ntp_control_message));
181 memset(p, 0, sizeof(ntp_control_message)); 185 LI_SET(message->flags, LI_NOWARNING);
182 LI_SET(p->flags, LI_NOWARNING); 186 VN_SET(message->flags, VN_RESERVED);
183 VN_SET(p->flags, VN_RESERVED); 187 MODE_SET(message->flags, MODE_CONTROLMSG);
184 MODE_SET(p->flags, MODE_CONTROLMSG); 188 OP_SET(message->op, opcode);
185 OP_SET(p->op, opcode); 189 message->seq = htons(seq);
186 p->seq = htons(seq);
187 /* Remaining fields are zero for requests */ 190 /* Remaining fields are zero for requests */
188} 191}
189 192
@@ -198,22 +201,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 201 * 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 202 * used later in main to check is the server was synchronized. It works
200 * so I left it alone */ 203 * so I left it alone */
201int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum, int *num_truechimers){ 204typedef struct {
202 int conn=-1, i, npeers=0, num_candidates=0; 205 mp_state_enum state;
203 double tmp_offset = 0; 206 mp_state_enum offset_result;
204 int min_peer_sel=PEER_INCLUDED; 207 double offset;
205 int peers_size=0, peer_offset=0; 208 double jitter;
206 int status; 209 long stratum;
207 ntp_assoc_status_pair *peers=NULL; 210 int num_truechimers;
208 ntp_control_message req; 211} ntp_request_result;
209 const char *getvar = "stratum,offset,jitter"; 212ntp_request_result ntp_request(const check_ntp_peer_config config) {
210 char *data, *value, *nptr; 213
211 void *tmp; 214 ntp_request_result result = {
212 215 .state = STATE_OK,
213 status = STATE_OK; 216 .offset_result = STATE_UNKNOWN,
214 *offset_result = STATE_UNKNOWN; 217 .jitter = -1,
215 *jitter = *stratum = -1; 218 .stratum = -1,
216 *num_truechimers = 0; 219 .num_truechimers = 0,
220 };
217 221
218 /* Long-winded explanation: 222 /* Long-winded explanation:
219 * Getting the sync peer offset, jitter and stratum requires a number of 223 * Getting the sync peer offset, jitter and stratum requires a number of
@@ -231,11 +235,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[] 235 * 4) Extract the offset, jitter and stratum value from the data[]
232 * (it's ASCII) 236 * (it's ASCII)
233 */ 237 */
234 my_udp_connect(server_address, port, &conn); 238 int min_peer_sel = PEER_INCLUDED;
239 int num_candidates = 0;
240 void *tmp;
241 ntp_assoc_status_pair *peers = NULL;
242 int peer_offset = 0;
243 size_t peers_size = 0;
244 size_t npeers = 0;
245 int conn = -1;
246 my_udp_connect(config.server_address, config.port, &conn);
235 247
236 /* keep sending requests until the server stops setting the 248 /* keep sending requests until the server stops setting the
237 * REM_MORE bit, though usually this is only 1 packet. */ 249 * REM_MORE bit, though usually this is only 1 packet. */
238 do{ 250 ntp_control_message req;
251 do {
239 setup_control_request(&req, OP_READSTAT, 1); 252 setup_control_request(&req, OP_READSTAT, 1);
240 DBG(printf("sending READSTAT request")); 253 DBG(printf("sending READSTAT request"));
241 write(conn, &req, SIZEOF_NTPCM(req)); 254 write(conn, &req, SIZEOF_NTPCM(req));
@@ -243,63 +256,81 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
243 256
244 do { 257 do {
245 /* Attempt to read the largest size packet possible */ 258 /* Attempt to read the largest size packet possible */
246 req.count=htons(MAX_CM_SIZE); 259 req.count = htons(MAX_CM_SIZE);
247 DBG(printf("receiving READSTAT response")) 260 DBG(printf("receiving READSTAT response"))
248 if(read(conn, &req, SIZEOF_NTPCM(req)) == -1) 261 if (read(conn, &req, SIZEOF_NTPCM(req)) == -1) {
249 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); 262 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
263 }
250 DBG(print_ntp_control_message(&req)); 264 DBG(print_ntp_control_message(&req));
251 /* discard obviously invalid packets */ 265 /* discard obviously invalid packets */
252 if (ntohs(req.count) > MAX_CM_SIZE) 266 if (ntohs(req.count) > MAX_CM_SIZE) {
253 die(STATE_CRITICAL, "NTP CRITICAL: Invalid packet received from NTP server\n"); 267 die(STATE_CRITICAL, "NTP CRITICAL: Invalid packet received from NTP server\n");
254 } while (!(req.op&OP_READSTAT && ntohs(req.seq) == 1)); 268 }
269 } while (!(req.op & OP_READSTAT && ntohs(req.seq) == 1));
255 270
256 if (LI(req.flags) == LI_ALARM) li_alarm = true; 271 if (LI(req.flags) == LI_ALARM) {
272 li_alarm = true;
273 }
257 /* Each peer identifier is 4 bytes in the data section, which 274 /* Each peer identifier is 4 bytes in the data section, which
258 * we represent as a ntp_assoc_status_pair datatype. 275 * we represent as a ntp_assoc_status_pair datatype.
259 */ 276 */
260 peers_size+=ntohs(req.count); 277 peers_size += ntohs(req.count);
261 if((tmp=realloc(peers, peers_size)) == NULL) 278 if ((tmp = realloc(peers, peers_size)) == NULL) {
262 free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n"); 279 free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n");
263 peers=tmp; 280 }
264 memcpy((void*)((ptrdiff_t)peers+peer_offset), (void*)req.data, ntohs(req.count)); 281 peers = tmp;
265 npeers=peers_size/sizeof(ntp_assoc_status_pair); 282 memcpy((peers + peer_offset), (void *)req.data, ntohs(req.count));
266 peer_offset+=ntohs(req.count); 283 npeers = peers_size / sizeof(ntp_assoc_status_pair);
267 } while(req.op&REM_MORE); 284 peer_offset += ntohs(req.count);
285 } while (req.op & REM_MORE);
268 286
269 /* first, let's find out if we have a sync source, or if there are 287 /* 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 288 * at least some candidates. In the latter case we'll issue
271 * a warning but go ahead with the check on them. */ 289 * a warning but go ahead with the check on them. */
272 for (i = 0; i < npeers; i++){ 290 for (size_t i = 0; i < npeers; i++) {
273 if(PEER_SEL(peers[i].status) >= PEER_TRUECHIMER){ 291 if (PEER_SEL(peers[i].status) >= PEER_TRUECHIMER) {
274 (*num_truechimers)++; 292 result.num_truechimers++;
275 if(PEER_SEL(peers[i].status) >= PEER_INCLUDED){ 293 if (PEER_SEL(peers[i].status) >= PEER_INCLUDED) {
276 num_candidates++; 294 num_candidates++;
277 if(PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE){ 295 if (PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE) {
278 syncsource_found = true; 296 syncsource_found = true;
279 min_peer_sel=PEER_SYNCSOURCE; 297 min_peer_sel = PEER_SYNCSOURCE;
280 } 298 }
281 } 299 }
282 } 300 }
283 } 301 }
284 if(verbose) printf("%d candidate peers available\n", num_candidates); 302
285 if(verbose && syncsource_found) printf("synchronization source found\n"); 303 if (verbose) {
286 if(! syncsource_found){ 304 printf("%d candidate peers available\n", num_candidates);
287 status = STATE_WARNING;
288 if(verbose) printf("warning: no synchronization source found\n");
289 } 305 }
290 if(li_alarm){ 306 if (verbose && syncsource_found) {
291 status = STATE_WARNING; 307 printf("synchronization source found\n");
292 if(verbose) printf("warning: LI_ALARM bit is set\n");
293 } 308 }
294 309
310 if (!syncsource_found) {
311 result.state = STATE_WARNING;
312 if (verbose) {
313 printf("warning: no synchronization source found\n");
314 }
315 }
316 if (li_alarm) {
317 result.state = STATE_WARNING;
318 if (verbose) {
319 printf("warning: LI_ALARM bit is set\n");
320 }
321 }
295 322
296 for (i = 0; i < npeers; i++){ 323 const char *getvar = "stratum,offset,jitter";
324 char *data;
325 for (size_t i = 0; i < npeers; i++) {
297 /* Only query this server if it is the current sync source */ 326 /* 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 */ 327 /* If there's no sync.peer, query all candidates and use the best one */
299 if (PEER_SEL(peers[i].status) >= min_peer_sel){ 328 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)); 329 if (verbose) {
330 printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc));
331 }
301 xasprintf(&data, ""); 332 xasprintf(&data, "");
302 do{ 333 do {
303 setup_control_request(&req, OP_READVAR, 2); 334 setup_control_request(&req, OP_READVAR, 2);
304 req.assoc = peers[i].assoc; 335 req.assoc = peers[i].assoc;
305 /* Putting the wanted variable names in the request 336 /* Putting the wanted variable names in the request
@@ -309,7 +340,7 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
309 */ 340 */
310 /* Older servers doesn't know what jitter is, so if we get an 341 /* Older servers doesn't know what jitter is, so if we get an
311 * error on the first pass we redo it with "dispersion" */ 342 * error on the first pass we redo it with "dispersion" */
312 strncpy(req.data, getvar, MAX_CM_SIZE-1); 343 strncpy(req.data, getvar, MAX_CM_SIZE - 1);
313 req.count = htons(strlen(getvar)); 344 req.count = htons(strlen(getvar));
314 DBG(printf("sending READVAR request...\n")); 345 DBG(printf("sending READVAR request...\n"));
315 write(conn, &req, SIZEOF_NTPCM(req)); 346 write(conn, &req, SIZEOF_NTPCM(req));
@@ -320,131 +351,159 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
320 DBG(printf("receiving READVAR response...\n")); 351 DBG(printf("receiving READVAR response...\n"));
321 read(conn, &req, SIZEOF_NTPCM(req)); 352 read(conn, &req, SIZEOF_NTPCM(req));
322 DBG(print_ntp_control_message(&req)); 353 DBG(print_ntp_control_message(&req));
323 } while (!(req.op&OP_READVAR && ntohs(req.seq) == 2)); 354 } while (!(req.op & OP_READVAR && ntohs(req.seq) == 2));
324 355
325 if(!(req.op&REM_ERROR)) 356 if (!(req.op & REM_ERROR)) {
326 xasprintf(&data, "%s%s", data, req.data); 357 xasprintf(&data, "%s%s", data, req.data);
327 } while(req.op&REM_MORE); 358 }
328 359 } while (req.op & REM_MORE);
329 if(req.op&REM_ERROR) { 360
330 if(strstr(getvar, "jitter")) { 361 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"); 362 if (strstr(getvar, "jitter")) {
363 if (verbose) {
364 printf("The command failed. This is usually caused by servers refusing the "
365 "'jitter'\nvariable. Restarting with "
366 "'dispersion'...\n");
367 }
332 getvar = "stratum,offset,dispersion"; 368 getvar = "stratum,offset,dispersion";
333 i--; 369 i--;
334 continue; 370 continue;
335 } else if(strlen(getvar)) { 371 }
336 if(verbose) printf("Server didn't like dispersion either; will retrieve everything\n"); 372 if (strlen(getvar)) {
373 if (verbose) {
374 printf("Server didn't like dispersion either; will retrieve everything\n");
375 }
337 getvar = ""; 376 getvar = "";
338 i--; 377 i--;
339 continue; 378 continue;
340 } 379 }
341 } 380 }
342 381
343 if(verbose > 1) 382 if (verbose > 1) {
344 printf("Server responded: >>>%s<<<\n", data); 383 printf("Server responded: >>>%s<<<\n", data);
384 }
345 385
386 double tmp_offset = 0;
387 char *value;
388 char *nptr;
346 /* get the offset */ 389 /* get the offset */
347 if(verbose) 390 if (verbose) {
348 printf("parsing offset from peer %.2x: ", ntohs(peers[i].assoc)); 391 printf("parsing offset from peer %.2x: ", ntohs(peers[i].assoc));
392 }
349 393
350 value = np_extract_ntpvar(data, "offset"); 394 value = np_extract_ntpvar(data, "offset");
351 nptr=NULL; 395 nptr = NULL;
352 /* Convert the value if we have one */ 396 /* Convert the value if we have one */
353 if(value != NULL) 397 if (value != NULL) {
354 tmp_offset = strtod(value, &nptr) / 1000; 398 tmp_offset = strtod(value, &nptr) / 1000;
399 }
355 /* If value is null or no conversion was performed */ 400 /* If value is null or no conversion was performed */
356 if(value == NULL || value==nptr) { 401 if (value == NULL || value == nptr) {
357 if(verbose) printf("error: unable to read server offset response.\n"); 402 if (verbose) {
403 printf("error: unable to read server offset response.\n");
404 }
358 } else { 405 } else {
359 if(verbose) printf("%.10g\n", tmp_offset); 406 if (verbose) {
360 if(*offset_result == STATE_UNKNOWN || fabs(tmp_offset) < fabs(*offset)) { 407 printf("%.10g\n", tmp_offset);
361 *offset = tmp_offset; 408 }
362 *offset_result = STATE_OK; 409 if (result.offset_result == STATE_UNKNOWN ||
410 fabs(tmp_offset) < fabs(result.offset)) {
411 result.offset = tmp_offset;
412 result.offset_result = STATE_OK;
363 } else { 413 } else {
364 /* Skip this one; move to the next */ 414 /* Skip this one; move to the next */
365 continue; 415 continue;
366 } 416 }
367 } 417 }
368 418
369 if(do_jitter) { 419 if (config.do_jitter) {
370 /* get the jitter */ 420 /* get the jitter */
371 if(verbose) { 421 if (verbose) {
372 printf("parsing %s from peer %.2x: ", strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter", ntohs(peers[i].assoc)); 422 printf("parsing %s from peer %.2x: ",
423 strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter",
424 ntohs(peers[i].assoc));
373 } 425 }
374 value = np_extract_ntpvar(data, strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter"); 426 value = np_extract_ntpvar(data, strstr(getvar, "dispersion") != NULL ? "dispersion"
375 nptr=NULL; 427 : "jitter");
428 nptr = NULL;
376 /* Convert the value if we have one */ 429 /* Convert the value if we have one */
377 if(value != NULL) 430 if (value != NULL) {
378 *jitter = strtod(value, &nptr); 431 result.jitter = strtod(value, &nptr);
432 }
379 /* If value is null or no conversion was performed */ 433 /* If value is null or no conversion was performed */
380 if(value == NULL || value==nptr) { 434 if (value == NULL || value == nptr) {
381 if(verbose) printf("error: unable to read server jitter/dispersion response.\n"); 435 if (verbose) {
382 *jitter = -1; 436 printf("error: unable to read server jitter/dispersion response.\n");
383 } else if(verbose) { 437 }
384 printf("%.10g\n", *jitter); 438 result.jitter = -1;
439 } else if (verbose) {
440 printf("%.10g\n", result.jitter);
385 } 441 }
386 } 442 }
387 443
388 if(do_stratum) { 444 if (config.do_stratum) {
389 /* get the stratum */ 445 /* get the stratum */
390 if(verbose) { 446 if (verbose) {
391 printf("parsing stratum from peer %.2x: ", ntohs(peers[i].assoc)); 447 printf("parsing stratum from peer %.2x: ", ntohs(peers[i].assoc));
392 } 448 }
393 value = np_extract_ntpvar(data, "stratum"); 449 value = np_extract_ntpvar(data, "stratum");
394 nptr=NULL; 450 nptr = NULL;
395 /* Convert the value if we have one */ 451 /* Convert the value if we have one */
396 if(value != NULL) 452 if (value != NULL) {
397 *stratum = strtol(value, &nptr, 10); 453 result.stratum = strtol(value, &nptr, 10);
398 if(value == NULL || value==nptr) { 454 }
399 if(verbose) printf("error: unable to read server stratum response.\n"); 455 if (value == NULL || value == nptr) {
400 *stratum = -1; 456 if (verbose) {
457 printf("error: unable to read server stratum response.\n");
458 }
459 result.stratum = -1;
401 } else { 460 } else {
402 if(verbose) printf("%i\n", *stratum); 461 if (verbose) {
462 printf("%li\n", result.stratum);
463 }
403 } 464 }
404 } 465 }
405 } /* if (PEER_SEL(peers[i].status) >= min_peer_sel) */ 466 } /* if (PEER_SEL(peers[i].status) >= min_peer_sel) */
406 } /* for (i = 0; i < npeers; i++) */ 467 } /* for (i = 0; i < npeers; i++) */
407 468
408 close(conn); 469 close(conn);
409 if(peers!=NULL) free(peers); 470 if (peers != NULL) {
471 free(peers);
472 }
410 473
411 return status; 474 return result;
412} 475}
413 476
414int process_arguments(int argc, char **argv){ 477check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) {
415 int c;
416 int option=0;
417 static struct option longopts[] = { 478 static struct option longopts[] = {
418 {"version", no_argument, 0, 'V'}, 479 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'},
419 {"help", no_argument, 0, 'h'}, 480 {"verbose", no_argument, 0, 'v'}, {"use-ipv4", no_argument, 0, '4'},
420 {"verbose", no_argument, 0, 'v'}, 481 {"use-ipv6", no_argument, 0, '6'}, {"quiet", no_argument, 0, 'q'},
421 {"use-ipv4", no_argument, 0, '4'}, 482 {"warning", required_argument, 0, 'w'}, {"critical", required_argument, 0, 'c'},
422 {"use-ipv6", no_argument, 0, '6'}, 483 {"swarn", required_argument, 0, 'W'}, {"scrit", required_argument, 0, 'C'},
423 {"quiet", no_argument, 0, 'q'}, 484 {"jwarn", required_argument, 0, 'j'}, {"jcrit", required_argument, 0, 'k'},
424 {"warning", required_argument, 0, 'w'}, 485 {"twarn", required_argument, 0, 'm'}, {"tcrit", required_argument, 0, 'n'},
425 {"critical", required_argument, 0, 'c'}, 486 {"timeout", required_argument, 0, 't'}, {"hostname", required_argument, 0, 'H'},
426 {"swarn", required_argument, 0, 'W'}, 487 {"port", required_argument, 0, 'p'}, {0, 0, 0, 0}};
427 {"scrit", required_argument, 0, 'C'}, 488
428 {"jwarn", required_argument, 0, 'j'}, 489 if (argc < 2) {
429 {"jcrit", required_argument, 0, 'k'}, 490 usage("\n");
430 {"twarn", required_argument, 0, 'm'}, 491 }
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 492
439 if (argc < 2) 493 check_ntp_peer_config_wrapper result = {
440 usage ("\n"); 494 .errorcode = OK,
495 .config = check_ntp_peer_config_init(),
496 };
441 497
442 while (true) { 498 while (true) {
443 c = getopt_long (argc, argv, "Vhv46qw:c:W:C:j:k:m:n:t:H:p:", longopts, &option); 499 int option = 0;
444 if (c == -1 || c == EOF || c == 1) 500 int option_char =
501 getopt_long(argc, argv, "Vhv46qw:c:W:C:j:k:m:n:t:H:p:", longopts, &option);
502 if (option_char == -1 || option_char == EOF || option_char == 1) {
445 break; 503 break;
504 }
446 505
447 switch (c) { 506 switch (option_char) {
448 case 'h': 507 case 'h':
449 print_help(); 508 print_help();
450 exit(STATE_UNKNOWN); 509 exit(STATE_UNKNOWN);
@@ -457,48 +516,49 @@ int process_arguments(int argc, char **argv){
457 verbose++; 516 verbose++;
458 break; 517 break;
459 case 'q': 518 case 'q':
460 quiet = true; 519 result.config.quiet = true;
461 break; 520 break;
462 case 'w': 521 case 'w':
463 owarn = optarg; 522 result.config.owarn = optarg;
464 break; 523 break;
465 case 'c': 524 case 'c':
466 ocrit = optarg; 525 result.config.ocrit = optarg;
467 break; 526 break;
468 case 'W': 527 case 'W':
469 do_stratum = true; 528 result.config.do_stratum = true;
470 swarn = optarg; 529 result.config.swarn = optarg;
471 break; 530 break;
472 case 'C': 531 case 'C':
473 do_stratum = true; 532 result.config.do_stratum = true;
474 scrit = optarg; 533 result.config.scrit = optarg;
475 break; 534 break;
476 case 'j': 535 case 'j':
477 do_jitter = true; 536 result.config.do_jitter = true;
478 jwarn = optarg; 537 result.config.jwarn = optarg;
479 break; 538 break;
480 case 'k': 539 case 'k':
481 do_jitter = true; 540 result.config.do_jitter = true;
482 jcrit = optarg; 541 result.config.jcrit = optarg;
483 break; 542 break;
484 case 'm': 543 case 'm':
485 do_truechimers = true; 544 result.config.do_truechimers = true;
486 twarn = optarg; 545 result.config.twarn = optarg;
487 break; 546 break;
488 case 'n': 547 case 'n':
489 do_truechimers = true; 548 result.config.do_truechimers = true;
490 tcrit = optarg; 549 result.config.tcrit = optarg;
491 break; 550 break;
492 case 'H': 551 case 'H':
493 if(!is_host(optarg)) 552 if (!is_host(optarg)) {
494 usage2(_("Invalid hostname/address"), optarg); 553 usage2(_("Invalid hostname/address"), optarg);
495 server_address = strdup(optarg); 554 }
555 result.config.server_address = strdup(optarg);
496 break; 556 break;
497 case 'p': 557 case 'p':
498 port=atoi(optarg); 558 result.config.port = atoi(optarg);
499 break; 559 break;
500 case 't': 560 case 't':
501 socket_timeout=atoi(optarg); 561 socket_timeout = atoi(optarg);
502 break; 562 break;
503 case '4': 563 case '4':
504 address_family = AF_INET; 564 address_family = AF_INET;
@@ -507,222 +567,230 @@ int process_arguments(int argc, char **argv){
507#ifdef USE_IPV6 567#ifdef USE_IPV6
508 address_family = AF_INET6; 568 address_family = AF_INET6;
509#else 569#else
510 usage4 (_("IPv6 support not available")); 570 usage4(_("IPv6 support not available"));
511#endif 571#endif
512 break; 572 break;
513 case '?': 573 case '?':
514 /* print short usage statement if args not parsable */ 574 /* print short usage statement if args not parsable */
515 usage5 (); 575 usage5();
516 break; 576 break;
517 } 577 }
518 } 578 }
519 579
520 if(server_address == NULL){ 580 if (result.config.server_address == NULL) {
521 usage4(_("Hostname was not supplied")); 581 usage4(_("Hostname was not supplied"));
522 } 582 }
523 583
524 return 0; 584 set_thresholds(&result.config.offset_thresholds, result.config.owarn, result.config.ocrit);
525} 585 set_thresholds(&result.config.jitter_thresholds, result.config.jwarn, result.config.jcrit);
586 set_thresholds(&result.config.stratum_thresholds, result.config.swarn, result.config.scrit);
587 set_thresholds(&result.config.truechimer_thresholds, result.config.twarn, result.config.tcrit);
526 588
527char *perfd_offset (double offset) 589 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} 590}
534 591
535char *perfd_jitter (double jitter) 592char *perfd_offset(double offset, thresholds *offset_thresholds) {
536{ 593 return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true,
537 return fperfdata ("jitter", jitter, "", 594 offset_thresholds->critical->end, false, 0, false, 0);
538 do_jitter, jitter_thresholds->warning->end,
539 do_jitter, jitter_thresholds->critical->end,
540 true, 0, false, 0);
541} 595}
542 596
543char *perfd_stratum (int stratum) 597char *perfd_jitter(double jitter, bool do_jitter, thresholds *jitter_thresholds) {
544{ 598 return fperfdata("jitter", jitter, "", do_jitter, jitter_thresholds->warning->end, do_jitter,
545 return perfdata ("stratum", stratum, "", 599 jitter_thresholds->critical->end, true, 0, false, 0);
546 do_stratum, (int)stratum_thresholds->warning->end,
547 do_stratum, (int)stratum_thresholds->critical->end,
548 true, 0, true, 16);
549} 600}
550 601
551char *perfd_truechimers (int num_truechimers) 602char *perfd_stratum(int stratum, bool do_stratum, thresholds *stratum_thresholds) {
552{ 603 return perfdata("stratum", stratum, "", do_stratum, (int)stratum_thresholds->warning->end,
553 return perfdata ("truechimers", num_truechimers, "", 604 do_stratum, (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} 605}
558 606
559int main(int argc, char *argv[]){ 607char *perfd_truechimers(int num_truechimers, const bool do_truechimers,
560 int result, offset_result, stratum, num_truechimers; 608 thresholds *truechimer_thresholds) {
561 double offset=0, jitter=0; 609 return perfdata("truechimers", num_truechimers, "", do_truechimers,
562 char *result_line, *perfdata_line; 610 (int)truechimer_thresholds->warning->end, do_truechimers,
611 (int)truechimer_thresholds->critical->end, true, 0, false, 0);
612}
563 613
564 setlocale (LC_ALL, ""); 614int main(int argc, char *argv[]) {
565 bindtextdomain (PACKAGE, LOCALEDIR); 615 setlocale(LC_ALL, "");
566 textdomain (PACKAGE); 616 bindtextdomain(PACKAGE, LOCALEDIR);
617 textdomain(PACKAGE);
567 618
568 /* Parse extra opts if any */ 619 /* Parse extra opts if any */
569 argv=np_extra_opts (&argc, argv, progname); 620 argv = np_extra_opts(&argc, argv, progname);
570 621
571 if (process_arguments (argc, argv) == ERROR) 622 check_ntp_peer_config_wrapper tmp_config = process_arguments(argc, argv);
572 usage4 (_("Could not parse arguments"));
573 623
574 set_thresholds(&offset_thresholds, owarn, ocrit); 624 if (tmp_config.errorcode == ERROR) {
575 set_thresholds(&jitter_thresholds, jwarn, jcrit); 625 usage4(_("Could not parse arguments"));
576 set_thresholds(&stratum_thresholds, swarn, scrit); 626 }
577 set_thresholds(&truechimer_thresholds, twarn, tcrit); 627
628 const check_ntp_peer_config config = tmp_config.config;
578 629
579 /* initialize alarm signal handling */ 630 /* initialize alarm signal handling */
580 signal (SIGALRM, socket_timeout_alarm_handler); 631 signal(SIGALRM, socket_timeout_alarm_handler);
581 632
582 /* set socket timeout */ 633 /* set socket timeout */
583 alarm (socket_timeout); 634 alarm(socket_timeout);
584 635
585 /* This returns either OK or WARNING (See comment preceding ntp_request) */ 636 /* This returns either OK or WARNING (See comment preceding ntp_request) */
586 result = ntp_request(&offset, &offset_result, &jitter, &stratum, &num_truechimers); 637 ntp_request_result ntp_res = ntp_request(config);
638 mp_state_enum result = STATE_UNKNOWN;
587 639
588 if(offset_result == STATE_UNKNOWN) { 640 if (ntp_res.offset_result == STATE_UNKNOWN) {
589 /* if there's no sync peer (this overrides ntp_request output): */ 641 /* if there's no sync peer (this overrides ntp_request output): */
590 result = (quiet ? STATE_UNKNOWN : STATE_CRITICAL); 642 result = (config.quiet ? STATE_UNKNOWN : STATE_CRITICAL);
591 } else { 643 } else {
592 /* Be quiet if there's no candidates either */ 644 /* Be quiet if there's no candidates either */
593 if (quiet && result == STATE_WARNING) 645 if (config.quiet && result == STATE_WARNING) {
594 result = STATE_UNKNOWN; 646 result = STATE_UNKNOWN;
595 result = max_state_alt(result, get_status(fabs(offset), offset_thresholds)); 647 }
648 result = max_state_alt(result, get_status(fabs(ntp_res.offset), config.offset_thresholds));
596 } 649 }
597 650
598 int oresult = result; 651 mp_state_enum oresult = result;
599 652 mp_state_enum tresult = STATE_UNKNOWN;
600 653
601 int tresult = STATE_UNKNOWN; 654 if (config.do_truechimers) {
602 655 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); 656 result = max_state_alt(result, tresult);
606 } 657 }
607 658
659 mp_state_enum sresult = STATE_UNKNOWN;
608 660
609 int sresult = STATE_UNKNOWN; 661 if (config.do_stratum) {
610 662 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); 663 result = max_state_alt(result, sresult);
614 } 664 }
615 665
666 mp_state_enum jresult = STATE_UNKNOWN;
616 667
617 int jresult = STATE_UNKNOWN; 668 if (config.do_jitter) {
618 669 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); 670 result = max_state_alt(result, jresult);
622 } 671 }
623 672
673 char *result_line;
624 switch (result) { 674 switch (result) {
625 case STATE_CRITICAL : 675 case STATE_CRITICAL:
626 xasprintf(&result_line, _("NTP CRITICAL:")); 676 xasprintf(&result_line, _("NTP CRITICAL:"));
627 break; 677 break;
628 case STATE_WARNING : 678 case STATE_WARNING:
629 xasprintf(&result_line, _("NTP WARNING:")); 679 xasprintf(&result_line, _("NTP WARNING:"));
630 break; 680 break;
631 case STATE_OK : 681 case STATE_OK:
632 xasprintf(&result_line, _("NTP OK:")); 682 xasprintf(&result_line, _("NTP OK:"));
633 break; 683 break;
634 default : 684 default:
635 xasprintf(&result_line, _("NTP UNKNOWN:")); 685 xasprintf(&result_line, _("NTP UNKNOWN:"));
636 break; 686 break;
637 } 687 }
638 if(!syncsource_found) 688
689 if (!syncsource_found) {
639 xasprintf(&result_line, "%s %s,", result_line, _("Server not synchronized")); 690 xasprintf(&result_line, "%s %s,", result_line, _("Server not synchronized"));
640 else if(li_alarm) 691 } else if (li_alarm) {
641 xasprintf(&result_line, "%s %s,", result_line, _("Server has the LI_ALARM bit set")); 692 xasprintf(&result_line, "%s %s,", result_line, _("Server has the LI_ALARM bit set"));
693 }
642 694
643 if(offset_result == STATE_UNKNOWN){ 695 char *perfdata_line;
696 if (ntp_res.offset_result == STATE_UNKNOWN) {
644 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown")); 697 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
645 xasprintf(&perfdata_line, ""); 698 xasprintf(&perfdata_line, "");
646 } else if (oresult == STATE_WARNING) { 699 } else if (oresult == STATE_WARNING) {
647 xasprintf(&result_line, "%s %s %.10g secs (WARNING)", result_line, _("Offset"), offset); 700 xasprintf(&result_line, "%s %s %.10g secs (WARNING)", result_line, _("Offset"),
701 ntp_res.offset);
648 } else if (oresult == STATE_CRITICAL) { 702 } else if (oresult == STATE_CRITICAL) {
649 xasprintf(&result_line, "%s %s %.10g secs (CRITICAL)", result_line, _("Offset"), offset); 703 xasprintf(&result_line, "%s %s %.10g secs (CRITICAL)", result_line, _("Offset"),
704 ntp_res.offset);
650 } else { 705 } else {
651 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset); 706 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), ntp_res.offset);
652 } 707 }
653 xasprintf(&perfdata_line, "%s", perfd_offset(offset)); 708 xasprintf(&perfdata_line, "%s", perfd_offset(ntp_res.offset, config.offset_thresholds));
654 709
655 if (do_jitter) { 710 if (config.do_jitter) {
656 if (jresult == STATE_WARNING) { 711 if (jresult == STATE_WARNING) {
657 xasprintf(&result_line, "%s, jitter=%f (WARNING)", result_line, jitter); 712 xasprintf(&result_line, "%s, jitter=%f (WARNING)", result_line, ntp_res.jitter);
658 } else if (jresult == STATE_CRITICAL) { 713 } else if (jresult == STATE_CRITICAL) {
659 xasprintf(&result_line, "%s, jitter=%f (CRITICAL)", result_line, jitter); 714 xasprintf(&result_line, "%s, jitter=%f (CRITICAL)", result_line, ntp_res.jitter);
660 } else { 715 } else {
661 xasprintf(&result_line, "%s, jitter=%f", result_line, jitter); 716 xasprintf(&result_line, "%s, jitter=%f", result_line, ntp_res.jitter);
662 } 717 }
663 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_jitter(jitter)); 718 xasprintf(&perfdata_line, "%s %s", perfdata_line,
719 perfd_jitter(ntp_res.jitter, config.do_jitter, config.jitter_thresholds));
664 } 720 }
665 if (do_stratum) { 721
722 if (config.do_stratum) {
666 if (sresult == STATE_WARNING) { 723 if (sresult == STATE_WARNING) {
667 xasprintf(&result_line, "%s, stratum=%i (WARNING)", result_line, stratum); 724 xasprintf(&result_line, "%s, stratum=%li (WARNING)", result_line, ntp_res.stratum);
668 } else if (sresult == STATE_CRITICAL) { 725 } else if (sresult == STATE_CRITICAL) {
669 xasprintf(&result_line, "%s, stratum=%i (CRITICAL)", result_line, stratum); 726 xasprintf(&result_line, "%s, stratum=%li (CRITICAL)", result_line, ntp_res.stratum);
670 } else { 727 } else {
671 xasprintf(&result_line, "%s, stratum=%i", result_line, stratum); 728 xasprintf(&result_line, "%s, stratum=%li", result_line, ntp_res.stratum);
672 } 729 }
673 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_stratum(stratum)); 730 xasprintf(&perfdata_line, "%s %s", perfdata_line,
731 perfd_stratum(ntp_res.stratum, config.do_stratum, config.stratum_thresholds));
674 } 732 }
675 if (do_truechimers) { 733
734 if (config.do_truechimers) {
676 if (tresult == STATE_WARNING) { 735 if (tresult == STATE_WARNING) {
677 xasprintf(&result_line, "%s, truechimers=%i (WARNING)", result_line, num_truechimers); 736 xasprintf(&result_line, "%s, truechimers=%i (WARNING)", result_line,
737 ntp_res.num_truechimers);
678 } else if (tresult == STATE_CRITICAL) { 738 } else if (tresult == STATE_CRITICAL) {
679 xasprintf(&result_line, "%s, truechimers=%i (CRITICAL)", result_line, num_truechimers); 739 xasprintf(&result_line, "%s, truechimers=%i (CRITICAL)", result_line,
740 ntp_res.num_truechimers);
680 } else { 741 } else {
681 xasprintf(&result_line, "%s, truechimers=%i", result_line, num_truechimers); 742 xasprintf(&result_line, "%s, truechimers=%i", result_line, ntp_res.num_truechimers);
682 } 743 }
683 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_truechimers(num_truechimers)); 744 xasprintf(&perfdata_line, "%s %s", perfdata_line,
745 perfd_truechimers(ntp_res.num_truechimers, config.do_truechimers,
746 config.truechimer_thresholds));
684 } 747 }
748
685 printf("%s|%s\n", result_line, perfdata_line); 749 printf("%s|%s\n", result_line, perfdata_line);
686 750
687 if(server_address!=NULL) free(server_address); 751 if (config.server_address != NULL) {
688 return result; 752 free(config.server_address);
753 }
754
755 exit(result);
689} 756}
690 757
691void print_help(void){ 758void print_help(void) {
692 print_revision(progname, NP_VERSION); 759 print_revision(progname, NP_VERSION);
693 760
694 printf ("Copyright (c) 2006 Sean Finney\n"); 761 printf("Copyright (c) 2006 Sean Finney\n");
695 printf (COPYRIGHT, copyright, email); 762 printf(COPYRIGHT, copyright, email);
696 763
697 printf ("%s\n", _("This plugin checks the selected ntp server")); 764 printf("%s\n", _("This plugin checks the selected ntp server"));
698 765
699 printf ("\n\n"); 766 printf("\n\n");
700 767
701 print_usage(); 768 print_usage();
702 printf (UT_HELP_VRSN); 769 printf(UT_HELP_VRSN);
703 printf (UT_EXTRA_OPTS); 770 printf(UT_EXTRA_OPTS);
704 printf (UT_IPv46); 771 printf(UT_IPv46);
705 printf (UT_HOST_PORT, 'p', "123"); 772 printf(UT_HOST_PORT, 'p', "123");
706 printf (" %s\n", "-q, --quiet"); 773 printf(" %s\n", "-q, --quiet");
707 printf (" %s\n", _("Returns UNKNOWN instead of CRITICAL or WARNING if server isn't synchronized")); 774 printf(" %s\n",
708 printf (" %s\n", "-w, --warning=THRESHOLD"); 775 _("Returns UNKNOWN instead of CRITICAL or WARNING if server isn't synchronized"));
709 printf (" %s\n", _("Offset to result in warning status (seconds)")); 776 printf(" %s\n", "-w, --warning=THRESHOLD");
710 printf (" %s\n", "-c, --critical=THRESHOLD"); 777 printf(" %s\n", _("Offset to result in warning status (seconds)"));
711 printf (" %s\n", _("Offset to result in critical status (seconds)")); 778 printf(" %s\n", "-c, --critical=THRESHOLD");
712 printf (" %s\n", "-W, --swarn=THRESHOLD"); 779 printf(" %s\n", _("Offset to result in critical status (seconds)"));
713 printf (" %s\n", _("Warning threshold for stratum of server's synchronization peer")); 780 printf(" %s\n", "-W, --swarn=THRESHOLD");
714 printf (" %s\n", "-C, --scrit=THRESHOLD"); 781 printf(" %s\n", _("Warning threshold for stratum of server's synchronization peer"));
715 printf (" %s\n", _("Critical threshold for stratum of server's synchronization peer")); 782 printf(" %s\n", "-C, --scrit=THRESHOLD");
716 printf (" %s\n", "-j, --jwarn=THRESHOLD"); 783 printf(" %s\n", _("Critical threshold for stratum of server's synchronization peer"));
717 printf (" %s\n", _("Warning threshold for jitter")); 784 printf(" %s\n", "-j, --jwarn=THRESHOLD");
718 printf (" %s\n", "-k, --jcrit=THRESHOLD"); 785 printf(" %s\n", _("Warning threshold for jitter"));
719 printf (" %s\n", _("Critical threshold for jitter")); 786 printf(" %s\n", "-k, --jcrit=THRESHOLD");
720 printf (" %s\n", "-m, --twarn=THRESHOLD"); 787 printf(" %s\n", _("Critical threshold for jitter"));
721 printf (" %s\n", _("Warning threshold for number of usable time sources (\"truechimers\")")); 788 printf(" %s\n", "-m, --twarn=THRESHOLD");
722 printf (" %s\n", "-n, --tcrit=THRESHOLD"); 789 printf(" %s\n", _("Warning threshold for number of usable time sources (\"truechimers\")"));
723 printf (" %s\n", _("Critical threshold for number of usable time sources (\"truechimers\")")); 790 printf(" %s\n", "-n, --tcrit=THRESHOLD");
724 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 791 printf(" %s\n", _("Critical threshold for number of usable time sources (\"truechimers\")"));
725 printf (UT_VERBOSE); 792 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
793 printf(UT_VERBOSE);
726 794
727 printf("\n"); 795 printf("\n");
728 printf("%s\n", _("This plugin checks an NTP server independent of any commandline")); 796 printf("%s\n", _("This plugin checks an NTP server independent of any commandline"));
@@ -741,7 +809,8 @@ void print_help(void){
741 printf(" %s\n", _("Simple NTP server check:")); 809 printf(" %s\n", _("Simple NTP server check:"));
742 printf(" %s\n", ("./check_ntp_peer -H ntpserv -w 0.5 -c 1")); 810 printf(" %s\n", ("./check_ntp_peer -H ntpserv -w 0.5 -c 1"));
743 printf("\n"); 811 printf("\n");
744 printf(" %s\n", _("Check jitter too, avoiding critical notifications if jitter isn't available")); 812 printf(" %s\n",
813 _("Check jitter too, avoiding critical notifications if jitter isn't available"));
745 printf(" %s\n", _("(See Notes above for more details on thresholds formats):")); 814 printf(" %s\n", _("(See Notes above for more details on thresholds formats):"));
746 printf(" %s\n", ("./check_ntp_peer -H ntpserv -w 0.5 -c 1 -j -1:100 -k -1:200")); 815 printf(" %s\n", ("./check_ntp_peer -H ntpserv -w 0.5 -c 1 -j -1:100 -k -1:200"));
747 printf("\n"); 816 printf("\n");
@@ -751,13 +820,11 @@ void print_help(void){
751 printf(" %s\n", _("Check only stratum:")); 820 printf(" %s\n", _("Check only stratum:"));
752 printf(" %s\n", ("./check_ntp_peer -H ntpserv -W 4 -C 6")); 821 printf(" %s\n", ("./check_ntp_peer -H ntpserv -W 4 -C 6"));
753 822
754 printf (UT_SUPPORT); 823 printf(UT_SUPPORT);
755} 824}
756 825
757void 826void print_usage(void) {
758print_usage(void) 827 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); 828 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"); 829 printf(" [-j <warn>] [-k <crit>] [-v verbose]\n");
763} 830}
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..ad69b804 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,139 @@ 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) + \
155 (.00000001*(0.5+(double)(ntohl(R32(n))/42.94967296))):\ 168 (.00000001 * (0.5 + (double)(ntohl(R32(n)) / 42.94967296))) \
156 0) 169 : 0)
157 170
158/* convert a struct timeval to a double */ 171/* convert a struct timeval to a double */
159#define TVasDOUBLE(x) (double)(x.tv_sec+(0.000001*x.tv_usec)) 172#define TVasDOUBLE(x) (double)(x.tv_sec + (0.000001 * x.tv_usec))
160 173
161/* convert an ntp 64-bit fp number to a struct timeval */ 174/* convert an ntp 64-bit fp number to a struct timeval */
162#define NTP64toTV(n,t) \ 175#define NTP64toTV(n, t) \
163 do{ if(!n) t.tv_sec = t.tv_usec = 0; \ 176 do { \
164 else { \ 177 if (!n) \
165 t.tv_sec=ntohl(L32(n))-EPOCHDIFF; \ 178 t.tv_sec = t.tv_usec = 0; \
166 t.tv_usec=(int)(0.5+(double)(ntohl(R32(n))/4294.967296)); \ 179 else { \
167 } \ 180 t.tv_sec = ntohl(L32(n)) - EPOCHDIFF; \
168 }while(0) 181 t.tv_usec = (int)(0.5 + (double)(ntohl(R32(n)) / 4294.967296)); \
182 } \
183 } while (0)
169 184
170/* convert a struct timeval to an ntp 64-bit fp number */ 185/* convert a struct timeval to an ntp 64-bit fp number */
171#define TVtoNTP64(t,n) \ 186#define TVtoNTP64(t, n) \
172 do{ if(!t.tv_usec && !t.tv_sec) n=0x0UL; \ 187 do { \
173 else { \ 188 if (!t.tv_usec && !t.tv_sec) \
174 L32(n)=htonl(t.tv_sec + EPOCHDIFF); \ 189 n = 0x0UL; \
175 R32(n)=htonl((uint64_t)((4294.967296*t.tv_usec)+.5)); \ 190 else { \
176 } \ 191 L32(n) = htonl(t.tv_sec + EPOCHDIFF); \
177 } while(0) 192 R32(n) = htonl((uint64_t)((4294.967296 * t.tv_usec) + .5)); \
193 } \
194 } while (0)
178 195
179/* NTP control message header is 12 bytes, plus any data in the data 196/* 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. 197 * field, plus null padding to the nearest 32-bit boundary per rfc.
181 */ 198 */
182#define SIZEOF_NTPCM(m) (12+ntohs(m.count)+((m.count)?4-(ntohs(m.count)%4):0)) 199#define SIZEOF_NTPCM(m) (12 + ntohs(m.count) + ((m.count) ? 4 - (ntohs(m.count) % 4) : 0))
183 200
184/* finally, a little helper or two for debugging: */ 201/* finally, a little helper or two for debugging: */
185#define DBG(x) do{if(verbose>1){ x; }}while(0); 202#define DBG(x) \
186#define PRINTSOCKADDR(x) \ 203 do { \
187 do{ \ 204 if (verbose > 1) { \
188 printf("%u.%u.%u.%u", (x>>24)&0xff, (x>>16)&0xff, (x>>8)&0xff, x&0xff);\ 205 x; \
189 }while(0); 206 } \
207 } while (0);
208#define PRINTSOCKADDR(x) \
209 do { \
210 printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \
211 } while (0);
190 212
191/* calculate the offset of the local clock */ 213/* calculate the offset of the local clock */
192static inline double calc_offset(const ntp_message *m, const struct timeval *t){ 214static inline double calc_offset(const ntp_message *message, const struct timeval *time_value) {
193 double client_tx, peer_rx, peer_tx, client_rx; 215 double client_tx = NTP64asDOUBLE(message->origts);
194 client_tx = NTP64asDOUBLE(m->origts); 216 double peer_rx = NTP64asDOUBLE(message->rxts);
195 peer_rx = NTP64asDOUBLE(m->rxts); 217 double peer_tx = NTP64asDOUBLE(message->txts);
196 peer_tx = NTP64asDOUBLE(m->txts); 218 double client_rx = TVasDOUBLE((*time_value));
197 client_rx=TVasDOUBLE((*t)); 219 return (((peer_tx - client_rx) + (peer_rx - client_tx)) / 2);
198 return (.5*((peer_tx-client_rx)+(peer_rx-client_tx)));
199} 220}
200 221
201/* print out a ntp packet in human readable/debuggable format */ 222/* print out a ntp packet in human readable/debuggable format */
202void print_ntp_message(const ntp_message *p){ 223void print_ntp_message(const ntp_message *message) {
203 struct timeval ref, orig, rx, tx; 224 struct timeval ref;
225 struct timeval orig;
204 226
205 NTP64toTV(p->refts,ref); 227 NTP64toTV(message->refts, ref);
206 NTP64toTV(p->origts,orig); 228 NTP64toTV(message->origts, orig);
207 NTP64toTV(p->rxts,rx);
208 NTP64toTV(p->txts,tx);
209 229
210 printf("packet contents:\n"); 230 printf("packet contents:\n");
211 printf("\tflags: 0x%.2x\n", p->flags); 231 printf("\tflags: 0x%.2x\n", message->flags);
212 printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags&LI_MASK); 232 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); 233 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); 234 printf("\t mode=%d (0x%.2x)\n", MODE(message->flags), message->flags & MODE_MASK);
215 printf("\tstratum = %d\n", p->stratum); 235 printf("\tstratum = %d\n", message->stratum);
216 printf("\tpoll = %g\n", pow(2, p->poll)); 236 printf("\tpoll = %g\n", pow(2, message->poll));
217 printf("\tprecision = %g\n", pow(2, p->precision)); 237 printf("\tprecision = %g\n", pow(2, message->precision));
218 printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(p->rtdelay)); 238 printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(message->rtdelay));
219 printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(p->rtdisp)); 239 printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(message->rtdisp));
220 printf("\trefid = %x\n", p->refid); 240 printf("\trefid = %x\n", message->refid);
221 printf("\trefts = %-.16g\n", NTP64asDOUBLE(p->refts)); 241 printf("\trefts = %-.16g\n", NTP64asDOUBLE(message->refts));
222 printf("\torigts = %-.16g\n", NTP64asDOUBLE(p->origts)); 242 printf("\torigts = %-.16g\n", NTP64asDOUBLE(message->origts));
223 printf("\trxts = %-.16g\n", NTP64asDOUBLE(p->rxts)); 243 printf("\trxts = %-.16g\n", NTP64asDOUBLE(message->rxts));
224 printf("\ttxts = %-.16g\n", NTP64asDOUBLE(p->txts)); 244 printf("\ttxts = %-.16g\n", NTP64asDOUBLE(message->txts));
225} 245}
226 246
227void setup_request(ntp_message *p){ 247void setup_request(ntp_message *message) {
228 struct timeval t; 248 memset(message, 0, sizeof(ntp_message));
229 249 LI_SET(message->flags, LI_ALARM);
230 memset(p, 0, sizeof(ntp_message)); 250 VN_SET(message->flags, 4);
231 LI_SET(p->flags, LI_ALARM); 251 MODE_SET(message->flags, MODE_CLIENT);
232 VN_SET(p->flags, 4); 252 message->poll = 4;
233 MODE_SET(p->flags, MODE_CLIENT); 253 message->precision = (int8_t)0xfa;
234 p->poll=4; 254 L16(message->rtdelay) = htons(1);
235 p->precision=(int8_t)0xfa; 255 L16(message->rtdisp) = htons(1);
236 L16(p->rtdelay)=htons(1);
237 L16(p->rtdisp)=htons(1);
238 256
257 struct timeval t;
239 gettimeofday(&t, NULL); 258 gettimeofday(&t, NULL);
240 TVtoNTP64(t,p->txts); 259 TVtoNTP64(t, message->txts);
241} 260}
242 261
243/* select the "best" server from a list of servers, and return its index. 262/* 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 263 * this is done by filtering servers based on stratum, dispersion, and
245 * finally round-trip delay. */ 264 * finally round-trip delay. */
246int best_offset_server(const ntp_server_results *slist, int nservers){ 265int best_offset_server(const ntp_server_results *slist, int nservers) {
247 int cserver=0, best_server=-1; 266 int best_server = -1;
248 267
249 /* for each server */ 268 /* for each server */
250 for(cserver=0; cserver<nservers; cserver++){ 269 for (int cserver = 0; cserver < nservers; cserver++) {
251 /* We don't want any servers that fails these tests */ 270 /* We don't want any servers that fails these tests */
252 /* Sort out servers that didn't respond or responede with a 0 stratum; 271 /* 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 272 * stratum 0 is for reference clocks so no NTP server should ever report
254 * a stratum 0 */ 273 * a stratum 0 */
255 if ( slist[cserver].stratum == 0){ 274 if (slist[cserver].stratum == 0) {
256 if (verbose) printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum); 275 if (verbose) {
276 printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum);
277 }
257 continue; 278 continue;
258 } 279 }
259 /* Sort out servers with error flags */ 280 /* Sort out servers with error flags */
260 if ( LI(slist[cserver].flags) == LI_ALARM ){ 281 if (LI(slist[cserver].flags) == LI_ALARM) {
261 if (verbose) printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags)); 282 if (verbose) {
283 printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags));
284 }
262 continue; 285 continue;
263 } 286 }
264 287
@@ -272,13 +295,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 */ 295 /* compare the server to the best one we've seen so far */
273 /* does it have an equal or better stratum? */ 296 /* does it have an equal or better stratum? */
274 DBG(printf("comparing peer %d with peer %d\n", cserver, best_server)); 297 DBG(printf("comparing peer %d with peer %d\n", cserver, best_server));
275 if(slist[cserver].stratum <= slist[best_server].stratum){ 298 if (slist[cserver].stratum <= slist[best_server].stratum) {
276 DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server)); 299 DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server));
277 /* does it have an equal or better dispersion? */ 300 /* does it have an equal or better dispersion? */
278 if(slist[cserver].rtdisp <= slist[best_server].rtdisp){ 301 if (slist[cserver].rtdisp <= slist[best_server].rtdisp) {
279 DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server)); 302 DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server));
280 /* does it have a better rtdelay? */ 303 /* does it have a better rtdelay? */
281 if(slist[cserver].rtdelay < slist[best_server].rtdelay){ 304 if (slist[cserver].rtdelay < slist[best_server].rtdelay) {
282 DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server)); 305 DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server));
283 best_server = cserver; 306 best_server = cserver;
284 DBG(printf("peer %d is now our best candidate\n", best_server)); 307 DBG(printf("peer %d is now our best candidate\n", best_server));
@@ -287,13 +310,12 @@ int best_offset_server(const ntp_server_results *slist, int nservers){
287 } 310 }
288 } 311 }
289 312
290 if(best_server >= 0) { 313 if (best_server >= 0) {
291 DBG(printf("best server selected: peer %d\n", best_server)); 314 DBG(printf("best server selected: peer %d\n", best_server));
292 return best_server; 315 return best_server;
293 } else {
294 DBG(printf("no peers meeting synchronization criteria :(\n"));
295 return -1;
296 } 316 }
317 DBG(printf("no peers meeting synchronization criteria :(\n"));
318 return -1;
297} 319}
298 320
299/* do everything we need to get the total average offset 321/* do everything we need to get the total average offset
@@ -301,178 +323,209 @@ int best_offset_server(const ntp_server_results *slist, int nservers){
301 * we don't waste time sitting around waiting for single packets. 323 * we don't waste time sitting around waiting for single packets.
302 * - we also "manually" handle resolving host names and connecting, because 324 * - 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 :( */ 325 * we have to do it in a way that our lazy macros don't handle currently :( */
304double offset_request(const char *host, int *status){ 326double 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 */ 327 /* setup hints to only return results from getaddrinfo that we'd like */
328 struct addrinfo hints;
316 memset(&hints, 0, sizeof(struct addrinfo)); 329 memset(&hints, 0, sizeof(struct addrinfo));
317 hints.ai_family = address_family; 330 hints.ai_family = address_family;
318 hints.ai_protocol = IPPROTO_UDP; 331 hints.ai_protocol = IPPROTO_UDP;
319 hints.ai_socktype = SOCK_DGRAM; 332 hints.ai_socktype = SOCK_DGRAM;
320 333
321 /* fill in ai with the list of hosts resolved by the host name */ 334 /* fill in ai with the list of hosts resolved by the host name */
322 ga_result = getaddrinfo(host, port, &hints, &ai); 335 struct addrinfo *addresses = NULL;
323 if(ga_result!=0){ 336 int ga_result = getaddrinfo(host, port, &hints, &addresses);
324 die(STATE_UNKNOWN, "error getting address for %s: %s\n", 337 if (ga_result != 0) {
325 host, gai_strerror(ga_result)); 338 die(STATE_UNKNOWN, "error getting address for %s: %s\n", host, gai_strerror(ga_result));
326 } 339 }
327 340
328 /* count the number of returned hosts, and allocate stuff accordingly */ 341 /* 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++; } 342 size_t num_hosts = 0;
330 req=(ntp_message*)malloc(sizeof(ntp_message)*num_hosts); 343 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"); 344 num_hosts++;
332 socklist=(int*)malloc(sizeof(int)*num_hosts); 345 }
333 if(socklist==NULL) die(STATE_UNKNOWN, "can not allocate socket array"); 346
334 ufds=(struct pollfd*)malloc(sizeof(struct pollfd)*num_hosts); 347 ntp_message *req = (ntp_message *)malloc(sizeof(ntp_message) * num_hosts);
335 if(ufds==NULL) die(STATE_UNKNOWN, "can not allocate socket array"); 348
336 servers=(ntp_server_results*)malloc(sizeof(ntp_server_results)*num_hosts); 349 if (req == NULL) {
337 if(servers==NULL) die(STATE_UNKNOWN, "can not allocate server array"); 350 die(STATE_UNKNOWN, "can not allocate ntp message array");
338 memset(servers, 0, sizeof(ntp_server_results)*num_hosts); 351 }
339 DBG(printf("Found %d peers to check\n", num_hosts)); 352 int *socklist = (int *)malloc(sizeof(int) * num_hosts);
353
354 if (socklist == NULL) {
355 die(STATE_UNKNOWN, "can not allocate socket array");
356 }
357
358 struct pollfd *ufds = (struct pollfd *)malloc(sizeof(struct pollfd) * num_hosts);
359 if (ufds == NULL) {
360 die(STATE_UNKNOWN, "can not allocate socket array");
361 }
362
363 ntp_server_results *servers =
364 (ntp_server_results *)malloc(sizeof(ntp_server_results) * num_hosts);
365 if (servers == NULL) {
366 die(STATE_UNKNOWN, "can not allocate server array");
367 }
368 memset(servers, 0, sizeof(ntp_server_results) * num_hosts);
369 DBG(printf("Found %zu peers to check\n", num_hosts));
340 370
341 /* setup each socket for writing, and the corresponding struct pollfd */ 371 /* setup each socket for writing, and the corresponding struct pollfd */
342 ai_tmp=ai; 372 struct addrinfo *ai_tmp = addresses;
343 for(i=0;ai_tmp;i++){ 373 for (int i = 0; ai_tmp; i++) {
344 socklist[i]=socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP); 374 socklist[i] = socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP);
345 if(socklist[i] == -1) { 375 if (socklist[i] == -1) {
346 perror(NULL); 376 perror(NULL);
347 die(STATE_UNKNOWN, "can not create new socket"); 377 die(STATE_UNKNOWN, "can not create new socket");
348 } 378 }
349 if(connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)){ 379 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 380 /* 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 381 answering in time. This also would break for dual ipv4/6 stacked
352 ntp servers when the client only supports on of them. 382 ntp servers when the client only supports on of them.
353 */ 383 */
354 DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno))); 384 DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno)));
355 } else { 385 } else {
356 ufds[i].fd=socklist[i]; 386 ufds[i].fd = socklist[i];
357 ufds[i].events=POLLIN; 387 ufds[i].events = POLLIN;
358 ufds[i].revents=0; 388 ufds[i].revents = 0;
359 } 389 }
360 ai_tmp = ai_tmp->ai_next; 390 ai_tmp = ai_tmp->ai_next;
361 } 391 }
362 392
363 /* now do AVG_NUM checks to each host. We stop before timeout/2 seconds 393 /* 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. */ 394 * have passed in order to ensure post-processing and jitter time. */
365 now_time=start_ts=time(NULL); 395 time_t start_ts = 0;
366 while(servers_completed<num_hosts && now_time-start_ts <= socket_timeout/2){ 396 time_t now_time = 0;
397 now_time = start_ts = time(NULL);
398 size_t servers_completed = 0;
399 bool one_read = false;
400 while (servers_completed < num_hosts && now_time - start_ts <= socket_timeout / 2) {
367 /* loop through each server and find each one which hasn't 401 /* loop through each server and find each one which hasn't
368 * been touched in the past second or so and is still lacking 402 * been touched in the past second or so and is still lacking
369 * some responses. For each of these servers, send a new request, 403 * some responses. For each of these servers, send a new request,
370 * and update the "waiting" timestamp with the current time. */ 404 * and update the "waiting" timestamp with the current time. */
371 now_time=time(NULL); 405 now_time = time(NULL);
372 406
373 for(i=0; i<num_hosts; i++){ 407 for (size_t i = 0; i < num_hosts; i++) {
374 if(servers[i].waiting<now_time && servers[i].num_responses<AVG_NUM){ 408 if (servers[i].waiting < now_time && servers[i].num_responses < AVG_NUM) {
375 if(verbose && servers[i].waiting != 0) printf("re-"); 409 if (verbose && servers[i].waiting != 0) {
376 if(verbose) printf("sending request to peer %d\n", i); 410 printf("re-");
411 }
412 if (verbose) {
413 printf("sending request to peer %zu\n", i);
414 }
377 setup_request(&req[i]); 415 setup_request(&req[i]);
378 write(socklist[i], &req[i], sizeof(ntp_message)); 416 write(socklist[i], &req[i], sizeof(ntp_message));
379 servers[i].waiting=now_time; 417 servers[i].waiting = now_time;
380 break; 418 break;
381 } 419 }
382 } 420 }
383 421
384 /* quickly poll for any sockets with pending data */ 422 /* quickly poll for any sockets with pending data */
385 servers_readable=poll(ufds, num_hosts, 100); 423 int servers_readable = poll(ufds, num_hosts, 100);
386 if(servers_readable==-1){ 424 if (servers_readable == -1) {
387 perror("polling ntp sockets"); 425 perror("polling ntp sockets");
388 die(STATE_UNKNOWN, "communication errors"); 426 die(STATE_UNKNOWN, "communication errors");
389 } 427 }
390 428
391 /* read from any sockets with pending data */ 429 /* read from any sockets with pending data */
392 for(i=0; servers_readable && i<num_hosts; i++){ 430 for (size_t i = 0; servers_readable && i < num_hosts; i++) {
393 if(ufds[i].revents&POLLIN && servers[i].num_responses < AVG_NUM){ 431 if (ufds[i].revents & POLLIN && servers[i].num_responses < AVG_NUM) {
394 if(verbose) { 432 if (verbose) {
395 printf("response from peer %d: ", i); 433 printf("response from peer %zu: ", i);
396 } 434 }
397 435
398 read(ufds[i].fd, &req[i], sizeof(ntp_message)); 436 read(ufds[i].fd, &req[i], sizeof(ntp_message));
437
438 struct timeval recv_time;
399 gettimeofday(&recv_time, NULL); 439 gettimeofday(&recv_time, NULL);
400 DBG(print_ntp_message(&req[i])); 440 DBG(print_ntp_message(&req[i]));
401 respnum=servers[i].num_responses++; 441 int respnum = servers[i].num_responses++;
402 servers[i].offset[respnum]=calc_offset(&req[i], &recv_time)+time_offset; 442 servers[i].offset[respnum] = calc_offset(&req[i], &recv_time) + time_offset;
403 if(verbose) { 443 if (verbose) {
404 printf("offset %.10g\n", servers[i].offset[respnum]); 444 printf("offset %.10g\n", servers[i].offset[respnum]);
405 } 445 }
406 servers[i].stratum=req[i].stratum; 446 servers[i].stratum = req[i].stratum;
407 servers[i].rtdisp=NTP32asDOUBLE(req[i].rtdisp); 447 servers[i].rtdisp = NTP32asDOUBLE(req[i].rtdisp);
408 servers[i].rtdelay=NTP32asDOUBLE(req[i].rtdelay); 448 servers[i].rtdelay = NTP32asDOUBLE(req[i].rtdelay);
409 servers[i].waiting=0; 449 servers[i].waiting = 0;
410 servers[i].flags=req[i].flags; 450 servers[i].flags = req[i].flags;
411 servers_readable--; 451 servers_readable--;
412 one_read = 1; 452 one_read = true;
413 if(servers[i].num_responses==AVG_NUM) servers_completed++; 453 if (servers[i].num_responses == AVG_NUM) {
454 servers_completed++;
455 }
414 } 456 }
415 } 457 }
416 /* lather, rinse, repeat. */ 458 /* lather, rinse, repeat. */
417 } 459 }
418 460
419 if (one_read == 0) { 461 if (!one_read) {
420 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); 462 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
421 } 463 }
422 464
423 /* now, pick the best server from the list */ 465 /* now, pick the best server from the list */
424 best_index=best_offset_server(servers, num_hosts); 466 double avg_offset = 0.;
425 if(best_index < 0){ 467 int best_index = best_offset_server(servers, num_hosts);
426 *status=STATE_UNKNOWN; 468 if (best_index < 0) {
469 *status = STATE_UNKNOWN;
427 } else { 470 } else {
428 /* finally, calculate the average offset */ 471 /* finally, calculate the average offset */
429 for(i=0; i<servers[best_index].num_responses;i++){ 472 for (int i = 0; i < servers[best_index].num_responses; i++) {
430 avg_offset+=servers[best_index].offset[i]; 473 avg_offset += servers[best_index].offset[i];
431 } 474 }
432 avg_offset/=servers[best_index].num_responses; 475 avg_offset /= servers[best_index].num_responses;
433 } 476 }
434 477
435 /* cleanup */ 478 /* cleanup */
436 for(j=0; j<num_hosts; j++){ close(socklist[j]); } 479 for (size_t j = 0; j < num_hosts; j++) {
480 close(socklist[j]);
481 }
437 free(socklist); 482 free(socklist);
438 free(ufds); 483 free(ufds);
439 free(servers); 484 free(servers);
440 free(req); 485 free(req);
441 freeaddrinfo(ai); 486 freeaddrinfo(addresses);
442 487
443 if(verbose) printf("overall average offset: %.10g\n", avg_offset); 488 if (verbose) {
489 printf("overall average offset: %.10g\n", avg_offset);
490 }
444 return avg_offset; 491 return avg_offset;
445} 492}
446 493
447int process_arguments(int argc, char **argv){ 494check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
448 int c; 495 static struct option longopts[] = {{"version", no_argument, 0, 'V'},
449 int option=0; 496 {"help", no_argument, 0, 'h'},
450 static struct option longopts[] = { 497 {"verbose", no_argument, 0, 'v'},
451 {"version", no_argument, 0, 'V'}, 498 {"use-ipv4", no_argument, 0, '4'},
452 {"help", no_argument, 0, 'h'}, 499 {"use-ipv6", no_argument, 0, '6'},
453 {"verbose", no_argument, 0, 'v'}, 500 {"quiet", no_argument, 0, 'q'},
454 {"use-ipv4", no_argument, 0, '4'}, 501 {"time-offset", optional_argument, 0, 'o'},
455 {"use-ipv6", no_argument, 0, '6'}, 502 {"warning", required_argument, 0, 'w'},
456 {"quiet", no_argument, 0, 'q'}, 503 {"critical", required_argument, 0, 'c'},
457 {"time-offset", optional_argument, 0, 'o'}, 504 {"timeout", required_argument, 0, 't'},
458 {"warning", required_argument, 0, 'w'}, 505 {"hostname", required_argument, 0, 'H'},
459 {"critical", required_argument, 0, 'c'}, 506 {"port", required_argument, 0, 'p'},
460 {"timeout", required_argument, 0, 't'}, 507 {0, 0, 0, 0}};
461 {"hostname", required_argument, 0, 'H'}, 508
462 {"port", required_argument, 0, 'p'}, 509 if (argc < 2) {
463 {0, 0, 0, 0} 510 usage("\n");
464 }; 511 }
465 512
513 check_ntp_time_config_wrapper result = {
514 .errorcode = OK,
515 .config = check_ntp_time_config_init(),
516 };
466 517
467 if (argc < 2) 518 char *owarn = "60";
468 usage ("\n"); 519 char *ocrit = "120";
469 520
470 while (1) { 521 while (true) {
471 c = getopt_long (argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option); 522 int option = 0;
472 if (c == -1 || c == EOF || c == 1) 523 int option_char = getopt_long(argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option);
524 if (option_char == -1 || option_char == EOF || option_char == 1) {
473 break; 525 break;
526 }
474 527
475 switch (c) { 528 switch (option_char) {
476 case 'h': 529 case 'h':
477 print_help(); 530 print_help();
478 exit(STATE_UNKNOWN); 531 exit(STATE_UNKNOWN);
@@ -485,7 +538,7 @@ int process_arguments(int argc, char **argv){
485 verbose++; 538 verbose++;
486 break; 539 break;
487 case 'q': 540 case 'q':
488 quiet = true; 541 result.config.quiet = true;
489 break; 542 break;
490 case 'w': 543 case 'w':
491 owarn = optarg; 544 owarn = optarg;
@@ -494,19 +547,20 @@ int process_arguments(int argc, char **argv){
494 ocrit = optarg; 547 ocrit = optarg;
495 break; 548 break;
496 case 'H': 549 case 'H':
497 if(!is_host(optarg)) 550 if (!is_host(optarg)) {
498 usage2(_("Invalid hostname/address"), optarg); 551 usage2(_("Invalid hostname/address"), optarg);
499 server_address = strdup(optarg); 552 }
553 result.config.server_address = strdup(optarg);
500 break; 554 break;
501 case 'p': 555 case 'p':
502 port = strdup(optarg); 556 result.config.port = strdup(optarg);
503 break; 557 break;
504 case 't': 558 case 't':
505 socket_timeout=atoi(optarg); 559 socket_timeout = atoi(optarg);
506 break; 560 break;
507 case 'o': 561 case 'o':
508 time_offset=atoi(optarg); 562 result.config.time_offset = atoi(optarg);
509 break; 563 break;
510 case '4': 564 case '4':
511 address_family = AF_INET; 565 address_family = AF_INET;
512 break; 566 break;
@@ -514,114 +568,119 @@ int process_arguments(int argc, char **argv){
514#ifdef USE_IPV6 568#ifdef USE_IPV6
515 address_family = AF_INET6; 569 address_family = AF_INET6;
516#else 570#else
517 usage4 (_("IPv6 support not available")); 571 usage4(_("IPv6 support not available"));
518#endif 572#endif
519 break; 573 break;
520 case '?': 574 case '?':
521 /* print short usage statement if args not parsable */ 575 /* print short usage statement if args not parsable */
522 usage5 (); 576 usage5();
523 break; 577 break;
524 } 578 }
525 } 579 }
526 580
527 if(server_address == NULL){ 581 if (result.config.server_address == NULL) {
528 usage4(_("Hostname was not supplied")); 582 usage4(_("Hostname was not supplied"));
529 } 583 }
530 584
531 return 0; 585 set_thresholds(&result.config.offset_thresholds, owarn, ocrit);
532}
533 586
534char *perfd_offset (double offset) { 587 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} 588}
540 589
541int main(int argc, char *argv[]){ 590char *perfd_offset(double offset, thresholds *offset_thresholds) {
542 int result, offset_result; 591 return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true,
543 double offset=0; 592 offset_thresholds->critical->end, false, 0, false, 0);
544 char *result_line, *perfdata_line; 593}
545
546 setlocale (LC_ALL, "");
547 bindtextdomain (PACKAGE, LOCALEDIR);
548 textdomain (PACKAGE);
549 594
550 result = offset_result = STATE_OK; 595int main(int argc, char *argv[]) {
596 setlocale(LC_ALL, "");
597 bindtextdomain(PACKAGE, LOCALEDIR);
598 textdomain(PACKAGE);
551 599
552 /* Parse extra opts if any */ 600 /* Parse extra opts if any */
553 argv=np_extra_opts (&argc, argv, progname); 601 argv = np_extra_opts(&argc, argv, progname);
554 602
555 if (process_arguments (argc, argv) == ERROR) 603 check_ntp_time_config_wrapper tmp_config = process_arguments(argc, argv);
556 usage4 (_("Could not parse arguments"));
557 604
558 set_thresholds(&offset_thresholds, owarn, ocrit); 605 if (tmp_config.errorcode == ERROR) {
606 usage4(_("Could not parse arguments"));
607 }
608
609 const check_ntp_time_config config = tmp_config.config;
559 610
560 /* initialize alarm signal handling */ 611 /* initialize alarm signal handling */
561 signal (SIGALRM, socket_timeout_alarm_handler); 612 signal(SIGALRM, socket_timeout_alarm_handler);
562 613
563 /* set socket timeout */ 614 /* set socket timeout */
564 alarm (socket_timeout); 615 alarm(socket_timeout);
565 616
566 offset = offset_request(server_address, &offset_result); 617 mp_state_enum offset_result = STATE_OK;
618 mp_state_enum result = STATE_OK;
619 double offset =
620 offset_request(config.server_address, config.port, &offset_result, config.time_offset);
567 if (offset_result == STATE_UNKNOWN) { 621 if (offset_result == STATE_UNKNOWN) {
568 result = ( (!quiet) ? STATE_UNKNOWN : STATE_CRITICAL); 622 result = ((!config.quiet) ? STATE_UNKNOWN : STATE_CRITICAL);
569 } else { 623 } else {
570 result = get_status(fabs(offset), offset_thresholds); 624 result = get_status(fabs(offset), config.offset_thresholds);
571 } 625 }
572 626
627 char *result_line;
573 switch (result) { 628 switch (result) {
574 case STATE_CRITICAL : 629 case STATE_CRITICAL:
575 xasprintf(&result_line, _("NTP CRITICAL:")); 630 xasprintf(&result_line, _("NTP CRITICAL:"));
576 break; 631 break;
577 case STATE_WARNING : 632 case STATE_WARNING:
578 xasprintf(&result_line, _("NTP WARNING:")); 633 xasprintf(&result_line, _("NTP WARNING:"));
579 break; 634 break;
580 case STATE_OK : 635 case STATE_OK:
581 xasprintf(&result_line, _("NTP OK:")); 636 xasprintf(&result_line, _("NTP OK:"));
582 break; 637 break;
583 default : 638 default:
584 xasprintf(&result_line, _("NTP UNKNOWN:")); 639 xasprintf(&result_line, _("NTP UNKNOWN:"));
585 break; 640 break;
586 } 641 }
587 if(offset_result == STATE_UNKNOWN){ 642
643 char *perfdata_line;
644 if (offset_result == STATE_UNKNOWN) {
588 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown")); 645 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
589 xasprintf(&perfdata_line, ""); 646 xasprintf(&perfdata_line, "");
590 } else { 647 } else {
591 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset); 648 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset);
592 xasprintf(&perfdata_line, "%s", perfd_offset(offset)); 649 xasprintf(&perfdata_line, "%s", perfd_offset(offset, config.offset_thresholds));
593 } 650 }
594 printf("%s|%s\n", result_line, perfdata_line); 651 printf("%s|%s\n", result_line, perfdata_line);
595 652
596 if(server_address!=NULL) free(server_address); 653 if (config.server_address != NULL) {
597 return result; 654 free(config.server_address);
655 }
656 exit(result);
598} 657}
599 658
600void print_help(void){ 659void print_help(void) {
601 print_revision(progname, NP_VERSION); 660 print_revision(progname, NP_VERSION);
602 661
603 printf ("Copyright (c) 2006 Sean Finney\n"); 662 printf("Copyright (c) 2006 Sean Finney\n");
604 printf (COPYRIGHT, copyright, email); 663 printf(COPYRIGHT, copyright, email);
605 664
606 printf ("%s\n", _("This plugin checks the clock offset with the ntp server")); 665 printf("%s\n", _("This plugin checks the clock offset with the ntp server"));
607 666
608 printf ("\n\n"); 667 printf("\n\n");
609 668
610 print_usage(); 669 print_usage();
611 printf (UT_HELP_VRSN); 670 printf(UT_HELP_VRSN);
612 printf (UT_EXTRA_OPTS); 671 printf(UT_EXTRA_OPTS);
613 printf (UT_IPv46); 672 printf(UT_IPv46);
614 printf (UT_HOST_PORT, 'p', "123"); 673 printf(UT_HOST_PORT, 'p', "123");
615 printf (" %s\n", "-q, --quiet"); 674 printf(" %s\n", "-q, --quiet");
616 printf (" %s\n", _("Returns UNKNOWN instead of CRITICAL if offset cannot be found")); 675 printf(" %s\n", _("Returns UNKNOWN instead of CRITICAL if offset cannot be found"));
617 printf (" %s\n", "-w, --warning=THRESHOLD"); 676 printf(" %s\n", "-w, --warning=THRESHOLD");
618 printf (" %s\n", _("Offset to result in warning status (seconds)")); 677 printf(" %s\n", _("Offset to result in warning status (seconds)"));
619 printf (" %s\n", "-c, --critical=THRESHOLD"); 678 printf(" %s\n", "-c, --critical=THRESHOLD");
620 printf (" %s\n", _("Offset to result in critical status (seconds)")); 679 printf(" %s\n", _("Offset to result in critical status (seconds)"));
621 printf (" %s\n", "-o, --time_offset=INTEGER"); 680 printf(" %s\n", "-o, --time_offset=INTEGER");
622 printf (" %s\n", _("Expected offset of the ntp server relative to local server (seconds)")); 681 printf(" %s\n", _("Expected offset of the ntp server relative to local server (seconds)"));
623 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 682 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
624 printf (UT_VERBOSE); 683 printf(UT_VERBOSE);
625 684
626 printf("\n"); 685 printf("\n");
627 printf("%s\n", _("This plugin checks the clock offset between the local host and a")); 686 printf("%s\n", _("This plugin checks the clock offset between the local host and a"));
@@ -641,13 +700,11 @@ void print_help(void){
641 printf("%s\n", _("Examples:")); 700 printf("%s\n", _("Examples:"));
642 printf(" %s\n", ("./check_ntp_time -H ntpserv -w 0.5 -c 1")); 701 printf(" %s\n", ("./check_ntp_time -H ntpserv -w 0.5 -c 1"));
643 702
644 printf (UT_SUPPORT); 703 printf(UT_SUPPORT);
645} 704}
646 705
647void 706void print_usage(void) {
648print_usage(void) 707 printf("%s\n", _("Usage:"));
649{ 708 printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-v verbose] [-o <time offset>]\n",
650 printf ("%s\n", _("Usage:")); 709 progname);
651 printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-v verbose] [-o <time offset>]\n", progname);
652} 710}
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..793a686f 100644
--- a/plugins/check_pgsql.c
+++ b/plugins/check_pgsql.c
@@ -1,95 +1,77 @@
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, \
57 PSQL_IS_UNIX_DOMAIN_SOCKET (host) ? "/.s.PGSQL." : ":", \ 57 PSQL_IS_UNIX_DOMAIN_SOCKET(host) ? "/.s.PGSQL." : ":", port
58 port 58
59 59typedef struct {
60enum { 60 int errorcode;
61 DEFAULT_PORT = 5432, 61 check_pgsql_config config;
62 DEFAULT_WARN = 2, 62} check_pgsql_config_wrapper;
63 DEFAULT_CRIT = 8 63static check_pgsql_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
64}; 64
65 65static void print_help(void);
66 66static bool is_pg_logname(char * /*username*/);
67 67static mp_state_enum do_query(PGconn * /*conn*/, char * /*query*/, const char /*pgqueryname*/[],
68int process_arguments (int, char **); 68 thresholds * /*qthresholds*/, char * /*query_warning*/,
69int validate_arguments (void); 69 char * /*query_critical*/);
70void print_usage (void); 70void print_usage(void);
71void print_help (void); 71
72bool is_pg_logname (char *); 72static int verbose = 0;
73int do_query (PGconn *, char *); 73
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 74#define OPTID_QUERYNAME -1000
88char *pgqueryname = NULL;
89char *query_warning = NULL;
90char *query_critical = NULL;
91thresholds *qthresholds = NULL;
92int verbose = 0;
93 75
94/****************************************************************************** 76/******************************************************************************
95 77
@@ -141,237 +123,239 @@ Please note that all tags must be lowercase to use the DocBook XML DTD.
141-@@ 123-@@
142******************************************************************************/ 124******************************************************************************/
143 125
126int main(int argc, char **argv) {
127 setlocale(LC_ALL, "");
128 bindtextdomain(PACKAGE, LOCALEDIR);
129 textdomain(PACKAGE);
144 130
131 /* Parse extra opts if any */
132 argv = np_extra_opts(&argc, argv, progname);
145 133
146int 134 check_pgsql_config_wrapper tmp_config = process_arguments(argc, argv);
147main (int argc, char **argv) 135 if (tmp_config.errorcode == ERROR) {
148{ 136 usage4(_("Could not parse arguments"));
149 PGconn *conn; 137 }
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 138
166 setlocale (LC_ALL, ""); 139 const check_pgsql_config config = tmp_config.config;
167 bindtextdomain (PACKAGE, LOCALEDIR);
168 textdomain (PACKAGE);
169 140
170 /* Parse extra opts if any */ 141 if (verbose > 2) {
171 argv=np_extra_opts (&argc, argv, progname);
172
173 if (process_arguments (argc, argv) == ERROR)
174 usage4 (_("Could not parse arguments"));
175 if (verbose > 2)
176 printf("Arguments initialized\n"); 142 printf("Arguments initialized\n");
143 }
177 144
178 /* Set signal handling and alarm */ 145 /* Set signal handling and alarm */
179 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 146 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
180 usage4 (_("Cannot catch SIGALRM")); 147 usage4(_("Cannot catch SIGALRM"));
148 }
149 alarm(timeout_interval);
150
151 char *conninfo = NULL;
152 if (config.pgparams) {
153 asprintf(&conninfo, "%s ", config.pgparams);
154 }
155
156 asprintf(&conninfo, "%sdbname = '%s'", conninfo ? conninfo : "", config.dbName);
157 if (config.pghost) {
158 asprintf(&conninfo, "%s host = '%s'", conninfo, config.pghost);
159 }
160 if (config.pgport) {
161 asprintf(&conninfo, "%s port = '%s'", conninfo, config.pgport);
162 }
163 if (config.pgoptions) {
164 asprintf(&conninfo, "%s options = '%s'", conninfo, config.pgoptions);
181 } 165 }
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 */ 166 /* if (pgtty) -- ignored by PQconnectdb */
195 if (pguser) 167 if (config.pguser) {
196 asprintf (&conninfo, "%s user = '%s'", conninfo, pguser); 168 asprintf(&conninfo, "%s user = '%s'", conninfo, config.pguser);
169 }
197 170
198 if (verbose) /* do not include password (see right below) in output */ 171 if (verbose) { /* do not include password (see right below) in output */
199 printf ("Connecting to PostgreSQL using conninfo: %s%s\n", conninfo, 172 printf("Connecting to PostgreSQL using conninfo: %s%s\n", conninfo,
200 pgpasswd ? " password = <hidden>" : ""); 173 config.pgpasswd ? " password = <hidden>" : "");
174 }
201 175
202 if (pgpasswd) 176 if (config.pgpasswd) {
203 asprintf (&conninfo, "%s password = '%s'", conninfo, pgpasswd); 177 asprintf(&conninfo, "%s password = '%s'", conninfo, config.pgpasswd);
178 }
204 179
205 /* make a connection to the database */ 180 /* make a connection to the database */
206 gettimeofday (&start_timeval, NULL); 181 struct timeval start_timeval;
207 conn = PQconnectdb (conninfo); 182 gettimeofday(&start_timeval, NULL);
208 gettimeofday (&end_timeval, NULL); 183 PGconn *conn = PQconnectdb(conninfo);
184 struct timeval end_timeval;
185 gettimeofday(&end_timeval, NULL);
209 186
210 while (start_timeval.tv_usec > end_timeval.tv_usec) { 187 while (start_timeval.tv_usec > end_timeval.tv_usec) {
211 --end_timeval.tv_sec; 188 --end_timeval.tv_sec;
212 end_timeval.tv_usec += 1000000; 189 end_timeval.tv_usec += 1000000;
213 } 190 }
214 elapsed_time = (double)(end_timeval.tv_sec - start_timeval.tv_sec) 191 double elapsed_time = (double)(end_timeval.tv_sec - start_timeval.tv_sec) +
215 + (double)(end_timeval.tv_usec - start_timeval.tv_usec) / 1000000.0; 192 ((double)(end_timeval.tv_usec - start_timeval.tv_usec) / 1000000.0);
216 193
217 if (verbose) 194 if (verbose) {
218 printf("Time elapsed: %f\n", elapsed_time); 195 printf("Time elapsed: %f\n", elapsed_time);
196 }
219 197
220 /* check to see that the backend connection was successfully made */ 198 /* check to see that the backend connection was successfully made */
221 if (verbose) 199 if (verbose) {
222 printf("Verifying connection\n"); 200 printf("Verifying connection\n");
223 if (PQstatus (conn) == CONNECTION_BAD) { 201 }
224 printf (_("CRITICAL - no connection to '%s' (%s).\n"), 202 if (PQstatus(conn) == CONNECTION_BAD) {
225 dbName, PQerrorMessage (conn)); 203 printf(_("CRITICAL - no connection to '%s' (%s).\n"), config.dbName, PQerrorMessage(conn));
226 PQfinish (conn); 204 PQfinish(conn);
227 return STATE_CRITICAL; 205 return STATE_CRITICAL;
228 } 206 }
229 else if (elapsed_time > tcrit) { 207
208 mp_state_enum status = STATE_UNKNOWN;
209 if (elapsed_time > config.tcrit) {
230 status = STATE_CRITICAL; 210 status = STATE_CRITICAL;
231 } 211 } else if (elapsed_time > config.twarn) {
232 else if (elapsed_time > twarn) {
233 status = STATE_WARNING; 212 status = STATE_WARNING;
234 } 213 } else {
235 else {
236 status = STATE_OK; 214 status = STATE_OK;
237 } 215 }
238 216
239 if (verbose) { 217 if (verbose) {
240 char *server_host = PQhost (conn); 218 char *server_host = PQhost(conn);
241 int server_version = PQserverVersion (conn); 219 int server_version = PQserverVersion(conn);
242 220
243 printf ("Successfully connected to database %s (user %s) " 221 printf("Successfully connected to database %s (user %s) "
244 "at server %s%s%s (server version: %d.%d.%d, " 222 "at server %s%s%s (server version: %d.%d.%d, "
245 "protocol version: %d, pid: %d)\n", 223 "protocol version: %d, pid: %d)\n",
246 PQdb (conn), PQuser (conn), 224 PQdb(conn), PQuser(conn), PSQL_SOCKET3(server_host, PQport(conn)),
247 PSQL_SOCKET3 (server_host, PQport (conn)), 225 PSQL_SERVER_VERSION3(server_version), PQprotocolVersion(conn), PQbackendPID(conn));
248 PSQL_SERVER_VERSION3 (server_version),
249 PQprotocolVersion (conn), PQbackendPID (conn));
250 } 226 }
251 227
252 printf (_(" %s - database %s (%f sec.)|%s\n"), 228 printf(_(" %s - database %s (%f sec.)|%s\n"), state_text(status), config.dbName, elapsed_time,
253 state_text(status), dbName, elapsed_time, 229 fperfdata("time", elapsed_time, "s", (config.twarn > 0.0), config.twarn,
254 fperfdata("time", elapsed_time, "s", 230 (config.tcrit > 0.0), config.tcrit, true, 0, false, 0));
255 !!(twarn > 0.0), twarn, !!(tcrit > 0.0), tcrit, true, 0, false,0));
256 231
257 if (pgquery) 232 mp_state_enum query_status = STATE_UNKNOWN;
258 query_status = do_query (conn, pgquery); 233 if (config.pgquery) {
234 query_status = do_query(conn, config.pgquery, config.pgqueryname, config.qthresholds,
235 config.query_warning, config.query_critical);
236 }
259 237
260 if (verbose) 238 if (verbose) {
261 printf("Closing connection\n"); 239 printf("Closing connection\n");
262 PQfinish (conn); 240 }
263 return (pgquery && query_status > status) ? query_status : status; 241 PQfinish(conn);
242 return (config.pgquery && query_status > status) ? query_status : status;
264} 243}
265 244
266
267
268/* process command-line arguments */ 245/* process command-line arguments */
269int 246check_pgsql_config_wrapper process_arguments(int argc, char **argv) {
270process_arguments (int argc, char **argv) 247 static struct option longopts[] = {{"help", no_argument, 0, 'h'},
271{ 248 {"version", no_argument, 0, 'V'},
272 int c; 249 {"timeout", required_argument, 0, 't'},
273 250 {"critical", required_argument, 0, 'c'},
274 int option = 0; 251 {"warning", required_argument, 0, 'w'},
275 static struct option longopts[] = { 252 {"hostname", required_argument, 0, 'H'},
276 {"help", no_argument, 0, 'h'}, 253 {"logname", required_argument, 0, 'l'},
277 {"version", no_argument, 0, 'V'}, 254 {"password", required_argument, 0, 'p'},
278 {"timeout", required_argument, 0, 't'}, 255 {"authorization", required_argument, 0, 'a'},
279 {"critical", required_argument, 0, 'c'}, 256 {"port", required_argument, 0, 'P'},
280 {"warning", required_argument, 0, 'w'}, 257 {"database", required_argument, 0, 'd'},
281 {"hostname", required_argument, 0, 'H'}, 258 {"option", required_argument, 0, 'o'},
282 {"logname", required_argument, 0, 'l'}, 259 {"query", required_argument, 0, 'q'},
283 {"password", required_argument, 0, 'p'}, 260 {"queryname", required_argument, 0, OPTID_QUERYNAME},
284 {"authorization", required_argument, 0, 'a'}, 261 {"query_critical", required_argument, 0, 'C'},
285 {"port", required_argument, 0, 'P'}, 262 {"query_warning", required_argument, 0, 'W'},
286 {"database", required_argument, 0, 'd'}, 263 {"verbose", no_argument, 0, 'v'},
287 {"option", required_argument, 0, 'o'}, 264 {0, 0, 0, 0}};
288 {"query", required_argument, 0, 'q'}, 265
289 {"queryname", required_argument, 0, OPTID_QUERYNAME}, 266 check_pgsql_config_wrapper result = {
290 {"query_critical", required_argument, 0, 'C'}, 267 .errorcode = OK,
291 {"query_warning", required_argument, 0, 'W'}, 268 .config = check_pgsql_config_init(),
292 {"verbose", no_argument, 0, 'v'},
293 {0, 0, 0, 0}
294 }; 269 };
295 270
296 while (1) { 271 while (true) {
297 c = getopt_long (argc, argv, "hVt:c:w:H:P:d:l:p:a:o:q:C:W:v", 272 int option = 0;
298 longopts, &option); 273 int option_char =
274 getopt_long(argc, argv, "hVt:c:w:H:P:d:l:p:a:o:q:C:W:v", longopts, &option);
299 275
300 if (c == EOF) 276 if (option_char == EOF) {
301 break; 277 break;
278 }
302 279
303 switch (c) { 280 switch (option_char) {
304 case '?': /* usage */ 281 case '?': /* usage */
305 usage5 (); 282 usage5();
306 case 'h': /* help */ 283 case 'h': /* help */
307 print_help (); 284 print_help();
308 exit (STATE_UNKNOWN); 285 exit(STATE_UNKNOWN);
309 case 'V': /* version */ 286 case 'V': /* version */
310 print_revision (progname, NP_VERSION); 287 print_revision(progname, NP_VERSION);
311 exit (STATE_UNKNOWN); 288 exit(STATE_UNKNOWN);
312 case 't': /* timeout period */ 289 case 't': /* timeout period */
313 if (!is_integer (optarg)) 290 if (!is_integer(optarg)) {
314 usage2 (_("Timeout interval must be a positive integer"), optarg); 291 usage2(_("Timeout interval must be a positive integer"), optarg);
315 else 292 } else {
316 timeout_interval = atoi (optarg); 293 timeout_interval = atoi(optarg);
294 }
317 break; 295 break;
318 case 'c': /* critical time threshold */ 296 case 'c': /* critical time threshold */
319 if (!is_nonnegative (optarg)) 297 if (!is_nonnegative(optarg)) {
320 usage2 (_("Critical threshold must be a positive integer"), optarg); 298 usage2(_("Critical threshold must be a positive integer"), optarg);
321 else 299 } else {
322 tcrit = strtod (optarg, NULL); 300 result.config.tcrit = strtod(optarg, NULL);
301 }
323 break; 302 break;
324 case 'w': /* warning time threshold */ 303 case 'w': /* warning time threshold */
325 if (!is_nonnegative (optarg)) 304 if (!is_nonnegative(optarg)) {
326 usage2 (_("Warning threshold must be a positive integer"), optarg); 305 usage2(_("Warning threshold must be a positive integer"), optarg);
327 else 306 } else {
328 twarn = strtod (optarg, NULL); 307 result.config.twarn = strtod(optarg, NULL);
308 }
329 break; 309 break;
330 case 'C': /* critical query threshold */ 310 case 'C': /* critical query threshold */
331 query_critical = optarg; 311 result.config.query_critical = optarg;
332 break; 312 break;
333 case 'W': /* warning query threshold */ 313 case 'W': /* warning query threshold */
334 query_warning = optarg; 314 result.config.query_warning = optarg;
335 break; 315 break;
336 case 'H': /* host */ 316 case 'H': /* host */
337 if ((*optarg != '/') && (!is_host (optarg))) 317 if ((*optarg != '/') && (!is_host(optarg))) {
338 usage2 (_("Invalid hostname/address"), optarg); 318 usage2(_("Invalid hostname/address"), optarg);
339 else 319 } else {
340 pghost = optarg; 320 result.config.pghost = optarg;
321 }
341 break; 322 break;
342 case 'P': /* port */ 323 case 'P': /* port */
343 if (!is_integer (optarg)) 324 if (!is_integer(optarg)) {
344 usage2 (_("Port must be a positive integer"), optarg); 325 usage2(_("Port must be a positive integer"), optarg);
345 else 326 } else {
346 pgport = optarg; 327 result.config.pgport = optarg;
328 }
347 break; 329 break;
348 case 'd': /* database name */ 330 case 'd': /* database name */
349 if (strlen(optarg) >= NAMEDATALEN) { 331 if (strlen(optarg) >= NAMEDATALEN) {
350 usage2 (_("Database name exceeds the maximum length"), optarg); 332 usage2(_("Database name exceeds the maximum length"), optarg);
351 } 333 }
352 snprintf(dbName, NAMEDATALEN, "%s", optarg); 334 snprintf(result.config.dbName, NAMEDATALEN, "%s", optarg);
353 break; 335 break;
354 case 'l': /* login name */ 336 case 'l': /* login name */
355 if (!is_pg_logname (optarg)) 337 if (!is_pg_logname(optarg)) {
356 usage2 (_("User name is not valid"), optarg); 338 usage2(_("User name is not valid"), optarg);
357 else 339 } else {
358 pguser = optarg; 340 result.config.pguser = optarg;
341 }
359 break; 342 break;
360 case 'p': /* authentication password */ 343 case 'p': /* authentication password */
361 case 'a': 344 case 'a':
362 pgpasswd = optarg; 345 result.config.pgpasswd = optarg;
363 break; 346 break;
364 case 'o': 347 case 'o':
365 if (pgparams) 348 if (result.config.pgparams) {
366 asprintf (&pgparams, "%s %s", pgparams, optarg); 349 asprintf(&result.config.pgparams, "%s %s", result.config.pgparams, optarg);
367 else 350 } else {
368 asprintf (&pgparams, "%s", optarg); 351 asprintf(&result.config.pgparams, "%s", optarg);
352 }
369 break; 353 break;
370 case 'q': 354 case 'q':
371 pgquery = optarg; 355 result.config.pgquery = optarg;
372 break; 356 break;
373 case OPTID_QUERYNAME: 357 case OPTID_QUERYNAME:
374 pgqueryname = optarg; 358 result.config.pgqueryname = optarg;
375 break; 359 break;
376 case 'v': 360 case 'v':
377 verbose++; 361 verbose++;
@@ -379,38 +363,10 @@ process_arguments (int argc, char **argv)
379 } 363 }
380 } 364 }
381 365
382 set_thresholds (&qthresholds, query_warning, query_critical); 366 set_thresholds(&result.config.qthresholds, result.config.query_warning,
367 result.config.query_critical);
383 368
384 return validate_arguments (); 369 return result;
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
410int
411validate_arguments ()
412{
413 return OK;
414} 370}
415 371
416/** 372/**
@@ -437,11 +393,10 @@ should be added.</para>
437-@@ 393-@@
438******************************************************************************/ 394******************************************************************************/
439 395
440 396bool is_pg_logname(char *username) {
441 397 if (strlen(username) > NAMEDATALEN - 1) {
442bool is_pg_logname (char *username) {
443 if (strlen (username) > NAMEDATALEN - 1)
444 return (false); 398 return (false);
399 }
445 return (true); 400 return (true);
446} 401}
447 402
@@ -453,182 +408,171 @@ bool is_pg_logname (char *username) {
453-@@ 408-@@
454******************************************************************************/ 409******************************************************************************/
455 410
456 411void print_help(void) {
457
458void
459print_help (void)
460{
461 char *myport; 412 char *myport;
462 413
463 xasprintf (&myport, "%d", DEFAULT_PORT); 414 xasprintf(&myport, "%d", 5432);
464 415
465 print_revision (progname, NP_VERSION); 416 print_revision(progname, NP_VERSION);
466 417
467 printf (COPYRIGHT, copyright, email); 418 printf(COPYRIGHT, copyright, email);
468 419
469 printf (_("Test whether a PostgreSQL Database is accepting connections.")); 420 printf(_("Test whether a PostgreSQL Database is accepting connections."));
470 421
471 printf ("\n\n"); 422 printf("\n\n");
472 423
473 print_usage (); 424 print_usage();
474 425
475 printf (UT_HELP_VRSN); 426 printf(UT_HELP_VRSN);
476 printf (UT_EXTRA_OPTS); 427 printf(UT_EXTRA_OPTS);
477 428
478 printf (UT_HOST_PORT, 'P', myport); 429 printf(UT_HOST_PORT, 'P', myport);
479 430
480 printf (" %s\n", "-d, --database=STRING"); 431 printf(" %s\n", "-d, --database=STRING");
481 printf (" %s", _("Database to check ")); 432 printf(" %s", _("Database to check "));
482 printf (_("(default: %s)\n"), DEFAULT_DB); 433 printf(_("(default: %s)\n"), DEFAULT_DB);
483 printf (" %s\n", "-l, --logname = STRING"); 434 printf(" %s\n", "-l, --logname = STRING");
484 printf (" %s\n", _("Login name of user")); 435 printf(" %s\n", _("Login name of user"));
485 printf (" %s\n", "-p, --password = STRING"); 436 printf(" %s\n", "-p, --password = STRING");
486 printf (" %s\n", _("Password (BIG SECURITY ISSUE)")); 437 printf(" %s\n", _("Password (BIG SECURITY ISSUE)"));
487 printf (" %s\n", "-o, --option = STRING"); 438 printf(" %s\n", "-o, --option = STRING");
488 printf (" %s\n", _("Connection parameters (keyword = value), see below")); 439 printf(" %s\n", _("Connection parameters (keyword = value), see below"));
489 440
490 printf (UT_WARN_CRIT); 441 printf(UT_WARN_CRIT);
491 442
492 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 443 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
493 444
494 printf (" %s\n", "-q, --query=STRING"); 445 printf(" %s\n", "-q, --query=STRING");
495 printf (" %s\n", _("SQL query to run. Only first column in first row will be read")); 446 printf(" %s\n", _("SQL query to run. Only first column in first row will be read"));
496 printf (" %s\n", "--queryname=STRING"); 447 printf(" %s\n", "--queryname=STRING");
497 printf (" %s\n", _("A name for the query, this string is used instead of the query")); 448 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")); 449 printf(" %s\n", _("in the long output of the plugin"));
499 printf (" %s\n", "-W, --query-warning=RANGE"); 450 printf(" %s\n", "-W, --query-warning=RANGE");
500 printf (" %s\n", _("SQL query value to result in warning status (double)")); 451 printf(" %s\n", _("SQL query value to result in warning status (double)"));
501 printf (" %s\n", "-C, --query-critical=RANGE"); 452 printf(" %s\n", "-C, --query-critical=RANGE");
502 printf (" %s\n", _("SQL query value to result in critical status (double)")); 453 printf(" %s\n", _("SQL query value to result in critical status (double)"));
503 454
504 printf (UT_VERBOSE); 455 printf(UT_VERBOSE);
505 456
506 printf ("\n"); 457 printf("\n");
507 printf (" %s\n", _("All parameters are optional.")); 458 printf(" %s\n", _("All parameters are optional."));
508 printf (" %s\n", _("This plugin tests a PostgreSQL DBMS to determine whether it is active and")); 459 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")); 460 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")); 461 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")); 462 printf(" %s\n", _("connects to the template1 database, which is present in every functioning"));
512 printf (" %s\n\n", _("PostgreSQL DBMS.")); 463 printf(" %s\n\n", _("PostgreSQL DBMS."));
513 464
514 printf (" %s\n", _("If a query is specified using the -q option, it will be executed after")); 465 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.")); 466 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 ")); 467 printf(" %s\n",
517 printf (" %s\n", _("of the last command is taken into account only. The value of the first")); 468 _("Multiple SQL commands, separated by semicolon, are allowed but the result "));
518 printf (" %s\n", _("column in the first row is used as the check result. If a second column is")); 469 printf(" %s\n", _("of the last command is taken into account only. The value of the first"));
519 printf (" %s\n", _("present in the result set, this is added to the plugin output with a")); 470 printf(" %s\n",
520 printf (" %s\n", _("prefix of \"Extra Info:\". This information can be displayed in the system")); 471 _("column in the first row is used as the check result. If a second column is"));
521 printf (" %s\n\n", _("executing the plugin.")); 472 printf(" %s\n", _("present in the result set, this is added to the plugin output with a"));
522 473 printf(" %s\n",
523 printf (" %s\n", _("See the chapter \"Monitoring Database Activity\" of the PostgreSQL manual")); 474 _("prefix of \"Extra Info:\". This information can be displayed in the system"));
524 printf (" %s\n\n", _("for details about how to access internal statistics of the database server.")); 475 printf(" %s\n\n", _("executing the plugin."));
525 476
526 printf (" %s\n", _("For a list of available connection parameters which may be used with the -o")); 477 printf(" %s\n", _("See the chapter \"Monitoring Database Activity\" of the PostgreSQL manual"));
527 printf (" %s\n", _("command line option, see the documentation for PQconnectdb() in the chapter")); 478 printf(" %s\n\n",
528 printf (" %s\n", _("\"libpq - C Library\" of the PostgreSQL manual. For example, this may be")); 479 _("for details about how to access internal statistics of the database server."));
529 printf (" %s\n", _("used to specify a service name in pg_service.conf to be used for additional")); 480
530 printf (" %s\n", _("connection parameters: -o 'service=<name>' or to specify the SSL mode:")); 481 printf(" %s\n",
531 printf (" %s\n\n", _("-o 'sslmode=require'.")); 482 _("For a list of available connection parameters which may be used with the -o"));
532 483 printf(" %s\n",
533 printf (" %s\n", _("The plugin will connect to a local postmaster if no host is specified. To")); 484 _("command line option, see the documentation for PQconnectdb() in the chapter"));
534 printf (" %s\n", _("connect to a remote host, be sure that the remote postmaster accepts TCP/IP")); 485 printf(" %s\n", _("\"libpq - C Library\" of the PostgreSQL manual. For example, this may be"));
535 printf (" %s\n\n", _("connections (start the postmaster with the -i option).")); 486 printf(" %s\n",
536 487 _("used to specify a service name in pg_service.conf to be used for additional"));
537 printf (" %s\n", _("Typically, the monitoring user (unless the --logname option is used) should be")); 488 printf(" %s\n", _("connection parameters: -o 'service=<name>' or to specify the SSL mode:"));
538 printf (" %s\n", _("able to connect to the database without a password. The plugin can also send")); 489 printf(" %s\n\n", _("-o 'sslmode=require'."));
539 printf (" %s\n", _("a password, but no effort is made to obscure or encrypt the password.")); 490
540 491 printf(" %s\n", _("The plugin will connect to a local postmaster if no host is specified. To"));
541 printf (UT_SUPPORT); 492 printf(" %s\n",
493 _("connect to a remote host, be sure that the remote postmaster accepts TCP/IP"));
494 printf(" %s\n\n", _("connections (start the postmaster with the -i option)."));
495
496 printf(" %s\n",
497 _("Typically, the monitoring user (unless the --logname option is used) should be"));
498 printf(" %s\n",
499 _("able to connect to the database without a password. The plugin can also send"));
500 printf(" %s\n", _("a password, but no effort is made to obscure or encrypt the password."));
501
502 printf(UT_SUPPORT);
542} 503}
543 504
544 505void print_usage(void) {
545 506 printf("%s\n", _("Usage:"));
546void 507 printf("%s [-H <host>] [-P <port>] [-c <critical time>] [-w <warning time>]\n", progname);
547print_usage (void) 508 printf(" [-t <timeout>] [-d <database>] [-l <logname>] [-p <password>]\n"
548{ 509 "[-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} 510}
554 511
555int 512mp_state_enum do_query(PGconn *conn, char *query, const char pgqueryname[], thresholds *qthresholds,
556do_query (PGconn *conn, char *query) 513 char *query_warning, char *query_critical) {
557{ 514 if (verbose) {
558 PGresult *res; 515 printf("Executing SQL query \"%s\".\n", query);
559 516 }
560 char *val_str; 517 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 518
572 if (PGRES_TUPLES_OK != PQresultStatus (res)) { 519 if (PGRES_TUPLES_OK != PQresultStatus(res)) {
573 printf (_("QUERY %s - %s: %s.\n"), _("CRITICAL"), _("Error with query"), 520 printf(_("QUERY %s - %s: %s.\n"), _("CRITICAL"), _("Error with query"),
574 PQerrorMessage (conn)); 521 PQerrorMessage(conn));
575 return STATE_CRITICAL; 522 return STATE_CRITICAL;
576 } 523 }
577 524
578 if (PQntuples (res) < 1) { 525 if (PQntuples(res) < 1) {
579 printf ("QUERY %s - %s.\n", _("WARNING"), _("No rows returned")); 526 printf("QUERY %s - %s.\n", _("WARNING"), _("No rows returned"));
580 return STATE_WARNING; 527 return STATE_WARNING;
581 } 528 }
582 529
583 if (PQnfields (res) < 1) { 530 if (PQnfields(res) < 1) {
584 printf ("QUERY %s - %s.\n", _("WARNING"), _("No columns returned")); 531 printf("QUERY %s - %s.\n", _("WARNING"), _("No columns returned"));
585 return STATE_WARNING; 532 return STATE_WARNING;
586 } 533 }
587 534
588 val_str = PQgetvalue (res, 0, 0); 535 char *val_str = PQgetvalue(res, 0, 0);
589 if (! val_str) { 536 if (!val_str) {
590 printf ("QUERY %s - %s.\n", _("CRITICAL"), _("No data returned")); 537 printf("QUERY %s - %s.\n", _("CRITICAL"), _("No data returned"));
591 return STATE_CRITICAL; 538 return STATE_CRITICAL;
592 } 539 }
593 540
594 value = strtod (val_str, &endptr); 541 char *endptr = NULL;
595 if (verbose) 542 double value = strtod(val_str, &endptr);
596 printf ("Query result: %f\n", value); 543 if (verbose) {
544 printf("Query result: %f\n", value);
545 }
597 546
598 if (endptr == val_str) { 547 if (endptr == val_str) {
599 printf ("QUERY %s - %s: %s\n", _("CRITICAL"), _("Is not a numeric"), val_str); 548 printf("QUERY %s - %s: %s\n", _("CRITICAL"), _("Is not a numeric"), val_str);
600 return STATE_CRITICAL; 549 return STATE_CRITICAL;
601 } 550 }
602 else if ((endptr != NULL) && (*endptr != '\0')) {
603 if (verbose)
604 printf ("Garbage after value: %s.\n", endptr);
605 }
606 551
607 my_status = get_status (value, qthresholds); 552 if ((endptr != NULL) && (*endptr != '\0')) {
608 printf ("QUERY %s - ", 553 if (verbose) {
609 (my_status == STATE_OK) 554 printf("Garbage after value: %s.\n", endptr);
610 ? _("OK") 555 }
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 } 556 }
619 else { 557
620 printf (_("'%s' returned %f"), query, value); 558 mp_state_enum my_status = get_status(value, qthresholds);
559 printf("QUERY %s - ", (my_status == STATE_OK) ? _("OK")
560 : (my_status == STATE_WARNING) ? _("WARNING")
561 : (my_status == STATE_CRITICAL) ? _("CRITICAL")
562 : _("UNKNOWN"));
563 if (pgqueryname) {
564 printf(_("%s returned %f"), pgqueryname, value);
565 } else {
566 printf(_("'%s' returned %f"), query, value);
621 } 567 }
622 568
623 printf ("|query=%f;%s;%s;;\n", value, 569 printf("|query=%f;%s;%s;;\n", value, query_warning ? query_warning : "",
624 query_warning ? query_warning : "", 570 query_critical ? query_critical : "");
625 query_critical ? query_critical : ""); 571 if (PQnfields(res) > 1) {
626 if (PQnfields (res) > 1) { 572 char *extra_info = PQgetvalue(res, 0, 1);
627 extra_info = PQgetvalue (res, 0, 1);
628 if (extra_info != NULL) { 573 if (extra_info != NULL) {
629 printf ("Extra Info: %s\n", extra_info); 574 printf("Extra Info: %s\n", extra_info);
630 } 575 }
631 } 576 }
632 return my_status; 577 return my_status;
633} 578}
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..61feb958 100644
--- a/plugins/check_ping.c
+++ b/plugins/check_ping.c
@@ -1,620 +1,673 @@
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 ||
139 pinged.round_trip_average < 0) {
140 pinged.state = STATE_CRITICAL;
141 } else if (pinged.packet_loss >= config.wpl || pinged.round_trip_average >= config.wrta) {
142 pinged.state = STATE_WARNING;
143 } else if (pinged.packet_loss >= 0 && pinged.round_trip_average >= 0) {
144 pinged.state = max_state(STATE_OK, pinged.state);
145 }
146
147 if (config.n_addresses > 1 && pinged.state != STATE_UNKNOWN) {
148 die(STATE_OK, "%s is alive\n", config.addresses[i]);
144 } 149 }
145 150
146 if (pl >= cpl || rta >= crta || rta < 0) 151 if (config.display_html) {
147 this_result = STATE_CRITICAL; 152 printf("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, config.addresses[i]);
148 else if (pl >= wpl || rta >= wrta) 153 }
149 this_result = STATE_WARNING; 154 if (pinged.packet_loss == 100) {
150 else if (pl >= 0 && rta >= 0) 155 printf(_("PING %s - %sPacket loss = %d%%"), state_text(pinged.state), warn_text,
151 this_result = max_state (STATE_OK, this_result); 156 pinged.packet_loss);
152 157 } else {
153 if (n_addresses > 1 && this_result != STATE_UNKNOWN) 158 printf(_("PING %s - %sPacket loss = %d%%, RTA = %2.2f ms"), state_text(pinged.state),
154 die (STATE_OK, "%s is alive\n", addresses[i]); 159 warn_text, pinged.packet_loss, pinged.round_trip_average);
155 160 }
156 if (display_html == true) 161 if (config.display_html) {
157 printf ("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, addresses[i]); 162 printf("</A>");
158 if (pl == 100) 163 }
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 164
167 /* Print performance data */ 165 /* Print performance data */
168 if (pl != 100) { 166 if (pinged.packet_loss != 100) {
169 printf("|%s", fperfdata ("rta", (double) rta, "ms", 167 printf("|%s",
170 wrta>0?true:false, wrta, 168 fperfdata("rta", pinged.round_trip_average, "ms", (bool)(config.wrta > 0),
171 crta>0?true:false, crta, 169 config.wrta, (bool)(config.crta > 0), config.crta, true, 0, false, 0));
172 true, 0, false, 0));
173 } else { 170 } else {
174 printf("| rta=U;%f;%f;;", wrta, crta); 171 printf("| rta=U;%f;%f;;", config.wrta, config.crta);
175 } 172 }
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 173
181 if (verbose >= 2) 174 printf(" %s\n",
182 printf ("%f:%d%% %f:%d%%\n", wrta, wpl, crta, cpl); 175 perfdata("pl", (long)pinged.packet_loss, "%", (bool)(config.wpl > 0), config.wpl,
176 (bool)(config.cpl > 0), config.cpl, true, 0, false, 0));
177
178 if (verbose >= 2) {
179 printf("%f:%d%% %f:%d%%\n", config.wrta, config.wpl, config.crta, config.cpl);
180 }
183 181
184 result = max_state (result, this_result); 182 result = max_state(result, pinged.state);
185 free (rawcmd); 183 free(rawcmd);
186 free (cmd); 184 free(cmd);
187 } 185 }
188 186
189 return result; 187 return result;
190} 188}
191 189
192
193
194/* process command-line arguments */ 190/* process command-line arguments */
195int 191check_ping_config_wrapper process_arguments(int argc, char **argv) {
196process_arguments (int argc, char **argv) 192 static struct option longopts[] = {STD_LONG_OPTS,
197{ 193 {"packets", required_argument, 0, 'p'},
198 int c = 1; 194 {"nohtml", no_argument, 0, 'n'},
199 char *ptr; 195 {"link", no_argument, 0, 'L'},
200 196 {"use-ipv4", no_argument, 0, '4'},
201 int option = 0; 197 {"use-ipv6", no_argument, 0, '6'},
202 static struct option longopts[] = { 198 {0, 0, 0, 0}};
203 STD_LONG_OPTS, 199
204 {"packets", required_argument, 0, 'p'}, 200 check_ping_config_wrapper result = {
205 {"nohtml", no_argument, 0, 'n'}, 201 .errorcode = OK,
206 {"link", no_argument, 0, 'L'}, 202 .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 }; 203 };
211 204
212 if (argc < 2) 205 if (argc < 2) {
213 return ERROR; 206 result.errorcode = ERROR;
207 return result;
208 }
214 209
215 for (c = 1; c < argc; c++) { 210 for (int index = 1; index < argc; index++) {
216 if (strcmp ("-to", argv[c]) == 0) 211 if (strcmp("-to", argv[index]) == 0) {
217 strcpy (argv[c], "-t"); 212 strcpy(argv[index], "-t");
218 if (strcmp ("-nohtml", argv[c]) == 0) 213 }
219 strcpy (argv[c], "-n"); 214 if (strcmp("-nohtml", argv[index]) == 0) {
215 strcpy(argv[index], "-n");
216 }
220 } 217 }
221 218
222 while (1) { 219 int option = 0;
223 c = getopt_long (argc, argv, "VvhnL46t:c:w:H:p:", longopts, &option); 220 size_t max_addr = MAX_ADDR_START;
221 while (true) {
222 int option_index = getopt_long(argc, argv, "VvhnL46t:c:w:H:p:", longopts, &option);
224 223
225 if (c == -1 || c == EOF) 224 if (option_index == -1 || option_index == EOF) {
226 break; 225 break;
226 }
227 227
228 switch (c) { 228 switch (option_index) {
229 case '?': /* usage */ 229 case '?': /* usage */
230 usage5 (); 230 usage5();
231 case 'h': /* help */ 231 case 'h': /* help */
232 print_help (); 232 print_help();
233 exit (STATE_UNKNOWN); 233 exit(STATE_UNKNOWN);
234 break; 234 break;
235 case 'V': /* version */ 235 case 'V': /* version */
236 print_revision (progname, NP_VERSION); 236 print_revision(progname, NP_VERSION);
237 exit (STATE_UNKNOWN); 237 exit(STATE_UNKNOWN);
238 break; 238 break;
239 case 't': /* timeout period */ 239 case 't': /* timeout period */
240 timeout_interval = atoi (optarg); 240 timeout_interval = atoi(optarg);
241 break; 241 break;
242 case 'v': /* verbose mode */ 242 case 'v': /* verbose mode */
243 verbose++; 243 verbose++;
244 break; 244 break;
245 case '4': /* IPv4 only */ 245 case '4': /* IPv4 only */
246 address_family = AF_INET; 246 address_family = AF_INET;
247 break; 247 break;
248 case '6': /* IPv6 only */ 248 case '6': /* IPv6 only */
249#ifdef USE_IPV6 249#ifdef USE_IPV6
250 address_family = AF_INET6; 250 address_family = AF_INET6;
251#else 251#else
252 usage (_("IPv6 support not available\n")); 252 usage(_("IPv6 support not available\n"));
253#endif 253#endif
254 break; 254 break;
255 case 'H': /* hostname */ 255 case 'H': /* hostname */ {
256 ptr=optarg; 256 char *ptr = optarg;
257 while (1) { 257 while (true) {
258 n_addresses++; 258 result.config.n_addresses++;
259 if (n_addresses > max_addr) { 259 if (result.config.n_addresses > max_addr) {
260 max_addr *= 2; 260 max_addr *= 2;
261 addresses = realloc (addresses, sizeof(char*) * max_addr); 261 result.config.addresses =
262 if (addresses == NULL) 262 realloc(result.config.addresses, sizeof(char *) * max_addr);
263 die (STATE_UNKNOWN, _("Could not realloc() addresses\n")); 263 if (result.config.addresses == NULL) {
264 die(STATE_UNKNOWN, _("Could not realloc() addresses\n"));
265 }
264 } 266 }
265 addresses[n_addresses-1] = ptr; 267 result.config.addresses[result.config.n_addresses - 1] = ptr;
266 if ((ptr = index (ptr, ','))) { 268 if ((ptr = index(ptr, ','))) {
267 strcpy (ptr, ""); 269 strcpy(ptr, "");
268 ptr += sizeof(char); 270 ptr += sizeof(char);
269 } else { 271 } else {
270 break; 272 break;
271 } 273 }
272 } 274 }
275 } break;
276 case 'p': /* number of packets to send */
277 if (is_intnonneg(optarg)) {
278 result.config.max_packets = atoi(optarg);
279 } else {
280 usage2(_("<max_packets> (%s) must be a non-negative number\n"), optarg);
281 }
273 break; 282 break;
274 case 'p': /* number of packets to send */ 283 case 'n': /* no HTML */
275 if (is_intnonneg (optarg)) 284 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; 285 break;
283 case 'L': /* show HTML */ 286 case 'L': /* show HTML */
284 display_html = true; 287 result.config.display_html = true;
285 break; 288 break;
286 case 'c': 289 case 'c':
287 get_threshold (optarg, &crta, &cpl); 290 get_threshold(optarg, &result.config.crta, &result.config.cpl);
288 break; 291 break;
289 case 'w': 292 case 'w':
290 get_threshold (optarg, &wrta, &wpl); 293 get_threshold(optarg, &result.config.wrta, &result.config.wpl);
291 break; 294 break;
292 } 295 }
293 } 296 }
294 297
295 c = optind; 298 int arg_counter = optind;
296 if (c == argc) 299 if (arg_counter == argc) {
297 return validate_arguments (); 300 return validate_arguments(result);
301 }
298 302
299 if (addresses[0] == NULL) { 303 if (result.config.addresses[0] == NULL) {
300 if (!is_host (argv[c])) { 304 if (!is_host(argv[arg_counter])) {
301 usage2 (_("Invalid hostname/address"), argv[c]); 305 usage2(_("Invalid hostname/address"), argv[arg_counter]);
302 } else { 306 } else {
303 addresses[0] = argv[c++]; 307 result.config.addresses[0] = argv[arg_counter++];
304 n_addresses++; 308 result.config.n_addresses++;
305 if (c == argc) 309 if (arg_counter == argc) {
306 return validate_arguments (); 310 return validate_arguments(result);
311 }
307 } 312 }
308 } 313 }
309 314
310 if (wpl == UNKNOWN_PACKET_LOSS) { 315 if (result.config.wpl == UNKNOWN_PACKET_LOSS) {
311 if (!is_intpercent (argv[c])) { 316 if (!is_intpercent(argv[arg_counter])) {
312 printf (_("<wpl> (%s) must be an integer percentage\n"), argv[c]); 317 printf(_("<wpl> (%s) must be an integer percentage\n"), argv[arg_counter]);
313 return ERROR; 318 result.errorcode = ERROR;
314 } else { 319 return result;
315 wpl = atoi (argv[c++]); 320 }
316 if (c == argc) 321 result.config.wpl = atoi(argv[arg_counter++]);
317 return validate_arguments (); 322 if (arg_counter == argc) {
323 return validate_arguments(result);
318 } 324 }
319 } 325 }
320 326
321 if (cpl == UNKNOWN_PACKET_LOSS) { 327 if (result.config.cpl == UNKNOWN_PACKET_LOSS) {
322 if (!is_intpercent (argv[c])) { 328 if (!is_intpercent(argv[arg_counter])) {
323 printf (_("<cpl> (%s) must be an integer percentage\n"), argv[c]); 329 printf(_("<cpl> (%s) must be an integer percentage\n"), argv[arg_counter]);
324 return ERROR; 330 result.errorcode = ERROR;
325 } else { 331 return result;
326 cpl = atoi (argv[c++]); 332 }
327 if (c == argc) 333 result.config.cpl = atoi(argv[arg_counter++]);
328 return validate_arguments (); 334 if (arg_counter == argc) {
335 return validate_arguments(result);
329 } 336 }
330 } 337 }
331 338
332 if (wrta < 0.0) { 339 if (result.config.wrta < 0.0) {
333 if (is_negative (argv[c])) { 340 if (is_negative(argv[arg_counter])) {
334 printf (_("<wrta> (%s) must be a non-negative number\n"), argv[c]); 341 printf(_("<wrta> (%s) must be a non-negative number\n"), argv[arg_counter]);
335 return ERROR; 342 result.errorcode = ERROR;
336 } else { 343 return result;
337 wrta = atof (argv[c++]); 344 }
338 if (c == argc) 345 result.config.wrta = atof(argv[arg_counter++]);
339 return validate_arguments (); 346 if (arg_counter == argc) {
347 return validate_arguments(result);
340 } 348 }
341 } 349 }
342 350
343 if (crta < 0.0) { 351 if (result.config.crta < 0.0) {
344 if (is_negative (argv[c])) { 352 if (is_negative(argv[arg_counter])) {
345 printf (_("<crta> (%s) must be a non-negative number\n"), argv[c]); 353 printf(_("<crta> (%s) must be a non-negative number\n"), argv[arg_counter]);
346 return ERROR; 354 result.errorcode = ERROR;
347 } else { 355 return result;
348 crta = atof (argv[c++]); 356 }
349 if (c == argc) 357 result.config.crta = atof(argv[arg_counter++]);
350 return validate_arguments (); 358 if (arg_counter == argc) {
359 return validate_arguments(result);
351 } 360 }
352 } 361 }
353 362
354 if (max_packets == -1) { 363 if (result.config.max_packets == -1) {
355 if (is_intnonneg (argv[c])) { 364 if (is_intnonneg(argv[arg_counter])) {
356 max_packets = atoi (argv[c++]); 365 result.config.max_packets = atoi(argv[arg_counter++]);
357 } else { 366 } else {
358 printf (_("<max_packets> (%s) must be a non-negative number\n"), argv[c]); 367 printf(_("<max_packets> (%s) must be a non-negative number\n"), argv[arg_counter]);
359 return ERROR; 368 result.errorcode = ERROR;
369 return result;
360 } 370 }
361 } 371 }
362 372
363 return validate_arguments (); 373 return validate_arguments(result);
364} 374}
365 375
366 376int get_threshold(char *arg, double *trta, int *tpl) {
367 377 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; 378 return OK;
373 else if (strpbrk (arg, ",:") && strstr (arg, "%") && sscanf (arg, "%f%*[:,]%d%%", trta, tpl) == 2) 379 }
380
381 if (strpbrk(arg, ",:") && strstr(arg, "%") && sscanf(arg, "%lf%*[:,]%d%%", trta, tpl) == 2) {
374 return OK; 382 return OK;
375 else if (strstr (arg, "%") && sscanf (arg, "%d%%", tpl) == 1) 383 }
384
385 if (strstr(arg, "%") && sscanf(arg, "%d%%", tpl) == 1) {
376 return OK; 386 return OK;
387 }
377 388
378 usage2 (_("%s: Warning threshold must be integer or percentage!\n\n"), arg); 389 usage2(_("%s: Warning threshold must be integer or percentage!\n\n"), arg);
379 return STATE_UNKNOWN; 390 return STATE_UNKNOWN;
380} 391}
381 392
382 393check_ping_config_wrapper validate_arguments(check_ping_config_wrapper config_wrapper) {
383 394 if (config_wrapper.config.wrta < 0.0) {
384int 395 printf(_("<wrta> was not set\n"));
385validate_arguments () 396 config_wrapper.errorcode = ERROR;
386{ 397 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 } 398 }
394 else if (crta < 0.0) { 399
395 printf (_("<crta> was not set\n")); 400 if (config_wrapper.config.crta < 0.0) {
396 return ERROR; 401 printf(_("<crta> was not set\n"));
402 config_wrapper.errorcode = ERROR;
403 return config_wrapper;
397 } 404 }
398 else if (wpl == UNKNOWN_PACKET_LOSS) { 405
399 printf (_("<wpl> was not set\n")); 406 if (config_wrapper.config.wpl == UNKNOWN_PACKET_LOSS) {
400 return ERROR; 407 printf(_("<wpl> was not set\n"));
408 config_wrapper.errorcode = ERROR;
409 return config_wrapper;
401 } 410 }
402 else if (cpl == UNKNOWN_PACKET_LOSS) { 411
403 printf (_("<cpl> was not set\n")); 412 if (config_wrapper.config.cpl == UNKNOWN_PACKET_LOSS) {
404 return ERROR; 413 printf(_("<cpl> was not set\n"));
414 config_wrapper.errorcode = ERROR;
415 return config_wrapper;
405 } 416 }
406 else if (wrta > crta) { 417
407 printf (_("<wrta> (%f) cannot be larger than <crta> (%f)\n"), wrta, crta); 418 if (config_wrapper.config.wrta > config_wrapper.config.crta) {
408 return ERROR; 419 printf(_("<wrta> (%f) cannot be larger than <crta> (%f)\n"), config_wrapper.config.wrta,
420 config_wrapper.config.crta);
421 config_wrapper.errorcode = ERROR;
422 return config_wrapper;
409 } 423 }
410 else if (wpl > cpl) { 424
411 printf (_("<wpl> (%d) cannot be larger than <cpl> (%d)\n"), wpl, cpl); 425 if (config_wrapper.config.wpl > config_wrapper.config.cpl) {
412 return ERROR; 426 printf(_("<wpl> (%d) cannot be larger than <cpl> (%d)\n"), config_wrapper.config.wpl,
427 config_wrapper.config.cpl);
428 config_wrapper.errorcode = ERROR;
429 return config_wrapper;
413 } 430 }
414 431
415 if (max_packets == -1) 432 if (config_wrapper.config.max_packets == -1) {
416 max_packets = DEFAULT_MAX_PACKETS; 433 config_wrapper.config.max_packets = DEFAULT_MAX_PACKETS;
434 }
417 435
418 max_seconds = crta / 1000.0 * max_packets + max_packets; 436 double max_seconds = (config_wrapper.config.crta / 1000.0 * config_wrapper.config.max_packets) +
419 if (max_seconds > timeout_interval) 437 config_wrapper.config.max_packets;
420 timeout_interval = (int)max_seconds; 438 if (max_seconds > timeout_interval) {
439 timeout_interval = (unsigned int)max_seconds;
440 }
421 441
422 for (i=0; i<n_addresses; i++) { 442 for (size_t i = 0; i < config_wrapper.config.n_addresses; i++) {
423 if (!is_host(addresses[i])) 443 if (!is_host(config_wrapper.config.addresses[i])) {
424 usage2 (_("Invalid hostname/address"), addresses[i]); 444 usage2(_("Invalid hostname/address"), config_wrapper.config.addresses[i]);
445 }
425 } 446 }
426 447
427 if (n_addresses == 0) { 448 if (config_wrapper.config.n_addresses == 0) {
428 usage (_("You must specify a server address or host name")); 449 usage(_("You must specify a server address or host name"));
429 } 450 }
430 451
431 return OK; 452 return config_wrapper;
432} 453}
433 454
455ping_result run_ping(const char *cmd, const char *addr, double crta) {
456 if ((child_process = spopen(cmd)) == NULL) {
457 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd);
458 }
434 459
460 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
461 if (child_stderr == NULL) {
462 printf(_("Cannot open stderr for %s\n"), cmd);
463 }
435 464
436int
437run_ping (const char *cmd, const char *addr)
438{
439 char buf[MAX_INPUT_BUFFER]; 465 char buf[MAX_INPUT_BUFFER];
440 int result = STATE_UNKNOWN; 466 ping_result result = {
441 int match; 467 .state = STATE_UNKNOWN,
442 468 .packet_loss = UNKNOWN_PACKET_LOSS,
443 if ((child_process = spopen (cmd)) == NULL) 469 .round_trip_average = UNKNOWN_TRIP_TIME,
444 die (STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd); 470 };
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 471
452 if (verbose >= 3) 472 while (fgets(buf, MAX_INPUT_BUFFER - 1, child_process)) {
473 if (verbose >= 3) {
453 printf("Output: %s", buf); 474 printf("Output: %s", buf);
475 }
454 476
455 result = max_state (result, error_scan (buf, addr)); 477 result.state = max_state(result.state, error_scan(buf, addr));
456 478
457 /* get the percent loss statistics */ 479 /* get the percent loss statistics */
458 match = 0; 480 int match = 0;
459 if((sscanf(buf,"%*d packets transmitted, %*d packets received, +%*d errors, %d%% packet loss%n",&pl,&match) && match) || 481 if ((sscanf(
460 (sscanf(buf,"%*d packets transmitted, %*d packets received, +%*d duplicates, %d%% packet loss%n",&pl,&match) && match) || 482 buf,
461 (sscanf(buf,"%*d packets transmitted, %*d received, +%*d duplicates, %d%% packet loss%n",&pl,&match) && match) || 483 "%*d packets transmitted, %*d packets received, +%*d errors, %d%% packet loss%n",
462 (sscanf(buf,"%*d packets transmitted, %*d packets received, %d%% packet loss%n",&pl,&match) && match) || 484 &result.packet_loss, &match) == 1 &&
463 (sscanf(buf,"%*d packets transmitted, %*d packets received, %d%% loss, time%n",&pl,&match) && match) || 485 match) ||
464 (sscanf(buf,"%*d packets transmitted, %*d received, %d%% loss, time%n",&pl,&match) && match) || 486 (sscanf(buf,
465 (sscanf(buf,"%*d packets transmitted, %*d received, %d%% packet loss, time%n",&pl,&match) && match) || 487 "%*d packets transmitted, %*d packets received, +%*d duplicates, %d%% packet "
466 (sscanf(buf,"%*d packets transmitted, %*d received, +%*d errors, %d%% packet loss%n",&pl,&match) && match) || 488 "loss%n",
467 (sscanf(buf,"%*d packets transmitted %*d received, +%*d errors, %d%% packet loss%n",&pl,&match) && match) || 489 &result.packet_loss, &match) == 1 &&
468 (sscanf(buf,"%*[^(](%d%% %*[^)])%n",&pl,&match) && match) 490 match) ||
469 ) 491 (sscanf(buf,
492 "%*d packets transmitted, %*d received, +%*d duplicates, %d%% packet loss%n",
493 &result.packet_loss, &match) == 1 &&
494 match) ||
495 (sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% packet loss%n",
496 &result.packet_loss, &match) == 1 &&
497 match) ||
498 (sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% loss, time%n",
499 &result.packet_loss, &match) == 1 &&
500 match) ||
501 (sscanf(buf, "%*d packets transmitted, %*d received, %d%% loss, time%n",
502 &result.packet_loss, &match) == 1 &&
503 match) ||
504 (sscanf(buf, "%*d packets transmitted, %*d received, %d%% packet loss, time%n",
505 &result.packet_loss, &match) == 1 &&
506 match) == 1 ||
507 (sscanf(buf, "%*d packets transmitted, %*d received, +%*d errors, %d%% packet loss%n",
508 &result.packet_loss, &match) == 1 &&
509 match) ||
510 (sscanf(buf, "%*d packets transmitted %*d received, +%*d errors, %d%% packet loss%n",
511 &result.packet_loss, &match) == 1 &&
512 match) ||
513 (sscanf(buf, "%*[^(](%d%% %*[^)])%n", &result.packet_loss, &match) == 1 && match)) {
470 continue; 514 continue;
515 }
471 516
472 /* get the round trip average */ 517 /* get the round trip average */
473 else 518 if ((sscanf(buf, "round-trip min/avg/max = %*f/%lf/%*f%n", &result.round_trip_average,
474 if((sscanf(buf,"round-trip min/avg/max = %*f/%f/%*f%n",&rta,&match) && match) || 519 &match) == 1 &&
475 (sscanf(buf,"round-trip min/avg/max/mdev = %*f/%f/%*f/%*f%n",&rta,&match) && match) || 520 match) ||
476 (sscanf(buf,"round-trip min/avg/max/sdev = %*f/%f/%*f/%*f%n",&rta,&match) && match) || 521 (sscanf(buf, "round-trip min/avg/max/mdev = %*f/%lf/%*f/%*f%n",
477 (sscanf(buf,"round-trip min/avg/max/stddev = %*f/%f/%*f/%*f%n",&rta,&match) && match) || 522 &result.round_trip_average, &match) == 1 &&
478 (sscanf(buf,"round-trip min/avg/max/std-dev = %*f/%f/%*f/%*f%n",&rta,&match) && match) || 523 match) ||
479 (sscanf(buf,"round-trip (ms) min/avg/max = %*f/%f/%*f%n",&rta,&match) && match) || 524 (sscanf(buf, "round-trip min/avg/max/sdev = %*f/%lf/%*f/%*f%n",
480 (sscanf(buf,"round-trip (ms) min/avg/max/stddev = %*f/%f/%*f/%*f%n",&rta,&match) && match) || 525 &result.round_trip_average, &match) == 1 &&
481 (sscanf(buf,"rtt min/avg/max/mdev = %*f/%f/%*f/%*f ms%n",&rta,&match) && match) || 526 match) ||
482 (sscanf(buf, "%*[^=] = %*fms, %*[^=] = %*fms, %*[^=] = %fms%n", &rta, &match) && match) 527 (sscanf(buf, "round-trip min/avg/max/stddev = %*f/%lf/%*f/%*f%n",
483 ) 528 &result.round_trip_average, &match) == 1 &&
529 match) ||
530 (sscanf(buf, "round-trip min/avg/max/std-dev = %*f/%lf/%*f/%*f%n",
531 &result.round_trip_average, &match) == 1 &&
532 match) ||
533 (sscanf(buf, "round-trip (ms) min/avg/max = %*f/%lf/%*f%n", &result.round_trip_average,
534 &match) == 1 &&
535 match) ||
536 (sscanf(buf, "round-trip (ms) min/avg/max/stddev = %*f/%lf/%*f/%*f%n",
537 &result.round_trip_average, &match) == 1 &&
538 match) ||
539 (sscanf(buf, "rtt min/avg/max/mdev = %*f/%lf/%*f/%*f ms%n", &result.round_trip_average,
540 &match) == 1 &&
541 match) ||
542 (sscanf(buf, "%*[^=] = %*fms, %*[^=] = %*fms, %*[^=] = %lfms%n",
543 &result.round_trip_average, &match) == 1 &&
544 match)) {
484 continue; 545 continue;
546 }
485 } 547 }
486 548
487 /* this is needed because there is no rta if all packets are lost */ 549 /* this is needed because there is no rta if all packets are lost */
488 if (pl == 100) 550 if (result.packet_loss == 100) {
489 rta = crta; 551 result.round_trip_average = crta;
552 }
490 553
491 /* check stderr, setting at least WARNING if there is output here */ 554 /* check stderr, setting at least WARNING if there is output here */
492 /* Add warning into warn_text */ 555 /* Add warning into warn_text */
493 while (fgets (buf, MAX_INPUT_BUFFER - 1, child_stderr)) { 556 while (fgets(buf, MAX_INPUT_BUFFER - 1, child_stderr)) {
494 if ( 557 if (!strstr(buf, "WARNING - no SO_TIMESTAMP support, falling back to SIOCGSTAMP") &&
495 ! strstr(buf,"WARNING - no SO_TIMESTAMP support, falling back to SIOCGSTAMP") 558 !strstr(buf, "Warning: time of day goes back")
496 && ! strstr(buf,"Warning: time of day goes back")
497 559
498 ) { 560 ) {
499 if (verbose >= 3) { 561 if (verbose >= 3) {
500 printf("Got stderr: %s", buf); 562 printf("Got stderr: %s", buf);
501 } 563 }
502 if ((result=error_scan(buf, addr)) == STATE_OK) { 564 if ((result.state = error_scan(buf, addr)) == STATE_OK) {
503 result = STATE_WARNING; 565 result.state = STATE_WARNING;
504 if (warn_text == NULL) { 566 if (warn_text == NULL) {
505 warn_text = strdup(_("System call sent warnings to stderr ")); 567 warn_text = strdup(_("System call sent warnings to stderr "));
506 } else { 568 } else {
507 xasprintf(&warn_text, "%s %s", warn_text, _("System call sent warnings to stderr ")); 569 xasprintf(&warn_text, "%s %s", warn_text,
570 _("System call sent warnings to stderr "));
508 } 571 }
509 } 572 }
510 } 573 }
511 } 574 }
512 575
513 (void) fclose (child_stderr); 576 (void)fclose(child_stderr);
514 577
578 spclose(child_process);
515 579
516 spclose (child_process); 580 if (warn_text == NULL) {
517
518 if (warn_text == NULL)
519 warn_text = strdup(""); 581 warn_text = strdup("");
582 }
520 583
521 return result; 584 return result;
522} 585}
523 586
587mp_state_enum error_scan(char buf[MAX_INPUT_BUFFER], const char *addr) {
588 if (strstr(buf, "Network is unreachable") || strstr(buf, "Destination Net Unreachable") ||
589 strstr(buf, "No route")) {
590 die(STATE_CRITICAL, _("CRITICAL - Network Unreachable (%s)\n"), addr);
591 } else if (strstr(buf, "Destination Host Unreachable") || strstr(buf, "Address unreachable")) {
592 die(STATE_CRITICAL, _("CRITICAL - Host Unreachable (%s)\n"), addr);
593 } else if (strstr(buf, "Destination Port Unreachable") || strstr(buf, "Port unreachable")) {
594 die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Port Unreachable (%s)\n"), addr);
595 } else if (strstr(buf, "Destination Protocol Unreachable")) {
596 die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Protocol Unreachable (%s)\n"), addr);
597 } else if (strstr(buf, "Destination Net Prohibited")) {
598 die(STATE_CRITICAL, _("CRITICAL - Network Prohibited (%s)\n"), addr);
599 } else if (strstr(buf, "Destination Host Prohibited")) {
600 die(STATE_CRITICAL, _("CRITICAL - Host Prohibited (%s)\n"), addr);
601 } else if (strstr(buf, "Packet filtered") || strstr(buf, "Administratively prohibited")) {
602 die(STATE_CRITICAL, _("CRITICAL - Packet Filtered (%s)\n"), addr);
603 } else if (strstr(buf, "unknown host")) {
604 die(STATE_CRITICAL, _("CRITICAL - Host not found (%s)\n"), addr);
605 } else if (strstr(buf, "Time to live exceeded") || strstr(buf, "Time exceeded")) {
606 die(STATE_CRITICAL, _("CRITICAL - Time to live exceeded (%s)\n"), addr);
607 } else if (strstr(buf, "Destination unreachable: ")) {
608 die(STATE_CRITICAL, _("CRITICAL - Destination Unreachable (%s)\n"), addr);
609 }
524 610
611 if (strstr(buf, "(DUP!)") || strstr(buf, "DUPLICATES FOUND")) {
612 if (warn_text == NULL) {
613 warn_text = strdup(_(WARN_DUPLICATES));
614 } else if (!strstr(warn_text, _(WARN_DUPLICATES)) &&
615 xasprintf(&warn_text, "%s %s", warn_text, _(WARN_DUPLICATES)) == -1) {
616 die(STATE_UNKNOWN, _("Unable to realloc warn_text\n"));
617 }
618 return STATE_WARNING;
619 }
525 620
526int 621 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} 622}
564 623
624void print_help(void) {
625 print_revision(progname, NP_VERSION);
565 626
627 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
628 printf(COPYRIGHT, copyright, email);
566 629
567void 630 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 631
577 printf ("\n\n"); 632 printf("\n\n");
578 633
579 print_usage (); 634 print_usage();
580 635
581 printf (UT_HELP_VRSN); 636 printf(UT_HELP_VRSN);
582 printf (UT_EXTRA_OPTS); 637 printf(UT_EXTRA_OPTS);
583 638
584 printf (UT_IPv46); 639 printf(UT_IPv46);
585 640
586 printf (" %s\n", "-H, --hostname=HOST"); 641 printf(" %s\n", "-H, --hostname=HOST");
587 printf (" %s\n", _("host to ping")); 642 printf(" %s\n", _("host to ping"));
588 printf (" %s\n", "-w, --warning=THRESHOLD"); 643 printf(" %s\n", "-w, --warning=THRESHOLD");
589 printf (" %s\n", _("warning threshold pair")); 644 printf(" %s\n", _("warning threshold pair"));
590 printf (" %s\n", "-c, --critical=THRESHOLD"); 645 printf(" %s\n", "-c, --critical=THRESHOLD");
591 printf (" %s\n", _("critical threshold pair")); 646 printf(" %s\n", _("critical threshold pair"));
592 printf (" %s\n", "-p, --packets=INTEGER"); 647 printf(" %s\n", "-p, --packets=INTEGER");
593 printf (" %s ", _("number of ICMP ECHO packets to send")); 648 printf(" %s ", _("number of ICMP ECHO packets to send"));
594 printf (_("(Default: %d)\n"), DEFAULT_MAX_PACKETS); 649 printf(_("(Default: %d)\n"), DEFAULT_MAX_PACKETS);
595 printf (" %s\n", "-L, --link"); 650 printf(" %s\n", "-L, --link");
596 printf (" %s\n", _("show HTML in the plugin output (obsoleted by urlize)")); 651 printf(" %s\n", _("show HTML in the plugin output (obsoleted by urlize)"));
597 652
598 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 653 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
599 654
600 printf ("\n"); 655 printf("\n");
601 printf ("%s\n", _("THRESHOLD is <rta>,<pl>% where <rta> is the round trip average travel")); 656 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")); 657 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.")); 658 printf("%s\n", _("percentage of packet loss to trigger an alarm state."));
604 659
605 printf ("\n"); 660 printf("\n");
606 printf ("%s\n", _("This plugin uses the ping command to probe the specified host for packet loss")); 661 printf("%s\n",
607 printf ("%s\n", _("(percentage) and round trip average (milliseconds). It can produce HTML output")); 662 _("This plugin uses the ping command to probe the specified host for packet loss"));
608 printf ("%s\n", _("linking to a traceroute CGI contributed by Ian Cass. The CGI can be found in")); 663 printf("%s\n",
609 printf ("%s\n", _("the contrib area of the downloads section at http://www.nagios.org/")); 664 _("(percentage) and round trip average (milliseconds). It can produce HTML output."));
610 665
611 printf (UT_SUPPORT); 666 printf(UT_SUPPORT);
612} 667}
613 668
614void 669void print_usage(void) {
615print_usage (void) 670 printf("%s\n", _("Usage:"));
616{ 671 printf("%s -H <host_address> -w <wrta>,<wpl>%% -c <crta>,<cpl>%%\n", progname);
617 printf ("%s\n", _("Usage:")); 672 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} 673}
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..ae6e9c23 100644
--- a/plugins/check_procs.c
+++ b/plugins/check_procs.c
@@ -1,357 +1,339 @@
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 "
241 procs, procuid, procvsz, procrss, 201 "prog=%s args=%s\n",
242 procpid, procppid, procpcpu, procstat, 202 procs, procuid, procvsz, procrss, procpid, procppid, procpcpu, procstat,
243 procetime, procprog, procargs); 203 procetime, procprog, procargs);
204 }
244 205
245 /* Ignore self */ 206 /* Ignore self */
246 if ((usepid && mypid == procpid) || 207 int ret = 0;
247 ( ((!usepid) && ((ret = stat_exe(procpid, &statbuf) != -1) && statbuf.st_dev == mydev && statbuf.st_ino == myino)) || 208 if ((config.usepid && mypid == procpid) ||
248 (ret == -1 && errno == ENOENT)) 209 (((!config.usepid) && ((ret = stat_exe(procpid, &statbuf) != -1) &&
249 ) { 210 statbuf.st_dev == mydev && statbuf.st_ino == myino)) ||
250 if (verbose >= 3) 211 (ret == -1 && errno == ENOENT))) {
251 printf("not considering - is myself or gone\n"); 212 if (verbose >= 3) {
213 printf("not considering - is myself or gone\n");
214 }
252 continue; 215 continue;
253 } 216 }
254 /* Ignore parent*/ 217 /* Ignore parent*/
255 else if (myppid == procpid) { 218 if (myppid == procpid) {
256 if (verbose >= 3) 219 if (verbose >= 3) {
257 printf("not considering - is parent\n"); 220 printf("not considering - is parent\n");
221 }
258 continue; 222 continue;
259 } 223 }
260 224
261 /* Ignore our own children */ 225 /* Ignore our own children */
262 if (procppid == mypid) { 226 if (procppid == mypid) {
263 if (verbose >= 3) 227 if (verbose >= 3) {
264 printf("not considering - is our child\n"); 228 printf("not considering - is our child\n");
229 }
265 continue; 230 continue;
266 } 231 }
267 232
268 /* Ignore excluded processes by name */ 233 /* Ignore excluded processes by name */
269 if(options & EXCLUDE_PROGS) { 234 if (config.options & EXCLUDE_PROGS) {
270 int found = 0; 235 bool found = false;
271 int i = 0; 236 for (int i = 0; i < (config.exclude_progs_counter); i++) {
272 237 if (!strcmp(procprog, config.exclude_progs_arr[i])) {
273 for(i=0; i < (exclude_progs_counter); i++) { 238 found = true;
274 if(!strcmp(procprog, exclude_progs_arr[i])) { 239 }
275 found = 1; 240 }
276 } 241 if (!found) {
277 } 242 resultsum |= EXCLUDE_PROGS;
278 if(found == 0) { 243 } else {
279 resultsum |= EXCLUDE_PROGS; 244 if (verbose >= 3) {
280 } else 245 printf("excluding - by ignorelist\n");
281 { 246 }
282 if(verbose >= 3) 247 }
283 printf("excluding - by ignorelist\n");
284 }
285 } 248 }
286 249
287 /* filter kernel threads (children of KTHREAD_PARENT)*/ 250 /* filter kernel threads (children of KTHREAD_PARENT)*/
288 /* TODO adapt for other OSes than GNU/Linux 251 /* TODO adapt for other OSes than GNU/Linux
289 sorry for not doing that, but I've no other OSes to test :-( */ 252 sorry for not doing that, but I've no other OSes to test :-( */
290 if (kthread_filter == 1) { 253 if (config.kthread_filter) {
291 /* get pid KTHREAD_PARENT */ 254 /* get pid KTHREAD_PARENT */
292 if (kthread_ppid == 0 && !strcmp(procprog, KTHREAD_PARENT) ) 255 if (kthread_ppid == 0 && !strcmp(procprog, KTHREAD_PARENT)) {
293 kthread_ppid = procpid; 256 kthread_ppid = procpid;
257 }
294 258
295 if (kthread_ppid == procppid) { 259 if (kthread_ppid == procppid) {
296 if (verbose >= 2) 260 if (verbose >= 2) {
297 printf ("Ignore kernel thread: pid=%d ppid=%d prog=%s args=%s\n", procpid, procppid, procprog, procargs); 261 printf("Ignore kernel thread: pid=%d ppid=%d prog=%s args=%s\n", procpid,
262 procppid, procprog, procargs);
263 }
298 continue; 264 continue;
299 } 265 }
300 } 266 }
301 267
302 if ((options & STAT) && (strstr (procstat, statopts))) 268 if ((config.options & STAT) && (strstr(procstat, config.statopts))) {
303 resultsum |= STAT; 269 resultsum |= STAT;
304 if ((options & ARGS) && procargs && (strstr (procargs, args) != NULL)) 270 }
271 if ((config.options & ARGS) && procargs && (strstr(procargs, config.args) != NULL)) {
305 resultsum |= ARGS; 272 resultsum |= ARGS;
306 if ((options & EREG_ARGS) && procargs && (regexec(&re_args, procargs, (size_t) 0, NULL, 0) == 0)) 273 }
274 if ((config.options & EREG_ARGS) && procargs &&
275 (regexec(&config.re_args, procargs, (size_t)0, NULL, 0) == 0)) {
307 resultsum |= EREG_ARGS; 276 resultsum |= EREG_ARGS;
308 if ((options & PROG) && procprog && (strcmp (prog, procprog) == 0)) 277 }
278 if ((config.options & PROG) && procprog && (strcmp(config.prog, procprog) == 0)) {
309 resultsum |= PROG; 279 resultsum |= PROG;
310 if ((options & PPID) && (procppid == ppid)) 280 }
281 if ((config.options & PPID) && (procppid == config.ppid)) {
311 resultsum |= PPID; 282 resultsum |= PPID;
312 if ((options & USER) && (procuid == uid)) 283 }
284 if ((config.options & USER) && (procuid == config.uid)) {
313 resultsum |= USER; 285 resultsum |= USER;
314 if ((options & VSZ) && (procvsz >= vsz)) 286 }
287 if ((config.options & VSZ) && (procvsz >= config.vsz)) {
315 resultsum |= VSZ; 288 resultsum |= VSZ;
316 if ((options & RSS) && (procrss >= rss)) 289 }
290 if ((config.options & RSS) && (procrss >= config.rss)) {
317 resultsum |= RSS; 291 resultsum |= RSS;
318 if ((options & PCPU) && (procpcpu >= pcpu)) 292 }
293 if ((config.options & PCPU) && (procpcpu >= config.pcpu)) {
319 resultsum |= PCPU; 294 resultsum |= PCPU;
295 }
320 296
321 found++; 297 found++;
322 298
323 /* Next line if filters not matched */ 299 /* Next line if filters not matched */
324 if (!(options == resultsum || options == ALL)) 300 if (!(config.options == resultsum || config.options == ALL)) {
325 continue; 301 continue;
302 }
326 303
327 procs++; 304 procs++;
328 if (verbose >= 2) { 305 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", 306 printf("Matched: uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s "
330 procuid, procvsz, procrss, 307 "prog=%s args=%s\n",
331 procpid, procppid, procpcpu, procstat, 308 procuid, procvsz, procrss, procpid, procppid, procpcpu, procstat, procetime,
332 procetime, procprog, procargs); 309 procprog, procargs);
333 } 310 }
334 311
335 if (metric == METRIC_VSZ) 312 mp_state_enum temporary_result = STATE_OK;
336 i = get_status ((double)procvsz, procs_thresholds); 313 if (config.metric == METRIC_VSZ) {
337 else if (metric == METRIC_RSS) 314 temporary_result = get_status((double)procvsz, config.procs_thresholds);
338 i = get_status ((double)procrss, procs_thresholds); 315 } else if (config.metric == METRIC_RSS) {
316 temporary_result = get_status((double)procrss, config.procs_thresholds);
317 }
339 /* TODO? float thresholds for --metric=CPU */ 318 /* TODO? float thresholds for --metric=CPU */
340 else if (metric == METRIC_CPU) 319 else if (config.metric == METRIC_CPU) {
341 i = get_status (procpcpu, procs_thresholds); 320 temporary_result = get_status(procpcpu, config.procs_thresholds);
342 else if (metric == METRIC_ELAPSED) 321 } else if (config.metric == METRIC_ELAPSED) {
343 i = get_status ((double)procseconds, procs_thresholds); 322 temporary_result = get_status((double)procseconds, config.procs_thresholds);
323 }
344 324
345 if (metric != METRIC_PROCS) { 325 if (config.metric != METRIC_PROCS) {
346 if (i == STATE_WARNING) { 326 if (temporary_result == STATE_WARNING) {
347 warn++; 327 warn++;
348 xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog); 328 xasprintf(&config.fails, "%s%s%s", config.fails,
349 result = max_state (result, i); 329 (strcmp(config.fails, "") ? ", " : ""), procprog);
330 result = max_state(result, temporary_result);
350 } 331 }
351 if (i == STATE_CRITICAL) { 332 if (temporary_result == STATE_CRITICAL) {
352 crit++; 333 crit++;
353 xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog); 334 xasprintf(&config.fails, "%s%s%s", config.fails,
354 result = max_state (result, i); 335 (strcmp(config.fails, "") ? ", " : ""), procprog);
336 result = max_state(result, temporary_result);
355 } 337 }
356 } 338 }
357 } 339 }
@@ -361,339 +343,366 @@ main (int argc, char **argv)
361 } 343 }
362 } 344 }
363 345
364 if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */ 346 if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */
365 printf (_("Unable to read output\n")); 347 printf(_("Unable to read output\n"));
366 return STATE_UNKNOWN; 348 return STATE_UNKNOWN;
367 } 349 }
368 350
369 if ( result == STATE_UNKNOWN ) 351 if (result == STATE_UNKNOWN) {
370 result = STATE_OK; 352 result = STATE_OK;
353 }
371 354
372 /* Needed if procs found, but none match filter */ 355 /* Needed if procs found, but none match filter */
373 if ( metric == METRIC_PROCS ) { 356 if (config.metric == METRIC_PROCS) {
374 result = max_state (result, get_status ((double)procs, procs_thresholds) ); 357 result = max_state(result, get_status((double)procs, config.procs_thresholds));
375 } 358 }
376 359
377 if ( result == STATE_OK ) { 360 if (result == STATE_OK) {
378 printf ("%s %s: ", metric_name, _("OK")); 361 printf("%s %s: ", config.metric_name, _("OK"));
379 } else if (result == STATE_WARNING) { 362 } else if (result == STATE_WARNING) {
380 printf ("%s %s: ", metric_name, _("WARNING")); 363 printf("%s %s: ", config.metric_name, _("WARNING"));
381 if ( metric != METRIC_PROCS ) { 364 if (config.metric != METRIC_PROCS) {
382 printf (_("%d warn out of "), warn); 365 printf(_("%d warn out of "), warn);
383 } 366 }
384 } else if (result == STATE_CRITICAL) { 367 } else if (result == STATE_CRITICAL) {
385 printf ("%s %s: ", metric_name, _("CRITICAL")); 368 printf("%s %s: ", config.metric_name, _("CRITICAL"));
386 if (metric != METRIC_PROCS) { 369 if (config.metric != METRIC_PROCS) {
387 printf (_("%d crit, %d warn out of "), crit, warn); 370 printf(_("%d crit, %d warn out of "), crit, warn);
388 } 371 }
389 } 372 }
390 printf (ngettext ("%d process", "%d processes", (unsigned long) procs), procs); 373 printf(ngettext("%d process", "%d processes", (unsigned long)procs), procs);
391 374
392 if (strcmp(fmt,"") != 0) { 375 if (strcmp(config.fmt, "") != 0) {
393 printf (_(" with %s"), fmt); 376 printf(_(" with %s"), config.fmt);
394 } 377 }
395 378
396 if ( verbose >= 1 && strcmp(fails,"") ) 379 if (verbose >= 1 && strcmp(config.fails, "")) {
397 printf (" [%s]", fails); 380 printf(" [%s]", config.fails);
381 }
398 382
399 if (metric == METRIC_PROCS) 383 if (config.metric == METRIC_PROCS) {
400 printf (" | procs=%d;%s;%s;0;", procs, 384 printf(" | procs=%d;%s;%s;0;", procs, config.warning_range ? config.warning_range : "",
401 warning_range ? warning_range : "", 385 config.critical_range ? config.critical_range : "");
402 critical_range ? critical_range : ""); 386 } else {
403 else 387 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); 388 }
405 389
406 printf ("\n"); 390 printf("\n");
407 return result; 391 exit(result);
408} 392}
409 393
410
411
412/* process command-line arguments */ 394/* process command-line arguments */
413int 395check_procs_config_wrapper process_arguments(int argc, char **argv) {
414process_arguments (int argc, char **argv) 396 static struct option longopts[] = {{"warning", required_argument, 0, 'w'},
415{ 397 {"critical", required_argument, 0, 'c'},
416 int c = 1; 398 {"metric", required_argument, 0, 'm'},
417 char *user; 399 {"timeout", required_argument, 0, 't'},
418 struct passwd *pw; 400 {"status", required_argument, 0, 's'},
419 int option = 0; 401 {"ppid", required_argument, 0, 'p'},
420 int err; 402 {"user", required_argument, 0, 'u'},
421 int cflags = REG_NOSUB | REG_EXTENDED; 403 {"command", required_argument, 0, 'C'},
422 char errbuf[MAX_INPUT_BUFFER]; 404 {"vsz", required_argument, 0, 'z'},
423 char *temp_string; 405 {"rss", required_argument, 0, 'r'},
424 int i=0; 406 {"pcpu", required_argument, 0, 'P'},
425 static struct option longopts[] = { 407 {"elapsed", required_argument, 0, 'e'},
426 {"warning", required_argument, 0, 'w'}, 408 {"argument-array", required_argument, 0, 'a'},
427 {"critical", required_argument, 0, 'c'}, 409 {"help", no_argument, 0, 'h'},
428 {"metric", required_argument, 0, 'm'}, 410 {"version", no_argument, 0, 'V'},
429 {"timeout", required_argument, 0, 't'}, 411 {"verbose", no_argument, 0, 'v'},
430 {"status", required_argument, 0, 's'}, 412 {"ereg-argument-array", required_argument, 0, CHAR_MAX + 1},
431 {"ppid", required_argument, 0, 'p'}, 413 {"input-file", required_argument, 0, CHAR_MAX + 2},
432 {"user", required_argument, 0, 'u'}, 414 {"no-kthreads", required_argument, 0, 'k'},
433 {"command", required_argument, 0, 'C'}, 415 {"traditional-filter", no_argument, 0, 'T'},
434 {"vsz", required_argument, 0, 'z'}, 416 {"exclude-process", required_argument, 0, 'X'},
435 {"rss", required_argument, 0, 'r'}, 417 {0, 0, 0, 0}};
436 {"pcpu", required_argument, 0, 'P'}, 418
437 {"elapsed", required_argument, 0, 'e'}, 419 for (int index = 1; index < argc; index++) {
438 {"argument-array", required_argument, 0, 'a'}, 420 if (strcmp("-to", argv[index]) == 0) {
439 {"help", no_argument, 0, 'h'}, 421 strcpy(argv[index], "-t");
440 {"version", no_argument, 0, 'V'}, 422 }
441 {"verbose", no_argument, 0, 'v'}, 423 }
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 424
450 for (c = 1; c < argc; c++) 425 check_procs_config_wrapper result = {
451 if (strcmp ("-to", argv[c]) == 0) 426 .errorcode = OK,
452 strcpy (argv[c], "-t"); 427 .config = check_procs_config_init(),
428 };
453 429
454 while (1) { 430 while (true) {
455 c = getopt_long (argc, argv, "Vvhkt:c:w:p:s:u:C:a:z:r:m:P:T:X:", 431 int option = 0;
456 longopts, &option); 432 int option_index =
433 getopt_long(argc, argv, "Vvhkt:c:w:p:s:u:C:a:z:r:m:P:T:X:", longopts, &option);
457 434
458 if (c == -1 || c == EOF) 435 if (option_index == -1 || option_index == EOF) {
459 break; 436 break;
437 }
460 438
461 switch (c) { 439 switch (option_index) {
462 case '?': /* help */ 440 case '?': /* help */
463 usage5 (); 441 usage5();
464 case 'h': /* help */ 442 case 'h': /* help */
465 print_help (); 443 print_help();
466 exit (STATE_UNKNOWN); 444 exit(STATE_UNKNOWN);
467 case 'V': /* version */ 445 case 'V': /* version */
468 print_revision (progname, NP_VERSION); 446 print_revision(progname, NP_VERSION);
469 exit (STATE_UNKNOWN); 447 exit(STATE_UNKNOWN);
470 case 't': /* timeout period */ 448 case 't': /* timeout period */
471 if (!is_integer (optarg)) 449 if (!is_integer(optarg)) {
472 usage2 (_("Timeout interval must be a positive integer"), optarg); 450 usage2(_("Timeout interval must be a positive integer"), optarg);
473 else 451 } else {
474 timeout_interval = atoi (optarg); 452 timeout_interval = atoi(optarg);
453 }
475 break; 454 break;
476 case 'c': /* critical threshold */ 455 case 'c': /* critical threshold */
477 critical_range = optarg; 456 result.config.critical_range = optarg;
478 break; 457 break;
479 case 'w': /* warning threshold */ 458 case 'w': /* warning threshold */
480 warning_range = optarg; 459 result.config.warning_range = optarg;
481 break; 460 break;
482 case 'p': /* process id */ 461 case 'p': { /* process id */
483 if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) { 462 static char tmp[MAX_INPUT_BUFFER];
484 xasprintf (&fmt, "%s%sPPID = %d", (fmt ? fmt : "") , (options ? ", " : ""), ppid); 463 if (sscanf(optarg, "%d%[^0-9]", &result.config.ppid, tmp) == 1) {
485 options |= PPID; 464 xasprintf(&result.config.fmt, "%s%sPPID = %d",
465 (result.config.fmt ? result.config.fmt : ""),
466 (result.config.options ? ", " : ""), result.config.ppid);
467 result.config.options |= PPID;
486 break; 468 break;
487 } 469 }
488 usage4 (_("Parent Process ID must be an integer!")); 470 usage4(_("Parent Process ID must be an integer!"));
489 case 's': /* status */ 471 }
490 if (statopts) 472 case 's': /* status */
473 if (result.config.statopts) {
491 break; 474 break;
492 else 475 } else {
493 statopts = optarg; 476 result.config.statopts = optarg;
494 xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts); 477 }
495 options |= STAT; 478 xasprintf(&result.config.fmt, _("%s%sSTATE = %s"),
479 (result.config.fmt ? result.config.fmt : ""),
480 (result.config.options ? ", " : ""), result.config.statopts);
481 result.config.options |= STAT;
496 break; 482 break;
497 case 'u': /* user or user id */ 483 case 'u': /* user or user id */ {
498 if (is_integer (optarg)) { 484 struct passwd *pw;
499 uid = atoi (optarg); 485 if (is_integer(optarg)) {
500 pw = getpwuid ((uid_t) uid); 486 result.config.uid = atoi(optarg);
487 pw = getpwuid(result.config.uid);
501 /* check to be sure user exists */ 488 /* check to be sure user exists */
502 if (pw == NULL) 489 if (pw == NULL) {
503 usage2 (_("UID was not found"), optarg); 490 usage2(_("UID was not found"), optarg);
504 } 491 }
505 else { 492 } else {
506 pw = getpwnam (optarg); 493 pw = getpwnam(optarg);
507 /* check to be sure user exists */ 494 /* check to be sure user exists */
508 if (pw == NULL) 495 if (pw == NULL) {
509 usage2 (_("User name was not found"), optarg); 496 usage2(_("User name was not found"), optarg);
497 }
510 /* then get uid */ 498 /* then get uid */
511 uid = pw->pw_uid; 499 result.config.uid = pw->pw_uid;
512 } 500 }
513 user = pw->pw_name; 501
514 xasprintf (&fmt, "%s%sUID = %d (%s)", (fmt ? fmt : ""), (options ? ", " : ""), 502 char *user = pw->pw_name;
515 uid, user); 503 xasprintf(&result.config.fmt, "%s%sUID = %d (%s)",
516 options |= USER; 504 (result.config.fmt ? result.config.fmt : ""),
517 break; 505 (result.config.options ? ", " : ""), result.config.uid, user);
518 case 'C': /* command */ 506 result.config.options |= USER;
507 } break;
508 case 'C': /* command */
519 /* TODO: allow this to be passed in with --metric */ 509 /* TODO: allow this to be passed in with --metric */
520 if (prog) 510 if (result.config.prog) {
521 break; 511 break;
522 else 512 } else {
523 prog = optarg; 513 result.config.prog = optarg;
524 xasprintf (&fmt, _("%s%scommand name '%s'"), (fmt ? fmt : ""), (options ? ", " : ""), 514 }
525 prog); 515 xasprintf(&result.config.fmt, _("%s%scommand name '%s'"),
526 options |= PROG; 516 (result.config.fmt ? result.config.fmt : ""),
517 (result.config.options ? ", " : ""), result.config.prog);
518 result.config.options |= PROG;
527 break; 519 break;
528 case 'X': 520 case 'X':
529 if(exclude_progs) 521 if (result.config.exclude_progs) {
530 break; 522 break;
531 else 523 } else {
532 exclude_progs = optarg; 524 result.config.exclude_progs = optarg;
533 xasprintf (&fmt, _("%s%sexclude progs '%s'"), (fmt ? fmt : ""), (options ? ", " : ""), 525 }
534 exclude_progs); 526 xasprintf(&result.config.fmt, _("%s%sexclude progs '%s'"),
535 char *p = strtok(exclude_progs, ","); 527 (result.config.fmt ? result.config.fmt : ""),
536 528 (result.config.options ? ", " : ""), result.config.exclude_progs);
537 while(p){ 529 char *tmp_pointer = strtok(result.config.exclude_progs, ",");
538 exclude_progs_arr = realloc(exclude_progs_arr, sizeof(char*) * ++exclude_progs_counter); 530
539 exclude_progs_arr[exclude_progs_counter-1] = p; 531 while (tmp_pointer) {
540 p = strtok(NULL, ","); 532 result.config.exclude_progs_arr =
533 realloc(result.config.exclude_progs_arr,
534 sizeof(char *) * ++result.config.exclude_progs_counter);
535 result.config.exclude_progs_arr[result.config.exclude_progs_counter - 1] =
536 tmp_pointer;
537 tmp_pointer = strtok(NULL, ",");
541 } 538 }
542 539
543 options |= EXCLUDE_PROGS; 540 result.config.options |= EXCLUDE_PROGS;
544 break; 541 break;
545 case 'a': /* args (full path name with args) */ 542 case 'a': /* args (full path name with args) */
546 /* TODO: allow this to be passed in with --metric */ 543 /* TODO: allow this to be passed in with --metric */
547 if (args) 544 if (result.config.args) {
548 break; 545 break;
549 else 546 } else {
550 args = optarg; 547 result.config.args = optarg;
551 xasprintf (&fmt, "%s%sargs '%s'", (fmt ? fmt : ""), (options ? ", " : ""), args); 548 }
552 options |= ARGS; 549 xasprintf(&result.config.fmt, "%s%sargs '%s'",
550 (result.config.fmt ? result.config.fmt : ""),
551 (result.config.options ? ", " : ""), result.config.args);
552 result.config.options |= ARGS;
553 break; 553 break;
554 case CHAR_MAX+1: 554 case CHAR_MAX + 1: {
555 err = regcomp(&re_args, optarg, cflags); 555 int cflags = REG_NOSUB | REG_EXTENDED;
556 int err = regcomp(&result.config.re_args, optarg, cflags);
556 if (err != 0) { 557 if (err != 0) {
557 regerror (err, &re_args, errbuf, MAX_INPUT_BUFFER); 558 char errbuf[MAX_INPUT_BUFFER];
558 die (STATE_UNKNOWN, "PROCS %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf); 559 regerror(err, &result.config.re_args, errbuf, MAX_INPUT_BUFFER);
560 die(STATE_UNKNOWN, "PROCS %s: %s - %s\n", _("UNKNOWN"),
561 _("Could not compile regular expression"), errbuf);
559 } 562 }
560 /* Strip off any | within the regex optarg */ 563 /* Strip off any | within the regex optarg */
561 temp_string = strdup(optarg); 564 char *temp_string = strdup(optarg);
562 while(temp_string[i]!='\0'){ 565 int index = 0;
563 if(temp_string[i]=='|') 566 while (temp_string[index] != '\0') {
564 temp_string[i]=','; 567 if (temp_string[index] == '|') {
565 i++; 568 temp_string[index] = ',';
566 } 569 }
567 xasprintf (&fmt, "%s%sregex args '%s'", (fmt ? fmt : ""), (options ? ", " : ""), temp_string); 570 index++;
568 options |= EREG_ARGS; 571 }
569 break; 572 xasprintf(&result.config.fmt, "%s%sregex args '%s'",
570 case 'r': /* RSS */ 573 (result.config.fmt ? result.config.fmt : ""),
571 if (sscanf (optarg, "%d%[^0-9]", &rss, tmp) == 1) { 574 (result.config.options ? ", " : ""), temp_string);
572 xasprintf (&fmt, "%s%sRSS >= %d", (fmt ? fmt : ""), (options ? ", " : ""), rss); 575 result.config.options |= EREG_ARGS;
573 options |= RSS; 576 } break;
577 case 'r': { /* RSS */
578 static char tmp[MAX_INPUT_BUFFER];
579 if (sscanf(optarg, "%d%[^0-9]", &result.config.rss, tmp) == 1) {
580 xasprintf(&result.config.fmt, "%s%sRSS >= %d",
581 (result.config.fmt ? result.config.fmt : ""),
582 (result.config.options ? ", " : ""), result.config.rss);
583 result.config.options |= RSS;
574 break; 584 break;
575 } 585 }
576 usage4 (_("RSS must be an integer!")); 586 usage4(_("RSS must be an integer!"));
577 case 'z': /* VSZ */ 587 }
578 if (sscanf (optarg, "%d%[^0-9]", &vsz, tmp) == 1) { 588 case 'z': { /* VSZ */
579 xasprintf (&fmt, "%s%sVSZ >= %d", (fmt ? fmt : ""), (options ? ", " : ""), vsz); 589 static char tmp[MAX_INPUT_BUFFER];
580 options |= VSZ; 590 if (sscanf(optarg, "%d%[^0-9]", &result.config.vsz, tmp) == 1) {
591 xasprintf(&result.config.fmt, "%s%sVSZ >= %d",
592 (result.config.fmt ? result.config.fmt : ""),
593 (result.config.options ? ", " : ""), result.config.vsz);
594 result.config.options |= VSZ;
581 break; 595 break;
582 } 596 }
583 usage4 (_("VSZ must be an integer!")); 597 usage4(_("VSZ must be an integer!"));
584 case 'P': /* PCPU */ 598 }
599 case 'P': { /* PCPU */
585 /* TODO: -P 1.5.5 is accepted */ 600 /* TODO: -P 1.5.5 is accepted */
586 if (sscanf (optarg, "%f%[^0-9.]", &pcpu, tmp) == 1) { 601 static char tmp[MAX_INPUT_BUFFER];
587 xasprintf (&fmt, "%s%sPCPU >= %.2f", (fmt ? fmt : ""), (options ? ", " : ""), pcpu); 602 if (sscanf(optarg, "%f%[^0-9.]", &result.config.pcpu, tmp) == 1) {
588 options |= PCPU; 603 xasprintf(&result.config.fmt, "%s%sPCPU >= %.2f",
604 (result.config.fmt ? result.config.fmt : ""),
605 (result.config.options ? ", " : ""), result.config.pcpu);
606 result.config.options |= PCPU;
589 break; 607 break;
590 } 608 }
591 usage4 (_("PCPU must be a float!")); 609 usage4(_("PCPU must be a float!"));
610 }
592 case 'm': 611 case 'm':
593 xasprintf (&metric_name, "%s", optarg); 612 xasprintf(&result.config.metric_name, "%s", optarg);
594 if ( strcmp(optarg, "PROCS") == 0) { 613 if (strcmp(optarg, "PROCS") == 0) {
595 metric = METRIC_PROCS; 614 result.config.metric = METRIC_PROCS;
596 break; 615 break;
597 } 616 }
598 else if ( strcmp(optarg, "VSZ") == 0) { 617 if (strcmp(optarg, "VSZ") == 0) {
599 metric = METRIC_VSZ; 618 result.config.metric = METRIC_VSZ;
600 break; 619 break;
601 } 620 }
602 else if ( strcmp(optarg, "RSS") == 0 ) { 621 if (strcmp(optarg, "RSS") == 0) {
603 metric = METRIC_RSS; 622 result.config.metric = METRIC_RSS;
604 break; 623 break;
605 } 624 }
606 else if ( strcmp(optarg, "CPU") == 0 ) { 625 if (strcmp(optarg, "CPU") == 0) {
607 metric = METRIC_CPU; 626 result.config.metric = METRIC_CPU;
608 break; 627 break;
609 } 628 }
610 else if ( strcmp(optarg, "ELAPSED") == 0) { 629 if (strcmp(optarg, "ELAPSED") == 0) {
611 metric = METRIC_ELAPSED; 630 result.config.metric = METRIC_ELAPSED;
612 break; 631 break;
613 } 632 }
614 633
615 usage4 (_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!")); 634 usage4(_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!"));
616 case 'k': /* linux kernel thread filter */ 635 case 'k': /* linux kernel thread filter */
617 kthread_filter = 1; 636 result.config.kthread_filter = true;
618 break; 637 break;
619 case 'v': /* command */ 638 case 'v': /* command */
620 verbose++; 639 verbose++;
621 break; 640 break;
622 case 'T': 641 case 'T':
623 usepid = 1; 642 result.config.usepid = true;
624 break; 643 break;
625 case CHAR_MAX+2: 644 case CHAR_MAX + 2:
626 input_filename = optarg; 645 result.config.input_filename = optarg;
627 break; 646 break;
628 } 647 }
629 } 648 }
630 649
631 c = optind; 650 int index = optind;
632 if ((! warning_range) && argv[c]) 651 if ((!result.config.warning_range) && argv[index]) {
633 warning_range = argv[c++]; 652 result.config.warning_range = argv[index++];
634 if ((! critical_range) && argv[c]) 653 }
635 critical_range = argv[c++]; 654 if ((!result.config.critical_range) && argv[index]) {
636 if (statopts == NULL && argv[c]) { 655 result.config.critical_range = argv[index++];
637 xasprintf (&statopts, "%s", argv[c++]); 656 }
638 xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts); 657 if (result.config.statopts == NULL && argv[index]) {
639 options |= STAT; 658 xasprintf(&result.config.statopts, "%s", argv[index++]);
659 xasprintf(&result.config.fmt, _("%s%sSTATE = %s"),
660 (result.config.fmt ? result.config.fmt : ""), (result.config.options ? ", " : ""),
661 result.config.statopts);
662 result.config.options |= STAT;
640 } 663 }
641 664
642 /* this will abort in case of invalid ranges */ 665 /* this will abort in case of invalid ranges */
643 set_thresholds (&procs_thresholds, warning_range, critical_range); 666 set_thresholds(&result.config.procs_thresholds, result.config.warning_range,
667 result.config.critical_range);
644 668
645 return validate_arguments (); 669 return validate_arguments(result);
646} 670}
647 671
672check_procs_config_wrapper validate_arguments(check_procs_config_wrapper config_wrapper) {
673 if (config_wrapper.config.options == 0) {
674 config_wrapper.config.options = ALL;
675 }
648 676
677 if (config_wrapper.config.statopts == NULL) {
678 config_wrapper.config.statopts = strdup("");
679 }
649 680
650int 681 if (config_wrapper.config.prog == NULL) {
651validate_arguments () 682 config_wrapper.config.prog = strdup("");
652{ 683 }
653 if (options == 0)
654 options = ALL;
655
656 if (statopts==NULL)
657 statopts = strdup("");
658
659 if (prog==NULL)
660 prog = strdup("");
661 684
662 if (args==NULL) 685 if (config_wrapper.config.args == NULL) {
663 args = strdup(""); 686 config_wrapper.config.args = strdup("");
687 }
664 688
665 if (fmt==NULL) 689 if (config_wrapper.config.fmt == NULL) {
666 fmt = strdup(""); 690 config_wrapper.config.fmt = strdup("");
691 }
667 692
668 if (fails==NULL) 693 if (config_wrapper.config.fails == NULL) {
669 fails = strdup(""); 694 config_wrapper.config.fails = strdup("");
695 }
670 696
671 return options; 697 // return options;
698 return config_wrapper;
672} 699}
673 700
674
675/* convert the elapsed time to seconds */ 701/* convert the elapsed time to seconds */
676int 702int convert_to_seconds(char *etime, enum metric metric) {
677convert_to_seconds(char *etime) { 703 int hyphcnt = 0;
678 704 int coloncnt = 0;
679 char *ptr; 705 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 706
698 if (*ptr == '-') { 707 if (*ptr == '-') {
699 hyphcnt++; 708 hyphcnt++;
@@ -705,9 +714,12 @@ convert_to_seconds(char *etime) {
705 } 714 }
706 } 715 }
707 716
717 int days = 0;
718 int hours = 0;
719 int minutes = 0;
720 int seconds = 0;
708 if (hyphcnt > 0) { 721 if (hyphcnt > 0) {
709 sscanf(etime, "%d-%d:%d:%d", 722 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 723 /* linux 2.6.5/2.6.6 reporting some processes with infinite
712 * elapsed times for some reason */ 724 * elapsed times for some reason */
713 if (days == 49710) { 725 if (days == 49710) {
@@ -715,135 +727,129 @@ convert_to_seconds(char *etime) {
715 } 727 }
716 } else { 728 } else {
717 if (coloncnt == 2) { 729 if (coloncnt == 2) {
718 sscanf(etime, "%d:%d:%d", 730 sscanf(etime, "%d:%d:%d", &hours, &minutes, &seconds);
719 &hours, &minutes, &seconds);
720 } else if (coloncnt == 1) { 731 } else if (coloncnt == 1) {
721 sscanf(etime, "%d:%d", 732 sscanf(etime, "%d:%d", &minutes, &seconds);
722 &minutes, &seconds);
723 } 733 }
724 } 734 }
725 735
726 total = (days * 86400) + 736 int total = (days * 86400) + (hours * 3600) + (minutes * 60) + seconds;
727 (hours * 3600) +
728 (minutes * 60) +
729 seconds;
730 737
731 if (verbose >= 3 && metric == METRIC_ELAPSED) { 738 if (verbose >= 3 && metric == METRIC_ELAPSED) {
732 printf("seconds: %d\n", total); 739 printf("seconds: %d\n", total);
733 } 740 }
734 return total; 741 return total;
735} 742}
736 743
737 744void print_help(void) {
738void 745 print_revision(progname, NP_VERSION);
739print_help (void) 746
740{ 747 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
741 print_revision (progname, NP_VERSION); 748 printf(COPYRIGHT, copyright, email);
742 749
743 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 750 printf("%s\n",
744 printf (COPYRIGHT, copyright, email); 751 _("Checks all processes and generates WARNING or CRITICAL states if the specified"));
745 752 printf("%s\n",
746 printf ("%s\n", _("Checks all processes and generates WARNING or CRITICAL states if the specified")); 753 _("metric is outside the required threshold ranges. The metric defaults to number"));
747 printf ("%s\n", _("metric is outside the required threshold ranges. The metric defaults to number")); 754 printf("%s\n",
748 printf ("%s\n", _("of processes. Search filters can be applied to limit the processes to check.")); 755 _("of processes. Search filters can be applied to limit the processes to check."));
749 756
750 printf ("\n\n"); 757 printf("\n\n");
751 758
752 printf ("%s\n", _("The parent process, check_procs itself and any child process of check_procs (ps)")); 759 printf("%s\n",
753 printf ("%s\n", _("are excluded from any checks to prevent false positives.")); 760 _("The parent process, check_procs itself and any child process of check_procs (ps)"));
754 761 printf("%s\n", _("are excluded from any checks to prevent false positives."));
755 printf ("\n\n"); 762
756 763 printf("\n\n");
757 print_usage (); 764
758 765 print_usage();
759 printf (UT_HELP_VRSN); 766
760 printf (UT_EXTRA_OPTS); 767 printf(UT_HELP_VRSN);
761 printf (" %s\n", "-w, --warning=RANGE"); 768 printf(UT_EXTRA_OPTS);
762 printf (" %s\n", _("Generate warning state if metric is outside this range")); 769 printf(" %s\n", "-w, --warning=RANGE");
763 printf (" %s\n", "-c, --critical=RANGE"); 770 printf(" %s\n", _("Generate warning state if metric is outside this range"));
764 printf (" %s\n", _("Generate critical state if metric is outside this range")); 771 printf(" %s\n", "-c, --critical=RANGE");
765 printf (" %s\n", "-m, --metric=TYPE"); 772 printf(" %s\n", _("Generate critical state if metric is outside this range"));
766 printf (" %s\n", _("Check thresholds against metric. Valid types:")); 773 printf(" %s\n", "-m, --metric=TYPE");
767 printf (" %s\n", _("PROCS - number of processes (default)")); 774 printf(" %s\n", _("Check thresholds against metric. Valid types:"));
768 printf (" %s\n", _("VSZ - virtual memory size")); 775 printf(" %s\n", _("PROCS - number of processes (default)"));
769 printf (" %s\n", _("RSS - resident set memory size")); 776 printf(" %s\n", _("VSZ - virtual memory size"));
770 printf (" %s\n", _("CPU - percentage CPU")); 777 printf(" %s\n", _("RSS - resident set memory size"));
778 printf(" %s\n", _("CPU - percentage CPU"));
771/* only linux etime is support currently */ 779/* only linux etime is support currently */
772#if defined( __linux__ ) 780#if defined(__linux__)
773 printf (" %s\n", _("ELAPSED - time elapsed in seconds")); 781 printf(" %s\n", _("ELAPSED - time elapsed in seconds"));
774#endif /* defined(__linux__) */ 782#endif /* defined(__linux__) */
775 printf (UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 783 printf(UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
776 784
777 printf (" %s\n", "-v, --verbose"); 785 printf(" %s\n", "-v, --verbose");
778 printf (" %s\n", _("Extra information. Up to 3 verbosity levels")); 786 printf(" %s\n", _("Extra information. Up to 3 verbosity levels"));
779 787
780 printf (" %s\n", "-T, --traditional"); 788 printf(" %s\n", "-T, --traditional");
781 printf (" %s\n", _("Filter own process the traditional way by PID instead of /proc/pid/exe")); 789 printf(" %s\n", _("Filter own process the traditional way by PID instead of /proc/pid/exe"));
782 790
783 printf ("\n"); 791 printf("\n");
784 printf ("%s\n", "Filters:"); 792 printf("%s\n", "Filters:");
785 printf (" %s\n", "-s, --state=STATUSFLAGS"); 793 printf(" %s\n", "-s, --state=STATUSFLAGS");
786 printf (" %s\n", _("Only scan for processes that have, in the output of `ps`, one or")); 794 printf(" %s\n", _("Only scan for processes that have, in the output of `ps`, one or"));
787 printf (" %s\n", _("more of the status flags you specify (for example R, Z, S, RS,")); 795 printf(" %s\n", _("more of the status flags you specify (for example R, Z, S, RS,"));
788 printf (" %s\n", _("RSZDT, plus others based on the output of your 'ps' command).")); 796 printf(" %s\n", _("RSZDT, plus others based on the output of your 'ps' command)."));
789 printf (" %s\n", "-p, --ppid=PPID"); 797 printf(" %s\n", "-p, --ppid=PPID");
790 printf (" %s\n", _("Only scan for children of the parent process ID indicated.")); 798 printf(" %s\n", _("Only scan for children of the parent process ID indicated."));
791 printf (" %s\n", "-z, --vsz=VSZ"); 799 printf(" %s\n", "-z, --vsz=VSZ");
792 printf (" %s\n", _("Only scan for processes with VSZ higher than indicated.")); 800 printf(" %s\n", _("Only scan for processes with VSZ higher than indicated."));
793 printf (" %s\n", "-r, --rss=RSS"); 801 printf(" %s\n", "-r, --rss=RSS");
794 printf (" %s\n", _("Only scan for processes with RSS higher than indicated.")); 802 printf(" %s\n", _("Only scan for processes with RSS higher than indicated."));
795 printf (" %s\n", "-P, --pcpu=PCPU"); 803 printf(" %s\n", "-P, --pcpu=PCPU");
796 printf (" %s\n", _("Only scan for processes with PCPU higher than indicated.")); 804 printf(" %s\n", _("Only scan for processes with PCPU higher than indicated."));
797 printf (" %s\n", "-u, --user=USER"); 805 printf(" %s\n", "-u, --user=USER");
798 printf (" %s\n", _("Only scan for processes with user name or ID indicated.")); 806 printf(" %s\n", _("Only scan for processes with user name or ID indicated."));
799 printf (" %s\n", "-a, --argument-array=STRING"); 807 printf(" %s\n", "-a, --argument-array=STRING");
800 printf (" %s\n", _("Only scan for processes with args that contain STRING.")); 808 printf(" %s\n", _("Only scan for processes with args that contain STRING."));
801 printf (" %s\n", "--ereg-argument-array=STRING"); 809 printf(" %s\n", "--ereg-argument-array=STRING");
802 printf (" %s\n", _("Only scan for processes with args that contain the regex STRING.")); 810 printf(" %s\n", _("Only scan for processes with args that contain the regex STRING."));
803 printf (" %s\n", "-C, --command=COMMAND"); 811 printf(" %s\n", "-C, --command=COMMAND");
804 printf (" %s\n", _("Only scan for exact matches of COMMAND (without path).")); 812 printf(" %s\n", _("Only scan for exact matches of COMMAND (without path)."));
805 printf (" %s\n", "-X, --exclude-process"); 813 printf(" %s\n", "-X, --exclude-process");
806 printf (" %s\n", _("Exclude processes which match this comma separated list")); 814 printf(" %s\n", _("Exclude processes which match this comma separated list"));
807 printf (" %s\n", "-k, --no-kthreads"); 815 printf(" %s\n", "-k, --no-kthreads");
808 printf (" %s\n", _("Only scan for non kernel threads (works on Linux only).")); 816 printf(" %s\n", _("Only scan for non kernel threads (works on Linux only)."));
809 817
810 printf(_("\n\ 818 printf(_("\n\
811RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n\ 819RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n\
812specified 'max:min', a warning status will be generated if the\n\ 820specified 'max:min', a warning status will be generated if the\n\
813count is inside the specified range\n\n")); 821count is inside the specified range\n\n"));
814 822
815 printf(_("\ 823 printf(_("\
816This plugin checks the number of currently running processes and\n\ 824This plugin checks the number of currently running processes and\n\
817generates WARNING or CRITICAL states if the process count is outside\n\ 825generates WARNING or CRITICAL states if the process count is outside\n\
818the specified threshold ranges. The process count can be filtered by\n\ 826the specified threshold ranges. The process count can be filtered by\n\
819process owner, parent process PID, current state (e.g., 'Z'), or may\n\ 827process owner, parent process PID, current state (e.g., 'Z'), or may\n\
820be the total number of running processes\n\n")); 828be the total number of running processes\n\n"));
821 829
822 printf ("%s\n", _("Examples:")); 830 printf("%s\n", _("Examples:"));
823 printf (" %s\n", "check_procs -w 2:2 -c 2:1024 -C portsentry"); 831 printf(" %s\n", "check_procs -w 2:2 -c 2:1024 -C portsentry");
824 printf (" %s\n", _("Warning if not two processes with command name portsentry.")); 832 printf(" %s\n", _("Warning if not two processes with command name portsentry."));
825 printf (" %s\n\n", _("Critical if < 2 or > 1024 processes")); 833 printf(" %s\n\n", _("Critical if < 2 or > 1024 processes"));
826 printf (" %s\n", "check_procs -c 1: -C sshd"); 834 printf(" %s\n", "check_procs -c 1: -C sshd");
827 printf (" %s\n", _("Critical if not at least 1 process with command sshd")); 835 printf(" %s\n", _("Critical if not at least 1 process with command sshd"));
828 printf (" %s\n", "check_procs -w 1024 -c 1: -C sshd"); 836 printf(" %s\n", "check_procs -w 1024 -c 1: -C sshd");
829 printf (" %s\n", _("Warning if > 1024 processes with command name sshd.")); 837 printf(" %s\n", _("Warning if > 1024 processes with command name sshd."));
830 printf (" %s\n\n", _("Critical if < 1 processes with command name sshd.")); 838 printf(" %s\n\n", _("Critical if < 1 processes with command name sshd."));
831 printf (" %s\n", "check_procs -w 10 -a '/usr/local/bin/perl' -u root"); 839 printf(" %s\n", "check_procs -w 10 -a '/usr/local/bin/perl' -u root");
832 printf (" %s\n", _("Warning alert if > 10 processes with command arguments containing")); 840 printf(" %s\n", _("Warning alert if > 10 processes with command arguments containing"));
833 printf (" %s\n\n", _("'/usr/local/bin/perl' and owned by root")); 841 printf(" %s\n\n", _("'/usr/local/bin/perl' and owned by root"));
834 printf (" %s\n", "check_procs -w 50000 -c 100000 --metric=VSZ"); 842 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")); 843 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"); 844 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\%")); 845 printf(" %s\n", _("Alert if CPU of any processes over 10%% or 20%%"));
838 846
839 printf (UT_SUPPORT); 847 printf(UT_SUPPORT);
840} 848}
841 849
842void 850void print_usage(void) {
843print_usage (void) 851 printf("%s\n", _("Usage:"));
844{ 852 printf("%s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n", progname);
845 printf ("%s\n", _("Usage:")); 853 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); 854 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} 855}
diff --git a/plugins/check_procs.d/config.h b/plugins/check_procs.d/config.h
new file mode 100644
index 00000000..e32ca066
--- /dev/null
+++ b/plugins/check_procs.d/config.h
@@ -0,0 +1,75 @@
1#pragma once
2
3#include "../../config.h"
4#include "regex.h"
5#include "thresholds.h"
6#include <stddef.h>
7#include <string.h>
8#include <sys/types.h>
9
10enum metric {
11 METRIC_PROCS,
12 METRIC_VSZ,
13 METRIC_RSS,
14 METRIC_CPU,
15 METRIC_ELAPSED
16};
17
18typedef struct {
19 int options; /* bitmask of filter criteria to test against */
20 enum metric metric;
21 char *metric_name;
22 char *input_filename;
23 char *prog;
24 char *args;
25 char *fmt;
26 char *fails;
27 char *exclude_progs;
28 char **exclude_progs_arr;
29 char exclude_progs_counter;
30 regex_t re_args;
31
32 bool kthread_filter;
33 bool usepid; /* whether to test for pid or /proc/pid/exe */
34 uid_t uid;
35 pid_t ppid;
36 int vsz;
37 int rss;
38 float pcpu;
39 char *statopts;
40
41 char *warning_range;
42 char *critical_range;
43 thresholds *procs_thresholds;
44} check_procs_config;
45
46check_procs_config check_procs_config_init() {
47 check_procs_config tmp = {
48 .options = 0,
49 .metric = METRIC_PROCS,
50 .metric_name = strdup("PROCS"),
51 .input_filename = NULL,
52 .prog = NULL,
53 .args = NULL,
54 .fmt = NULL,
55 .fails = NULL,
56 .exclude_progs = NULL,
57 .exclude_progs_arr = NULL,
58 .exclude_progs_counter = 0,
59 .re_args = {0},
60
61 .kthread_filter = false,
62 .usepid = false,
63 .uid = 0,
64 .ppid = 0,
65 .vsz = 0,
66 .rss = 0,
67 .pcpu = 0,
68 .statopts = NULL,
69
70 .warning_range = NULL,
71 .critical_range = NULL,
72 .procs_thresholds = NULL,
73 };
74 return tmp;
75}
diff --git a/plugins/check_radius.c b/plugins/check_radius.c
index 6b32710a..d26f7cf3 100644
--- a/plugins/check_radius.c
+++ b/plugins/check_radius.c
@@ -1,99 +1,93 @@
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;
52 54} check_radius_config_wrapper;
53#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI) 55static check_radius_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
54#define my_rc_conf_str(a) rc_conf_str(rch,a) 56static void print_help(void);
55#if defined(HAVE_LIBRADCLI) 57void print_usage(void);
56#define my_rc_send_server(a,b) rc_send_server(rch,a,b,AUTH) 58
57#else 59#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || \
58#define my_rc_send_server(a,b) rc_send_server(rch,a,b) 60 defined(HAVE_LIBRADCLI)
59#endif 61# define my_rc_conf_str(a) rc_conf_str(rch, a)
60#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADCLI) 62# if defined(HAVE_LIBRADCLI)
61#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(rch,a,b,c,d,(a)->secret,e,f) 63# define my_rc_send_server(a, b) rc_send_server(rch, a, b, AUTH)
64# else
65# define my_rc_send_server(a, b) rc_send_server(rch, a, b)
66# endif
67# if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADCLI)
68# define my_rc_buildreq(a, b, c, d, e, f) rc_buildreq(rch, a, b, c, d, (a)->secret, e, f)
69# else
70# define my_rc_buildreq(a, b, c, d, e, f) rc_buildreq(rch, a, b, c, d, e, f)
71# endif
72# define my_rc_avpair_add(a, b, c, d) rc_avpair_add(rch, a, b, c, -1, d)
73# define my_rc_read_dictionary(a) rc_read_dictionary(rch, a)
62#else 74#else
63#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(rch,a,b,c,d,e,f) 75# define my_rc_conf_str(a) rc_conf_str(a)
64#endif 76# define my_rc_send_server(a, b) rc_send_server(a, b)
65#define my_rc_avpair_add(a,b,c,d) rc_avpair_add(rch,a,b,c,-1,d) 77# define my_rc_buildreq(a, b, c, d, e, f) rc_buildreq(a, b, c, d, e, f)
66#define my_rc_read_dictionary(a) rc_read_dictionary(rch, a) 78# define my_rc_avpair_add(a, b, c, d) rc_avpair_add(a, b, c, d)
67#else 79# define my_rc_read_dictionary(a) rc_read_dictionary(a)
68#define my_rc_conf_str(a) rc_conf_str(a)
69#define my_rc_send_server(a,b) rc_send_server(a, b)
70#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(a,b,c,d,e,f)
71#define my_rc_avpair_add(a,b,c,d) rc_avpair_add(a, b, c, d)
72#define my_rc_read_dictionary(a) rc_read_dictionary(a)
73#endif 80#endif
74 81
75/* REJECT_RC is only defined in some version of radiusclient. It has 82/* REJECT_RC is only defined in some version of radiusclient. It has
76 * been reported from radiusclient-ng 0.5.6 on FreeBSD 7.2-RELEASE */ 83 * been reported from radiusclient-ng 0.5.6 on FreeBSD 7.2-RELEASE */
77#ifndef REJECT_RC 84#ifndef REJECT_RC
78#define REJECT_RC BADRESP_RC 85# define REJECT_RC BADRESP_RC
79#endif 86#endif
80 87
81int my_rc_read_config(char *); 88static int my_rc_read_config(char * /*a*/, rc_handle ** /*rch*/);
82
83#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
84rc_handle *rch = NULL;
85#endif
86 89
87char *server = NULL; 90static 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 91
98/****************************************************************************** 92/******************************************************************************
99 93
@@ -148,149 +142,171 @@ Please note that all tags must be lowercase to use the DocBook XML DTD.
148-@@ 142-@@
149******************************************************************************/ 143******************************************************************************/
150 144
145int main(int argc, char **argv) {
146 setlocale(LC_ALL, "");
147 bindtextdomain(PACKAGE, LOCALEDIR);
148 textdomain(PACKAGE);
151 149
150 /* Parse extra opts if any */
151 argv = np_extra_opts(&argc, argv, progname);
152
153 check_radius_config_wrapper tmp_config = process_arguments(argc, argv);
154
155 if (tmp_config.errorcode == ERROR) {
156 usage4(_("Could not parse arguments"));
157 }
158
159 check_radius_config config = tmp_config.config;
160
161#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || \
162 defined(HAVE_LIBRADCLI)
163 rc_handle *rch = NULL;
164#endif
165
166 char *str = strdup("dictionary");
167 if ((config.config_file && my_rc_read_config(config.config_file, &rch)) ||
168 my_rc_read_dictionary(my_rc_conf_str(str))) {
169 die(STATE_UNKNOWN, _("Config file error\n"));
170 }
171
172 uint32_t service = PW_AUTHENTICATE_ONLY;
173
174 SEND_DATA data;
175 memset(&data, 0, sizeof(data));
176 if (!(my_rc_avpair_add(&data.send_pairs, PW_SERVICE_TYPE, &service, 0) &&
177 my_rc_avpair_add(&data.send_pairs, PW_USER_NAME, config.username, 0) &&
178 my_rc_avpair_add(&data.send_pairs, PW_USER_PASSWORD, config.password, 0))) {
179 die(STATE_UNKNOWN, _("Out of Memory?\n"));
180 }
181
182 if (config.nas_id != NULL) {
183 if (!(my_rc_avpair_add(&data.send_pairs, PW_NAS_IDENTIFIER, config.nas_id, 0))) {
184 die(STATE_UNKNOWN, _("Invalid NAS-Identifier\n"));
185 }
186 }
152 187
153int
154main (int argc, char **argv)
155{
156 struct sockaddr_storage ss;
157 char name[HOST_NAME_MAX]; 188 char name[HOST_NAME_MAX];
189 if (config.nas_ip_address == NULL) {
190 if (gethostname(name, sizeof(name)) != 0) {
191 die(STATE_UNKNOWN, _("gethostname() failed!\n"));
192 }
193 config.nas_ip_address = name;
194 }
195
196 struct sockaddr_storage radius_server_socket;
197 if (!dns_lookup(config.nas_ip_address, &radius_server_socket, AF_UNSPEC)) {
198 die(STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
199 }
200
201 uint32_t client_id = ntohl(((struct sockaddr_in *)&radius_server_socket)->sin_addr.s_addr);
202 if (my_rc_avpair_add(&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0) == NULL) {
203 die(STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
204 }
205
206 my_rc_buildreq(&data, PW_ACCESS_REQUEST, config.server, config.port, (int)timeout_interval,
207 config.retries);
208
158#ifdef RC_BUFFER_LEN 209#ifdef RC_BUFFER_LEN
159 char msg[RC_BUFFER_LEN]; 210 char msg[RC_BUFFER_LEN];
160#else 211#else
161 char msg[BUFFER_LEN]; 212 char msg[BUFFER_LEN];
162#endif 213#endif
163 SEND_DATA data;
164 int result = STATE_UNKNOWN;
165 uint32_t client_id, service;
166 char *str;
167 214
168 setlocale (LC_ALL, ""); 215 int result = my_rc_send_server(&data, msg);
169 bindtextdomain (PACKAGE, LOCALEDIR); 216 rc_avpair_free(data.send_pairs);
170 textdomain (PACKAGE); 217 if (data.receive_pairs) {
171 218 rc_avpair_free(data.receive_pairs);
172 /* Parse extra opts if any */ 219 }
173 argv=np_extra_opts (&argc, argv, progname);
174 220
175 if (process_arguments (argc, argv) == ERROR) 221 if (result == TIMEOUT_RC) {
176 usage4 (_("Could not parse arguments")); 222 printf("Timeout\n");
223 exit(STATE_CRITICAL);
224 }
177 225
178 str = strdup ("dictionary"); 226 if (result == ERROR_RC) {
179 if ((config_file && my_rc_read_config (config_file)) || 227 printf(_("Auth Error\n"));
180 my_rc_read_dictionary (my_rc_conf_str (str))) 228 exit(STATE_CRITICAL);
181 die (STATE_UNKNOWN, _("Config file error\n")); 229 }
182 230
183 service = PW_AUTHENTICATE_ONLY; 231 if (result == REJECT_RC) {
232 printf(_("Auth Failed\n"));
233 exit(STATE_WARNING);
234 }
184 235
185 memset (&data, 0, sizeof(data)); 236 if (result == BADRESP_RC) {
186 if (!(my_rc_avpair_add (&data.send_pairs, PW_SERVICE_TYPE, &service, 0) && 237 printf(_("Bad Response\n"));
187 my_rc_avpair_add (&data.send_pairs, PW_USER_NAME, username, 0) && 238 exit(STATE_WARNING);
188 my_rc_avpair_add (&data.send_pairs, PW_USER_PASSWORD, password, 0) 239 }
189 ))
190 die (STATE_UNKNOWN, _("Out of Memory?\n"));
191 240
192 if (nasid != NULL) { 241 if (config.expect && !strstr(msg, config.expect)) {
193 if (!(my_rc_avpair_add (&data.send_pairs, PW_NAS_IDENTIFIER, nasid, 0))) 242 printf("%s\n", msg);
194 die (STATE_UNKNOWN, _("Invalid NAS-Identifier\n")); 243 exit(STATE_WARNING);
195 } 244 }
196 245
197 if (nasipaddress == NULL) { 246 if (result == OK_RC) {
198 if (gethostname (name, sizeof(name)) != 0) 247 printf(_("Auth OK\n"));
199 die (STATE_UNKNOWN, _("gethostname() failed!\n")); 248 exit(STATE_OK);
200 nasipaddress = name;
201 } 249 }
202 if (!dns_lookup (nasipaddress, &ss, AF_INET)) /* TODO: Support IPv6. */ 250
203 die (STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
204 client_id = ntohl (((struct sockaddr_in *)&ss)->sin_addr.s_addr);
205 if (my_rc_avpair_add (&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0) == NULL)
206 die (STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
207
208 my_rc_buildreq (&data, PW_ACCESS_REQUEST, server, port, (int)timeout_interval,
209 retries);
210
211 result = my_rc_send_server (&data, msg);
212 rc_avpair_free (data.send_pairs);
213 if (data.receive_pairs)
214 rc_avpair_free (data.receive_pairs);
215
216 if (result == TIMEOUT_RC)
217 die (STATE_CRITICAL, _("Timeout\n"));
218 if (result == ERROR_RC)
219 die (STATE_CRITICAL, _("Auth Error\n"));
220 if (result == REJECT_RC)
221 die (STATE_WARNING, _("Auth Failed\n"));
222 if (result == BADRESP_RC)
223 die (STATE_WARNING, _("Bad Response\n"));
224 if (expect && !strstr (msg, expect))
225 die (STATE_WARNING, "%s\n", msg);
226 if (result == OK_RC)
227 die (STATE_OK, _("Auth OK\n"));
228 (void)snprintf(msg, sizeof(msg), _("Unexpected result code %d"), result); 251 (void)snprintf(msg, sizeof(msg), _("Unexpected result code %d"), result);
229 die (STATE_UNKNOWN, "%s\n", msg); 252 printf("%s\n", msg);
253 exit(STATE_UNKNOWN);
230} 254}
231 255
232
233
234/* process command-line arguments */ 256/* process command-line arguments */
235int 257check_radius_config_wrapper process_arguments(int argc, char **argv) {
236process_arguments (int argc, char **argv)
237{
238 int c;
239
240 int option = 0;
241 static struct option longopts[] = { 258 static struct option longopts[] = {
242 {"hostname", required_argument, 0, 'H'}, 259 {"hostname", required_argument, 0, 'H'}, {"port", required_argument, 0, 'P'},
243 {"port", required_argument, 0, 'P'}, 260 {"username", required_argument, 0, 'u'}, {"password", required_argument, 0, 'p'},
244 {"username", required_argument, 0, 'u'}, 261 {"nas-id", required_argument, 0, 'n'}, {"nas-ip-address", required_argument, 0, 'N'},
245 {"password", required_argument, 0, 'p'}, 262 {"filename", required_argument, 0, 'F'}, {"expect", required_argument, 0, 'e'},
246 {"nas-id", required_argument, 0, 'n'}, 263 {"retries", required_argument, 0, 'r'}, {"timeout", required_argument, 0, 't'},
247 {"nas-ip-address", required_argument, 0, 'N'}, 264 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
248 {"filename", required_argument, 0, 'F'}, 265 {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
249 {"expect", required_argument, 0, 'e'}, 266
250 {"retries", required_argument, 0, 'r'}, 267 check_radius_config_wrapper result = {
251 {"timeout", required_argument, 0, 't'}, 268 .errorcode = OK,
252 {"verbose", no_argument, 0, 'v'}, 269 .config = check_radius_config_init(),
253 {"version", no_argument, 0, 'V'},
254 {"help", no_argument, 0, 'h'},
255 {0, 0, 0, 0}
256 }; 270 };
257 271
258 while (1) { 272 while (true) {
259 c = getopt_long (argc, argv, "+hVvH:P:F:u:p:n:N:t:r:e:", longopts, 273 int option = 0;
260 &option); 274 int option_index = getopt_long(argc, argv, "+hVvH:P:F:u:p:n:N:t:r:e:", longopts, &option);
261 275
262 if (c == -1 || c == EOF || c == 1) 276 if (option_index == -1 || option_index == EOF || option_index == 1) {
263 break; 277 break;
278 }
264 279
265 switch (c) { 280 switch (option_index) {
266 case '?': /* print short usage statement if args not parsable */ 281 case '?': /* print short usage statement if args not parsable */
267 usage5 (); 282 usage5();
268 case 'h': /* help */ 283 case 'h': /* help */
269 print_help (); 284 print_help();
270 exit (STATE_UNKNOWN); 285 exit(STATE_UNKNOWN);
271 case 'V': /* version */ 286 case 'V': /* version */
272 print_revision (progname, NP_VERSION); 287 print_revision(progname, NP_VERSION);
273 exit (STATE_UNKNOWN); 288 exit(STATE_UNKNOWN);
274 case 'v': /* verbose mode */ 289 case 'v': /* verbose mode */
275 verbose = true; 290 verbose = true;
276 break; 291 break;
277 case 'H': /* hostname */ 292 case 'H': /* hostname */
278 if (!is_host (optarg)) { 293 if (!is_host(optarg)) {
279 usage2 (_("Invalid hostname/address"), optarg); 294 usage2(_("Invalid hostname/address"), optarg);
280 } 295 }
281 server = optarg; 296 result.config.server = optarg;
282 break; 297 break;
283 case 'P': /* port */ 298 case 'P': /* port */
284 if (is_intnonneg (optarg)) 299 if (is_intnonneg(optarg)) {
285 port = (unsigned short)atoi (optarg); 300 result.config.port = (unsigned short)atoi(optarg);
286 else 301 } else {
287 usage4 (_("Port must be a positive integer")); 302 usage4(_("Port must be a positive integer"));
303 }
288 break; 304 break;
289 case 'u': /* username */ 305 case 'u': /* username */
290 username = optarg; 306 result.config.username = optarg;
291 break; 307 break;
292 case 'p': /* password */ 308 case 'p': /* password */
293 password = strdup(optarg); 309 result.config.password = strdup(optarg);
294 310
295 /* Delete the password from process list */ 311 /* Delete the password from process list */
296 while (*optarg != '\0') { 312 while (*optarg != '\0') {
@@ -298,119 +314,118 @@ process_arguments (int argc, char **argv)
298 optarg++; 314 optarg++;
299 } 315 }
300 break; 316 break;
301 case 'n': /* nas id */ 317 case 'n': /* nas id */
302 nasid = optarg; 318 result.config.nas_id = optarg;
303 break; 319 break;
304 case 'N': /* nas ip address */ 320 case 'N': /* nas ip address */
305 nasipaddress = optarg; 321 result.config.nas_ip_address = optarg;
306 break; 322 break;
307 case 'F': /* configuration file */ 323 case 'F': /* configuration file */
308 config_file = optarg; 324 result.config.config_file = optarg;
309 break; 325 break;
310 case 'e': /* expect */ 326 case 'e': /* expect */
311 expect = optarg; 327 result.config.expect = optarg;
312 break; 328 break;
313 case 'r': /* retries */ 329 case 'r': /* retries */
314 if (is_intpos (optarg)) 330 if (is_intpos(optarg)) {
315 retries = atoi (optarg); 331 result.config.retries = atoi(optarg);
316 else 332 } else {
317 usage4 (_("Number of retries must be a positive integer")); 333 usage4(_("Number of retries must be a positive integer"));
334 }
318 break; 335 break;
319 case 't': /* timeout */ 336 case 't': /* timeout */
320 if (is_intpos (optarg)) 337 if (is_intpos(optarg)) {
321 timeout_interval = (unsigned)atoi (optarg); 338 timeout_interval = (unsigned)atoi(optarg);
322 else 339 } else {
323 usage2 (_("Timeout interval must be a positive integer"), optarg); 340 usage2(_("Timeout interval must be a positive integer"), optarg);
341 }
324 break; 342 break;
325 } 343 }
326 } 344 }
327 345
328 if (server == NULL) 346 if (result.config.server == NULL) {
329 usage4 (_("Hostname was not supplied")); 347 usage4(_("Hostname was not supplied"));
330 if (username == NULL) 348 }
331 usage4 (_("User not specified")); 349 if (result.config.username == NULL) {
332 if (password == NULL) 350 usage4(_("User not specified"));
333 usage4 (_("Password not specified")); 351 }
334 if (config_file == NULL) 352 if (result.config.password == NULL) {
335 usage4 (_("Configuration file not specified")); 353 usage4(_("Password not specified"));
354 }
355 if (result.config.config_file == NULL) {
356 usage4(_("Configuration file not specified"));
357 }
336 358
337 return OK; 359 return result;
338} 360}
339 361
340 362void print_help(void) {
341
342void
343print_help (void)
344{
345 char *myport; 363 char *myport;
346 xasprintf (&myport, "%d", PW_AUTH_UDP_PORT); 364 xasprintf(&myport, "%d", PW_AUTH_UDP_PORT);
347 365
348 print_revision (progname, NP_VERSION); 366 print_revision(progname, NP_VERSION);
349 367
350 printf ("Copyright (c) 1999 Robert August Vincent II\n"); 368 printf("Copyright (c) 1999 Robert August Vincent II\n");
351 printf (COPYRIGHT, copyright, email); 369 printf(COPYRIGHT, copyright, email);
352 370
353 printf("%s\n", _("Tests to see if a RADIUS server is accepting connections.")); 371 printf("%s\n", _("Tests to see if a RADIUS server is accepting connections."));
354 372
355 printf ("\n\n"); 373 printf("\n\n");
356 374
357 print_usage (); 375 print_usage();
358 376
359 printf (UT_HELP_VRSN); 377 printf(UT_HELP_VRSN);
360 printf (UT_EXTRA_OPTS); 378 printf(UT_EXTRA_OPTS);
361 379
362 printf (UT_HOST_PORT, 'P', myport); 380 printf(UT_HOST_PORT, 'P', myport);
363 381
364 printf (" %s\n", "-u, --username=STRING"); 382 printf(" %s\n", "-u, --username=STRING");
365 printf (" %s\n", _("The user to authenticate")); 383 printf(" %s\n", _("The user to authenticate"));
366 printf (" %s\n", "-p, --password=STRING"); 384 printf(" %s\n", "-p, --password=STRING");
367 printf (" %s\n", _("Password for authentication (SECURITY RISK)")); 385 printf(" %s\n", _("Password for authentication (SECURITY RISK)"));
368 printf (" %s\n", "-n, --nas-id=STRING"); 386 printf(" %s\n", "-n, --nas-id=STRING");
369 printf (" %s\n", _("NAS identifier")); 387 printf(" %s\n", _("NAS identifier"));
370 printf (" %s\n", "-N, --nas-ip-address=STRING"); 388 printf(" %s\n", "-N, --nas-ip-address=STRING");
371 printf (" %s\n", _("NAS IP Address")); 389 printf(" %s\n", _("NAS IP Address"));
372 printf (" %s\n", "-F, --filename=STRING"); 390 printf(" %s\n", "-F, --filename=STRING");
373 printf (" %s\n", _("Configuration file")); 391 printf(" %s\n", _("Configuration file"));
374 printf (" %s\n", "-e, --expect=STRING"); 392 printf(" %s\n", "-e, --expect=STRING");
375 printf (" %s\n", _("Response string to expect from the server")); 393 printf(" %s\n", _("Response string to expect from the server"));
376 printf (" %s\n", "-r, --retries=INTEGER"); 394 printf(" %s\n", "-r, --retries=INTEGER");
377 printf (" %s\n", _("Number of times to retry a failed connection")); 395 printf(" %s\n", _("Number of times to retry a failed connection"));
378 396
379 printf (UT_CONN_TIMEOUT, timeout_interval); 397 printf(UT_CONN_TIMEOUT, timeout_interval);
380 398
381 printf ("\n"); 399 printf("\n");
382 printf ("%s\n", _("This plugin tests a RADIUS server to see if it is accepting connections.")); 400 printf("%s\n", _("This plugin tests a RADIUS server to see if it is accepting connections."));
383 printf ("%s\n", _("The server to test must be specified in the invocation, as well as a user")); 401 printf("%s\n", _("The server to test must be specified in the invocation, as well as a user"));
384 printf ("%s\n", _("name and password. A configuration file must be present. The format of")); 402 printf("%s\n", _("name and password. A configuration file must be present. The format of"));
385 printf ("%s\n", _("the configuration file is described in the radiusclient library sources.")); 403 printf("%s\n", _("the configuration file is described in the radiusclient library sources."));
386 printf ("%s\n", _("The password option presents a substantial security issue because the")); 404 printf("%s\n", _("The password option presents a substantial security issue because the"));
387 printf ("%s\n", _("password can possibly be determined by careful watching of the command line")); 405 printf("%s\n",
388 printf ("%s\n", _("in a process listing. This risk is exacerbated because the plugin will")); 406 _("password can possibly be determined by careful watching of the command line"));
389 printf ("%s\n", _("typically be executed at regular predictable intervals. Please be sure that")); 407 printf("%s\n", _("in a process listing. This risk is exacerbated because the plugin will"));
390 printf ("%s\n", _("the password used does not allow access to sensitive system resources.")); 408 printf("%s\n",
391 409 _("typically be executed at regular predictable intervals. Please be sure that"));
392 printf (UT_SUPPORT); 410 printf("%s\n", _("the password used does not allow access to sensitive system resources."));
411
412 printf(UT_SUPPORT);
393} 413}
394 414
395 415void print_usage(void) {
396 416 printf("%s\n", _("Usage:"));
397void 417 printf("%s -H host -F config_file -u username -p password\n\
398print_usage (void)
399{
400 printf ("%s\n", _("Usage:"));
401 printf ("%s -H host -F config_file -u username -p password\n\
402 [-P port] [-t timeout] [-r retries] [-e expect]\n\ 418 [-P port] [-t timeout] [-r retries] [-e expect]\n\
403 [-n nas-id] [-N nas-ip-addr]\n", progname); 419 [-n nas-id] [-N nas-ip-addr]\n",
420 progname);
404} 421}
405 422
406 423int my_rc_read_config(char *config_file_name, rc_handle **rch) {
407 424#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || \
408int my_rc_read_config(char * a) 425 defined(HAVE_LIBRADCLI)
409{ 426 *rch = rc_read_config(config_file_name);
410#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
411 rch = rc_read_config(a);
412 return (rch == NULL) ? 1 : 0; 427 return (rch == NULL) ? 1 : 0;
413#else 428#else
414 return rc_read_config(a); 429 return rc_read_config(config_file_name);
415#endif 430#endif
416} 431}
diff --git a/plugins/check_radius.d/config.h b/plugins/check_radius.d/config.h
new file mode 100644
index 00000000..b27d31e7
--- /dev/null
+++ b/plugins/check_radius.d/config.h
@@ -0,0 +1,42 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5#if defined(HAVE_LIBRADCLI)
6# include <radcli/radcli.h>
7#elif defined(HAVE_LIBFREERADIUS_CLIENT)
8# include <freeradius-client.h>
9#elif defined(HAVE_LIBRADIUSCLIENT_NG)
10# include <radiusclient-ng.h>
11#else
12# include <radiusclient.h>
13#endif
14
15typedef struct {
16 char *server;
17 char *username;
18 char *password;
19 char *config_file;
20 char *nas_id;
21 char *nas_ip_address;
22 int retries;
23 unsigned short port;
24
25 char *expect;
26} check_radius_config;
27
28check_radius_config check_radius_config_init() {
29 check_radius_config tmp = {
30 .server = NULL,
31 .username = NULL,
32 .password = NULL,
33 .config_file = NULL,
34 .nas_id = NULL,
35 .nas_ip_address = NULL,
36 .retries = 1,
37 .port = PW_AUTH_UDP_PORT,
38
39 .expect = NULL,
40 };
41 return tmp;
42}
diff --git a/plugins/check_real.c b/plugins/check_real.c
index 15e035b6..66d07f8f 100644
--- a/plugins/check_real.c
+++ b/plugins/check_real.c
@@ -1,454 +1,445 @@
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
46int process_arguments (int, char **);
47int validate_arguments (void);
48void print_help (void);
49void print_usage (void);
50
51int server_port = PORT;
52char *server_address;
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 44
45typedef struct {
46 int errorcode;
47 check_real_config config;
48} check_real_config_wrapper;
49static check_real_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
62 50
51static void print_help(void);
52void print_usage(void);
63 53
64int 54static bool verbose = false;
65main (int argc, char **argv)
66{
67 int sd;
68 int result = STATE_UNKNOWN;
69 char buffer[MAX_INPUT_BUFFER];
70 char *status_line = NULL;
71 55
72 setlocale (LC_ALL, ""); 56int main(int argc, char **argv) {
73 bindtextdomain (PACKAGE, LOCALEDIR); 57 setlocale(LC_ALL, "");
74 textdomain (PACKAGE); 58 bindtextdomain(PACKAGE, LOCALEDIR);
59 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,
82 config.server_port);
83 }
93 84
94 /* Part I - Server Check */ 85 /* Part I - Server Check */
95 86
96 /* send the OPTIONS request */ 87 /* send the OPTIONS request */
97 sprintf (buffer, "OPTIONS rtsp://%s:%d RTSP/1.0\r\n", host_name, server_port); 88 char buffer[MAX_INPUT_BUFFER];
98 result = send (sd, buffer, strlen (buffer), 0); 89 sprintf(buffer, "OPTIONS rtsp://%s:%d RTSP/1.0\r\n", config.host_name, config.server_port);
90 ssize_t sent_bytes = send(socket, buffer, strlen(buffer), 0);
91 if (sent_bytes == -1) {
92 die(STATE_CRITICAL, _("Sending options to %s failed\n"), config.host_name);
93 }
99 94
100 /* send the header sync */ 95 /* send the header sync */
101 sprintf (buffer, "CSeq: 1\r\n"); 96 sprintf(buffer, "CSeq: 1\r\n");
102 result = send (sd, buffer, strlen (buffer), 0); 97 sent_bytes = send(socket, buffer, strlen(buffer), 0);
98 if (sent_bytes == -1) {
99 die(STATE_CRITICAL, _("Sending header sync to %s failed\n"), config.host_name);
100 }
103 101
104 /* send a newline so the server knows we're done with the request */ 102 /* send a newline so the server knows we're done with the request */
105 sprintf (buffer, "\r\n"); 103 sprintf(buffer, "\r\n");
106 result = send (sd, buffer, strlen (buffer), 0); 104 sent_bytes = send(socket, buffer, strlen(buffer), 0);
105 if (sent_bytes == -1) {
106 die(STATE_CRITICAL, _("Sending newline to %s failed\n"), config.host_name);
107 }
107 108
108 /* watch for the REAL connection string */ 109 /* watch for the REAL connection string */
109 result = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0); 110 ssize_t received_bytes = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0);
110 111
111 /* return a CRITICAL status if we couldn't read any data */ 112 /* return a CRITICAL status if we couldn't read any data */
112 if (result == -1) 113 if (received_bytes == -1) {
113 die (STATE_CRITICAL, _("No data received from %s\n"), host_name); 114 die(STATE_CRITICAL, _("No data received from %s\n"), config.host_name);
115 }
114 116
117 mp_state_enum result = STATE_OK;
118 char *status_line = NULL;
115 /* make sure we find the response we are looking for */ 119 /* make sure we find the response we are looking for */
116 if (!strstr (buffer, server_expect)) { 120 if (!strstr(buffer, config.server_expect)) {
117 if (server_port == PORT) 121 if (config.server_port == PORT) {
118 printf ("%s\n", _("Invalid REAL response received from host")); 122 printf("%s\n", _("Invalid REAL response received from host"));
119 else 123 } else {
120 printf (_("Invalid REAL response received from host on port %d\n"), 124 printf(_("Invalid REAL response received from host on port %d\n"), config.server_port);
121 server_port); 125 }
122 } 126 } else {
123 else {
124 /* else we got the REAL string, so check the return code */ 127 /* else we got the REAL string, so check the return code */
125 128
126 time (&end_time); 129 time(&end_time);
127 130
128 result = STATE_OK; 131 result = STATE_OK;
129 132
130 status_line = (char *) strtok (buffer, "\n"); 133 status_line = strtok(buffer, "\n");
131 134
132 if (strstr (status_line, "200")) 135 if (strstr(status_line, "200")) {
133 result = STATE_OK; 136 result = STATE_OK;
137 }
134 138
135 /* client errors result in a warning state */ 139 /* client errors result in a warning state */
136 else if (strstr (status_line, "400")) 140 else if (strstr(status_line, "400")) {
137 result = STATE_WARNING; 141 result = STATE_WARNING;
138 else if (strstr (status_line, "401")) 142 } else if (strstr(status_line, "401")) {
139 result = STATE_WARNING; 143 result = STATE_WARNING;
140 else if (strstr (status_line, "402")) 144 } else if (strstr(status_line, "402")) {
141 result = STATE_WARNING; 145 result = STATE_WARNING;
142 else if (strstr (status_line, "403")) 146 } else if (strstr(status_line, "403")) {
143 result = STATE_WARNING; 147 result = STATE_WARNING;
144 else if (strstr (status_line, "404")) 148 } else if (strstr(status_line, "404")) {
145 result = STATE_WARNING; 149 result = STATE_WARNING;
146 150 } else if (strstr(status_line, "500")) {
147 /* server errors result in a critical state */ 151 /* server errors result in a critical state */
148 else if (strstr (status_line, "500"))
149 result = STATE_CRITICAL; 152 result = STATE_CRITICAL;
150 else if (strstr (status_line, "501")) 153 } else if (strstr(status_line, "501")) {
151 result = STATE_CRITICAL; 154 result = STATE_CRITICAL;
152 else if (strstr (status_line, "502")) 155 } else if (strstr(status_line, "502")) {
153 result = STATE_CRITICAL; 156 result = STATE_CRITICAL;
154 else if (strstr (status_line, "503")) 157 } else if (strstr(status_line, "503")) {
155 result = STATE_CRITICAL; 158 result = STATE_CRITICAL;
156 159 } else {
157 else
158 result = STATE_UNKNOWN; 160 result = STATE_UNKNOWN;
161 }
159 } 162 }
160 163
161 /* Part II - Check stream exists and is ok */ 164 /* Part II - Check stream exists and is ok */
162 if ((result == STATE_OK )&& (server_url != NULL) ) { 165 if ((result == STATE_OK) && (config.server_url != NULL)) {
163 166
164 /* Part I - Server Check */ 167 /* Part I - Server Check */
165 168
166 /* send the DESCRIBE request */ 169 /* send the DESCRIBE request */
167 sprintf (buffer, "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n", host_name, 170 sprintf(buffer, "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n", config.host_name,
168 server_port, server_url); 171 config.server_port, config.server_url);
169 result = send (sd, buffer, strlen (buffer), 0); 172
173 ssize_t sent_bytes = send(socket, buffer, strlen(buffer), 0);
174 if (sent_bytes == -1) {
175 die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name);
176 }
170 177
171 /* send the header sync */ 178 /* send the header sync */
172 sprintf (buffer, "CSeq: 2\r\n"); 179 sprintf(buffer, "CSeq: 2\r\n");
173 result = send (sd, buffer, strlen (buffer), 0); 180 sent_bytes = send(socket, buffer, strlen(buffer), 0);
181 if (sent_bytes == -1) {
182 die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name);
183 }
174 184
175 /* send a newline so the server knows we're done with the request */ 185 /* send a newline so the server knows we're done with the request */
176 sprintf (buffer, "\r\n"); 186 sprintf(buffer, "\r\n");
177 result = send (sd, buffer, strlen (buffer), 0); 187 sent_bytes = send(socket, buffer, strlen(buffer), 0);
188 if (sent_bytes == -1) {
189 die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name);
190 }
178 191
179 /* watch for the REAL connection string */ 192 /* watch for the REAL connection string */
180 result = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0); 193 ssize_t recv_bytes = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0);
181 buffer[result] = '\0'; /* null terminate received buffer */ 194 if (recv_bytes == -1) {
182 195 /* return a CRITICAL status if we couldn't read any data */
183 /* return a CRITICAL status if we couldn't read any data */ 196 printf(_("No data received from host\n"));
184 if (result == -1) {
185 printf (_("No data received from host\n"));
186 result = STATE_CRITICAL; 197 result = STATE_CRITICAL;
187 } 198 } else {
188 else { 199 buffer[result] = '\0'; /* null terminate received buffer */
189 /* make sure we find the response we are looking for */ 200 /* make sure we find the response we are looking for */
190 if (!strstr (buffer, server_expect)) { 201 if (!strstr(buffer, config.server_expect)) {
191 if (server_port == PORT) 202 if (config.server_port == PORT) {
192 printf ("%s\n", _("Invalid REAL response received from host")); 203 printf("%s\n", _("Invalid REAL response received from host"));
193 else 204 } else {
194 printf (_("Invalid REAL response received from host on port %d\n"), 205 printf(_("Invalid REAL response received from host on port %d\n"),
195 server_port); 206 config.server_port);
196 } 207 }
197 else { 208 } else {
198 209
199 /* else we got the REAL string, so check the return code */ 210 /* else we got the REAL string, so check the return code */
200 211
201 time (&end_time); 212 time(&end_time);
202 213
203 result = STATE_OK; 214 result = STATE_OK;
204 215
205 status_line = (char *) strtok (buffer, "\n"); 216 status_line = strtok(buffer, "\n");
206 217
207 if (strstr (status_line, "200")) 218 if (strstr(status_line, "200")) {
208 result = STATE_OK; 219 result = STATE_OK;
220 }
209 221
210 /* client errors result in a warning state */ 222 /* client errors result in a warning state */
211 else if (strstr (status_line, "400")) 223 else if (strstr(status_line, "400")) {
212 result = STATE_WARNING; 224 result = STATE_WARNING;
213 else if (strstr (status_line, "401")) 225 } else if (strstr(status_line, "401")) {
214 result = STATE_WARNING; 226 result = STATE_WARNING;
215 else if (strstr (status_line, "402")) 227 } else if (strstr(status_line, "402")) {
216 result = STATE_WARNING; 228 result = STATE_WARNING;
217 else if (strstr (status_line, "403")) 229 } else if (strstr(status_line, "403")) {
218 result = STATE_WARNING; 230 result = STATE_WARNING;
219 else if (strstr (status_line, "404")) 231 } else if (strstr(status_line, "404")) {
220 result = STATE_WARNING; 232 result = STATE_WARNING;
233 }
221 234
222 /* server errors result in a critical state */ 235 /* server errors result in a critical state */
223 else if (strstr (status_line, "500")) 236 else if (strstr(status_line, "500")) {
224 result = STATE_CRITICAL; 237 result = STATE_CRITICAL;
225 else if (strstr (status_line, "501")) 238 } else if (strstr(status_line, "501")) {
226 result = STATE_CRITICAL; 239 result = STATE_CRITICAL;
227 else if (strstr (status_line, "502")) 240 } else if (strstr(status_line, "502")) {
228 result = STATE_CRITICAL; 241 result = STATE_CRITICAL;
229 else if (strstr (status_line, "503")) 242 } else if (strstr(status_line, "503")) {
230 result = STATE_CRITICAL; 243 result = STATE_CRITICAL;
244 }
231 245
232 else 246 else {
233 result = STATE_UNKNOWN; 247 result = STATE_UNKNOWN;
248 }
234 } 249 }
235 } 250 }
236 } 251 }
237 252
238 /* Return results */ 253 /* Return results */
239 if (result == STATE_OK) { 254 if (result == STATE_OK) {
240 255 if (config.check_critical_time && (end_time - start_time) > config.critical_time) {
241 if (check_critical_time 256 result = STATE_CRITICAL;
242 && (end_time - start_time) > critical_time) result = STATE_CRITICAL; 257 } else if (config.check_warning_time && (end_time - start_time) > config.warning_time) {
243 else if (check_warning_time 258 result = STATE_WARNING;
244 && (end_time - start_time) > warning_time) result = 259 }
245 STATE_WARNING;
246 260
247 /* Put some HTML in here to create a dynamic link */ 261 /* Put some HTML in here to create a dynamic link */
248 printf (_("REAL %s - %d second response time\n"), 262 printf(_("REAL %s - %d second response time\n"), state_text(result),
249 state_text (result), 263 (int)(end_time - start_time));
250 (int) (end_time - start_time)); 264 } else {
265 printf("%s\n", status_line);
251 } 266 }
252 else
253 printf ("%s\n", status_line);
254 267
255 /* close the connection */ 268 /* close the connection */
256 close (sd); 269 close(socket);
257 270
258 /* reset the alarm */ 271 /* reset the alarm */
259 alarm (0); 272 alarm(0);
260 273
261 return result; 274 exit(result);
262} 275}
263 276
264
265
266/* process command-line arguments */ 277/* process command-line arguments */
267int 278check_real_config_wrapper process_arguments(int argc, char **argv) {
268process_arguments (int argc, char **argv)
269{
270 int c;
271
272 int option = 0;
273 static struct option longopts[] = { 279 static struct option longopts[] = {
274 {"hostname", required_argument, 0, 'H'}, 280 {"hostname", required_argument, 0, 'H'}, {"IPaddress", required_argument, 0, 'I'},
275 {"IPaddress", required_argument, 0, 'I'}, 281 {"expect", required_argument, 0, 'e'}, {"url", required_argument, 0, 'u'},
276 {"expect", required_argument, 0, 'e'}, 282 {"port", required_argument, 0, 'p'}, {"critical", required_argument, 0, 'c'},
277 {"url", required_argument, 0, 'u'}, 283 {"warning", required_argument, 0, 'w'}, {"timeout", required_argument, 0, 't'},
278 {"port", required_argument, 0, 'p'}, 284 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
279 {"critical", required_argument, 0, 'c'}, 285 {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
280 {"warning", required_argument, 0, 'w'}, 286
281 {"timeout", required_argument, 0, 't'}, 287 check_real_config_wrapper result = {
282 {"verbose", no_argument, 0, 'v'}, 288 .errorcode = OK,
283 {"version", no_argument, 0, 'V'}, 289 .config = check_real_config_init(),
284 {"help", no_argument, 0, 'h'},
285 {0, 0, 0, 0}
286 }; 290 };
287 291
288 if (argc < 2) 292 if (argc < 2) {
289 return ERROR; 293 result.errorcode = ERROR;
294 return result;
295 }
290 296
291 for (c = 1; c < argc; c++) { 297 for (int i = 1; i < argc; i++) {
292 if (strcmp ("-to", argv[c]) == 0) 298 if (strcmp("-to", argv[i]) == 0) {
293 strcpy (argv[c], "-t"); 299 strcpy(argv[i], "-t");
294 else if (strcmp ("-wt", argv[c]) == 0) 300 } else if (strcmp("-wt", argv[i]) == 0) {
295 strcpy (argv[c], "-w"); 301 strcpy(argv[i], "-w");
296 else if (strcmp ("-ct", argv[c]) == 0) 302 } else if (strcmp("-ct", argv[i]) == 0) {
297 strcpy (argv[c], "-c"); 303 strcpy(argv[i], "-c");
304 }
298 } 305 }
299 306
300 while (1) { 307 while (true) {
301 c = getopt_long (argc, argv, "+hvVI:H:e:u:p:w:c:t:", longopts, 308 int option = 0;
302 &option); 309 int option_char = getopt_long(argc, argv, "+hvVI:H:e:u:p:w:c:t:", longopts, &option);
303 310
304 if (c == -1 || c == EOF) 311 if (option_char == -1 || option_char == EOF) {
305 break; 312 break;
313 }
306 314
307 switch (c) { 315 switch (option_char) {
308 case 'I': /* hostname */ 316 case 'I': /* hostname */
309 case 'H': /* hostname */ 317 case 'H': /* hostname */
310 if (server_address) 318 if (result.config.server_address) {
311 break; 319 break;
312 else if (is_host (optarg)) 320 } else if (is_host(optarg)) {
313 server_address = optarg; 321 result.config.server_address = optarg;
314 else 322 } else {
315 usage2 (_("Invalid hostname/address"), optarg); 323 usage2(_("Invalid hostname/address"), optarg);
324 }
316 break; 325 break;
317 case 'e': /* string to expect in response header */ 326 case 'e': /* string to expect in response header */
318 server_expect = optarg; 327 result.config.server_expect = optarg;
319 break; 328 break;
320 case 'u': /* server URL */ 329 case 'u': /* server URL */
321 server_url = optarg; 330 result.config.server_url = optarg;
322 break; 331 break;
323 case 'p': /* port */ 332 case 'p': /* port */
324 if (is_intpos (optarg)) { 333 if (is_intpos(optarg)) {
325 server_port = atoi (optarg); 334 result.config.server_port = atoi(optarg);
326 } 335 } else {
327 else { 336 usage4(_("Port must be a positive integer"));
328 usage4 (_("Port must be a positive integer"));
329 } 337 }
330 break; 338 break;
331 case 'w': /* warning time threshold */ 339 case 'w': /* warning time threshold */
332 if (is_intnonneg (optarg)) { 340 if (is_intnonneg(optarg)) {
333 warning_time = atoi (optarg); 341 result.config.warning_time = atoi(optarg);
334 check_warning_time = true; 342 result.config.check_warning_time = true;
335 } 343 } else {
336 else { 344 usage4(_("Warning time must be a positive integer"));
337 usage4 (_("Warning time must be a positive integer"));
338 } 345 }
339 break; 346 break;
340 case 'c': /* critical time threshold */ 347 case 'c': /* critical time threshold */
341 if (is_intnonneg (optarg)) { 348 if (is_intnonneg(optarg)) {
342 critical_time = atoi (optarg); 349 result.config.critical_time = atoi(optarg);
343 check_critical_time = true; 350 result.config.check_critical_time = true;
344 } 351 } else {
345 else { 352 usage4(_("Critical time must be a positive integer"));
346 usage4 (_("Critical time must be a positive integer"));
347 } 353 }
348 break; 354 break;
349 case 'v': /* verbose */ 355 case 'v': /* verbose */
350 verbose = true; 356 verbose = true;
351 break; 357 break;
352 case 't': /* timeout */ 358 case 't': /* timeout */
353 if (is_intnonneg (optarg)) { 359 if (is_intnonneg(optarg)) {
354 socket_timeout = atoi (optarg); 360 socket_timeout = atoi(optarg);
355 } 361 } else {
356 else { 362 usage4(_("Timeout interval must be a positive integer"));
357 usage4 (_("Timeout interval must be a positive integer"));
358 } 363 }
359 break; 364 break;
360 case 'V': /* version */ 365 case 'V': /* version */
361 print_revision (progname, NP_VERSION); 366 print_revision(progname, NP_VERSION);
362 exit (STATE_UNKNOWN); 367 exit(STATE_UNKNOWN);
363 case 'h': /* help */ 368 case 'h': /* help */
364 print_help (); 369 print_help();
365 exit (STATE_UNKNOWN); 370 exit(STATE_UNKNOWN);
366 case '?': /* usage */ 371 case '?': /* usage */
367 usage5 (); 372 usage5();
368 } 373 }
369 } 374 }
370 375
371 c = optind; 376 int option_char = optind;
372 if (server_address==NULL && argc>c) { 377 if (result.config.server_address == NULL && argc > option_char) {
373 if (is_host (argv[c])) { 378 if (is_host(argv[option_char])) {
374 server_address = argv[c++]; 379 result.config.server_address = argv[option_char++];
375 } 380 } else {
376 else { 381 usage2(_("Invalid hostname/address"), argv[option_char]);
377 usage2 (_("Invalid hostname/address"), argv[c]);
378 } 382 }
379 } 383 }
380 384
381 if (server_address==NULL) 385 if (result.config.server_address == NULL) {
382 usage4 (_("You must provide a server to check")); 386 usage4(_("You must provide a server to check"));
383 387 }
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 388
389 if (result.config.host_name == NULL) {
390 result.config.host_name = strdup(result.config.server_address);
391 }
393 392
393 if (result.config.server_expect == NULL) {
394 result.config.server_expect = strdup(EXPECT);
395 }
394 396
395int 397 return result;
396validate_arguments (void)
397{
398 return OK;
399} 398}
400 399
401 400void print_help(void) {
402
403void
404print_help (void)
405{
406 char *myport; 401 char *myport;
407 xasprintf (&myport, "%d", PORT); 402 xasprintf(&myport, "%d", PORT);
408 403
409 print_revision (progname, NP_VERSION); 404 print_revision(progname, NP_VERSION);
410 405
411 printf ("Copyright (c) 1999 Pedro Leite <leite@cic.ua.pt>\n"); 406 printf("Copyright (c) 1999 Pedro Leite <leite@cic.ua.pt>\n");
412 printf (COPYRIGHT, copyright, email); 407 printf(COPYRIGHT, copyright, email);
413 408
414 printf ("%s\n", _("This plugin tests the REAL service on the specified host.")); 409 printf("%s\n", _("This plugin tests the REAL service on the specified host."));
415 410
416 printf ("\n\n"); 411 printf("\n\n");
417 412
418 print_usage (); 413 print_usage();
419 414
420 printf (UT_HELP_VRSN); 415 printf(UT_HELP_VRSN);
421 printf (UT_EXTRA_OPTS); 416 printf(UT_EXTRA_OPTS);
422 417
423 printf (UT_HOST_PORT, 'p', myport); 418 printf(UT_HOST_PORT, 'p', myport);
424 419
425 printf (" %s\n", "-u, --url=STRING"); 420 printf(" %s\n", "-u, --url=STRING");
426 printf (" %s\n", _("Connect to this url")); 421 printf(" %s\n", _("Connect to this url"));
427 printf (" %s\n", "-e, --expect=STRING"); 422 printf(" %s\n", "-e, --expect=STRING");
428 printf (_("String to expect in first line of server response (default: %s)\n"), 423 printf(_("String to expect in first line of server response (default: %s)\n"), EXPECT);
429 EXPECT);
430 424
431 printf (UT_WARN_CRIT); 425 printf(UT_WARN_CRIT);
432 426
433 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 427 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
434 428
435 printf (UT_VERBOSE); 429 printf(UT_VERBOSE);
436 430
437 printf ("\n"); 431 printf("\n");
438 printf ("%s\n", _("This plugin will attempt to open an RTSP connection with the host.")); 432 printf("%s\n", _("This plugin will attempt to open an RTSP connection with the host."));
439 printf ("%s\n", _("Successful connects return STATE_OK, refusals and timeouts return")); 433 printf("%s\n", _("Successful connects return STATE_OK, refusals and timeouts return"));
440 printf ("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful connects,")); 434 printf("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful connects,"));
441 printf ("%s\n", _("but incorrect response messages from the host result in STATE_WARNING return")); 435 printf("%s\n",
442 printf ("%s\n", _("values.")); 436 _("but incorrect response messages from the host result in STATE_WARNING return"));
437 printf("%s\n", _("values."));
443 438
444 printf (UT_SUPPORT); 439 printf(UT_SUPPORT);
445} 440}
446 441
447 442void print_usage(void) {
448 443 printf("%s\n", _("Usage:"));
449void 444 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} 445}
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..83ad575c 100644
--- a/plugins/check_smtp.c
+++ b/plugins/check_smtp.c
@@ -1,437 +1,450 @@
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,
62 bool ssl_established) {
42#ifdef HAVE_SSL 63#ifdef HAVE_SSL
43bool check_cert = false; 64 if ((config.use_starttls || config.use_ssl) && ssl_established) {
44int days_till_exp_warn, days_till_exp_crit; 65 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)) 66 }
46# define my_send(buf, len) (((use_starttls || use_ssl) && ssl_established) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0)) 67 return (int)read(socket_descriptor, buf, (size_t)num);
47#else /* ifndef HAVE_SSL */ 68#else /* ifndef HAVE_SSL */
48# define my_recv(buf, len) read(sd, buf, len) 69 return read(socket_descriptor, buf, len)
49# define my_send(buf, len) send(sd, buf, len, 0)
50#endif 70#endif
71}
51 72
52enum { 73int my_send(check_smtp_config config, void *buf, int num, int socket_descriptor,
53 SMTP_PORT = 25, 74 bool ssl_established) {
54 SMTPS_PORT = 465 75#ifdef HAVE_SSL
55}; 76 if ((config.use_starttls || config.use_ssl) && ssl_established) {
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 77
67int process_arguments (int, char **); 78 return np_net_ssl_write(buf, num);
68int validate_arguments (void); 79 }
69void print_help (void); 80 return (int)send(socket_descriptor, buf, (size_t)num, 0);
70void print_usage (void); 81#else /* ifndef HAVE_SSL */
71void smtp_quit(void); 82 return send(socket_descriptor, buf, len, 0);
72int recvline(char *, size_t); 83#endif
73int recvlines(char *, size_t); 84}
74int my_close(void);
75 85
76#include "regex.h" 86static void print_help(void);
77char regex_expect[MAX_INPUT_BUFFER] = ""; 87void print_usage(void);
78regex_t preg; 88static char *smtp_quit(check_smtp_config /*config*/, char /*buffer*/[MAX_INPUT_BUFFER],
79regmatch_t pmatch[10]; 89 int /*socket_descriptor*/, bool /*ssl_established*/);
80char timestamp[20] = ""; 90static int recvline(char * /*buf*/, size_t /*bufsize*/, check_smtp_config /*config*/,
81char errbuf[MAX_INPUT_BUFFER]; 91 int /*socket_descriptor*/, bool /*ssl_established*/);
82int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 92static int recvlines(check_smtp_config /*config*/, char * /*buf*/, size_t /*bufsize*/,
83int eflags = 0; 93 int /*socket_descriptor*/, bool /*ssl_established*/);
84int errcode, excode; 94static int my_close(int /*socket_descriptor*/);
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 95
138 /* Catch pipe errors in read/write - sometimes occurs when writing QUIT */ 96static int verbose = 0;
139 (void) signal (SIGPIPE, SIG_IGN);
140 97
141 setlocale (LC_ALL, ""); 98int main(int argc, char **argv) {
142 bindtextdomain (PACKAGE, LOCALEDIR); 99 setlocale(LC_ALL, "");
143 textdomain (PACKAGE); 100 bindtextdomain(PACKAGE, LOCALEDIR);
101 textdomain(PACKAGE);
144 102
145 /* Parse extra opts if any */ 103 /* Parse extra opts if any */
146 argv=np_extra_opts (&argc, argv, progname); 104 argv = np_extra_opts(&argc, argv, progname);
147 105
148 if (process_arguments (argc, argv) == ERROR) 106 check_smtp_config_wrapper tmp_config = process_arguments(argc, argv);
149 usage4 (_("Could not parse arguments")); 107
108 if (tmp_config.errorcode == ERROR) {
109 usage4(_("Could not parse arguments"));
110 }
111
112 const check_smtp_config config = tmp_config.config;
150 113
151 /* If localhostname not set on command line, use gethostname to set */ 114 /* If localhostname not set on command line, use gethostname to set */
152 if(! localhostname){ 115 char *localhostname = config.localhostname;
153 localhostname = malloc (HOST_MAX_BYTES); 116 if (!localhostname) {
154 if(!localhostname){ 117 localhostname = malloc(HOST_MAX_BYTES);
118 if (!localhostname) {
155 printf(_("malloc() failed!\n")); 119 printf(_("malloc() failed!\n"));
156 return STATE_CRITICAL; 120 exit(STATE_CRITICAL);
157 } 121 }
158 if(gethostname(localhostname, HOST_MAX_BYTES)){ 122 if (gethostname(localhostname, HOST_MAX_BYTES)) {
159 printf(_("gethostname() failed!\n")); 123 printf(_("gethostname() failed!\n"));
160 return STATE_CRITICAL; 124 exit(STATE_CRITICAL);
161 } 125 }
162 } 126 }
163 if(use_lhlo) 127
164 xasprintf (&helocmd, "%s%s%s", SMTP_LHLO, localhostname, "\r\n"); 128 char *helocmd = NULL;
165 else if(use_ehlo) 129 if (config.use_lhlo) {
166 xasprintf (&helocmd, "%s%s%s", SMTP_EHLO, localhostname, "\r\n"); 130 xasprintf(&helocmd, "%s%s%s", SMTP_LHLO, localhostname, "\r\n");
167 else 131 } else if (config.use_ehlo) {
168 xasprintf (&helocmd, "%s%s%s", SMTP_HELO, localhostname, "\r\n"); 132 xasprintf(&helocmd, "%s%s%s", SMTP_EHLO, localhostname, "\r\n");
169 133 } else {
170 if (verbose) 134 xasprintf(&helocmd, "%s%s%s", SMTP_HELO, localhostname, "\r\n");
135 }
136
137 if (verbose) {
171 printf("HELOCMD: %s", helocmd); 138 printf("HELOCMD: %s", helocmd);
139 }
172 140
141 char *mail_command = strdup("MAIL ");
142 char *cmd_str = NULL;
173 /* initialize the MAIL command with optional FROM command */ 143 /* initialize the MAIL command with optional FROM command */
174 xasprintf (&cmd_str, "%sFROM:<%s>%s", mail_command, from_arg, "\r\n"); 144 xasprintf(&cmd_str, "%sFROM:<%s>%s", mail_command, config.from_arg, "\r\n");
175 145
176 if (verbose && send_mail_from) 146 if (verbose && config.send_mail_from) {
177 printf ("FROM CMD: %s", cmd_str); 147 printf("FROM CMD: %s", cmd_str);
148 }
149
150 /* Catch pipe errors in read/write - sometimes occurs when writing QUIT */
151 (void)signal(SIGPIPE, SIG_IGN);
178 152
179 /* initialize alarm signal handling */ 153 /* initialize alarm signal handling */
180 (void) signal (SIGALRM, socket_timeout_alarm_handler); 154 (void)signal(SIGALRM, socket_timeout_alarm_handler);
181 155
182 /* set socket timeout */ 156 /* set socket timeout */
183 (void) alarm (socket_timeout); 157 (void)alarm(socket_timeout);
184 158
159 struct timeval start_time;
185 /* start timer */ 160 /* start timer */
186 gettimeofday (&tv, NULL); 161 gettimeofday(&start_time, NULL);
187 162
163 int socket_descriptor = 0;
188 /* try to connect to the host at the given port number */ 164 /* try to connect to the host at the given port number */
189 result = my_tcp_connect (server_address, server_port, &sd); 165 mp_state_enum result =
166 my_tcp_connect(config.server_address, config.server_port, &socket_descriptor);
190 167
168 char *error_msg = "";
169 char buffer[MAX_INPUT_BUFFER];
170 bool ssl_established = false;
191 if (result == STATE_OK) { /* we connected */ 171 if (result == STATE_OK) { /* we connected */
192 /* If requested, send PROXY header */ 172 /* If requested, send PROXY header */
193 if (use_proxy_prefix) { 173 if (config.use_proxy_prefix) {
194 if (verbose) 174 if (verbose) {
195 printf ("Sending header %s\n", PROXY_PREFIX); 175 printf("Sending header %s\n", PROXY_PREFIX);
196 my_send(PROXY_PREFIX, strlen(PROXY_PREFIX)); 176 }
177 my_send(config, PROXY_PREFIX, strlen(PROXY_PREFIX), socket_descriptor, ssl_established);
197 } 178 }
198 179
199#ifdef HAVE_SSL 180#ifdef HAVE_SSL
200 if (use_ssl) { 181 if (config.use_ssl) {
201 result = np_net_ssl_init_with_hostname(sd, (use_sni ? server_address : NULL)); 182 result = np_net_ssl_init_with_hostname(socket_descriptor,
183 (config.use_sni ? config.server_address : NULL));
202 if (result != STATE_OK) { 184 if (result != STATE_OK) {
203 printf (_("CRITICAL - Cannot create SSL context.\n")); 185 printf(_("CRITICAL - Cannot create SSL context.\n"));
204 close(sd); 186 close(socket_descriptor);
205 np_net_ssl_cleanup(); 187 np_net_ssl_cleanup();
206 return STATE_CRITICAL; 188 exit(STATE_CRITICAL);
207 } else {
208 ssl_established = 1;
209 } 189 }
190 ssl_established = true;
210 } 191 }
211#endif 192#endif
212 193
213 /* watch for the SMTP connection string and */ 194 /* watch for the SMTP connection string and */
214 /* return a WARNING status if we couldn't read any data */ 195 /* return a WARNING status if we couldn't read any data */
215 if (recvlines(buffer, MAX_INPUT_BUFFER) <= 0) { 196 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) {
216 printf (_("recv() failed\n")); 197 printf(_("recv() failed\n"));
217 return STATE_WARNING; 198 exit(STATE_WARNING);
218 } 199 }
219 200
201 char *server_response = NULL;
220 /* save connect return (220 hostname ..) for later use */ 202 /* save connect return (220 hostname ..) for later use */
221 xasprintf(&server_response, "%s", buffer); 203 xasprintf(&server_response, "%s", buffer);
222 204
223 /* send the HELO/EHLO command */ 205 /* send the HELO/EHLO command */
224 my_send(helocmd, strlen(helocmd)); 206 my_send(config, helocmd, (int)strlen(helocmd), socket_descriptor, ssl_established);
225 207
226 /* allow for response to helo command to reach us */ 208 /* allow for response to helo command to reach us */
227 if (recvlines(buffer, MAX_INPUT_BUFFER) <= 0) { 209 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) {
228 printf (_("recv() failed\n")); 210 printf(_("recv() failed\n"));
229 return STATE_WARNING; 211 exit(STATE_WARNING);
230 } else if(use_ehlo || use_lhlo){ 212 }
231 if(strstr(buffer, "250 STARTTLS") != NULL || 213
232 strstr(buffer, "250-STARTTLS") != NULL){ 214 bool supports_tls = false;
233 supports_tls=true; 215 if (config.use_ehlo || config.use_lhlo) {
216 if (strstr(buffer, "250 STARTTLS") != NULL || strstr(buffer, "250-STARTTLS") != NULL) {
217 supports_tls = true;
234 } 218 }
235 } 219 }
236 220
237 if(use_starttls && ! supports_tls){ 221 if (config.use_starttls && !supports_tls) {
238 printf(_("WARNING - TLS not supported by server\n")); 222 printf(_("WARNING - TLS not supported by server\n"));
239 smtp_quit(); 223 smtp_quit(config, buffer, socket_descriptor, ssl_established);
240 return STATE_WARNING; 224 exit(STATE_WARNING);
241 } 225 }
242 226
243#ifdef HAVE_SSL 227#ifdef HAVE_SSL
244 if(use_starttls) { 228 if (config.use_starttls) {
245 /* send the STARTTLS command */ 229 /* send the STARTTLS command */
246 send(sd, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0); 230 send(socket_descriptor, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0);
247 231
248 recvlines(buffer, MAX_INPUT_BUFFER); /* wait for it */ 232 recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor,
249 if (!strstr (buffer, SMTP_EXPECT)) { 233 ssl_established); /* wait for it */
250 printf (_("Server does not support STARTTLS\n")); 234 if (!strstr(buffer, SMTP_EXPECT)) {
251 smtp_quit(); 235 printf(_("Server does not support STARTTLS\n"));
252 return STATE_UNKNOWN; 236 smtp_quit(config, buffer, socket_descriptor, ssl_established);
253 } 237 exit(STATE_UNKNOWN);
254 result = np_net_ssl_init_with_hostname(sd, (use_sni ? server_address : NULL)); 238 }
255 if(result != STATE_OK) { 239
256 printf (_("CRITICAL - Cannot create SSL context.\n")); 240 result = np_net_ssl_init_with_hostname(socket_descriptor,
257 close(sd); 241 (config.use_sni ? config.server_address : NULL));
258 np_net_ssl_cleanup(); 242 if (result != STATE_OK) {
259 return STATE_CRITICAL; 243 printf(_("CRITICAL - Cannot create SSL context.\n"));
260 } else { 244 close(socket_descriptor);
261 ssl_established = 1; 245 np_net_ssl_cleanup();
262 } 246 exit(STATE_CRITICAL);
263 247 }
264 /* 248
265 * Resend the EHLO command. 249 ssl_established = true;
266 * 250
267 * RFC 3207 (4.2) says: ``The client MUST discard any knowledge 251 /*
268 * obtained from the server, such as the list of SMTP service 252 * Resend the EHLO command.
269 * extensions, which was not obtained from the TLS negotiation 253 *
270 * itself. The client SHOULD send an EHLO command as the first 254 * RFC 3207 (4.2) says: ``The client MUST discard any knowledge
271 * command after a successful TLS negotiation.'' For this 255 * obtained from the server, such as the list of SMTP service
272 * reason, some MTAs will not allow an AUTH LOGIN command before 256 * extensions, which was not obtained from the TLS negotiation
273 * we resent EHLO via TLS. 257 * itself. The client SHOULD send an EHLO command as the first
274 */ 258 * command after a successful TLS negotiation.'' For this
275 if (my_send(helocmd, strlen(helocmd)) <= 0) { 259 * reason, some MTAs will not allow an AUTH LOGIN command before
276 printf("%s\n", _("SMTP UNKNOWN - Cannot send EHLO command via TLS.")); 260 * we resent EHLO via TLS.
277 my_close(); 261 */
278 return STATE_UNKNOWN; 262 if (my_send(config, helocmd, strlen(helocmd), socket_descriptor, ssl_established) <=
279 } 263 0) {
280 if (verbose) 264 printf("%s\n", _("SMTP UNKNOWN - Cannot send EHLO command via TLS."));
281 printf(_("sent %s"), helocmd); 265 my_close(socket_descriptor);
282 if ((n = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) { 266 exit(STATE_UNKNOWN);
283 printf("%s\n", _("SMTP UNKNOWN - Cannot read EHLO response via TLS.")); 267 }
284 my_close(); 268
285 return STATE_UNKNOWN; 269 if (verbose) {
286 } 270 printf(_("sent %s"), helocmd);
287 if (verbose) { 271 }
288 printf("%s", buffer);
289 }
290 272
291# ifdef USE_OPENSSL 273 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <=
292 if ( check_cert ) { 274 0) {
293 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit); 275 printf("%s\n", _("SMTP UNKNOWN - Cannot read EHLO response via TLS."));
294 smtp_quit(); 276 my_close(socket_descriptor);
295 my_close(); 277 exit(STATE_UNKNOWN);
296 return result; 278 }
297 } 279
298# endif /* USE_OPENSSL */ 280 if (verbose) {
281 printf("%s", buffer);
282 }
283
284# ifdef USE_OPENSSL
285 if (config.check_cert) {
286 result =
287 np_net_ssl_check_cert(config.days_till_exp_warn, config.days_till_exp_crit);
288 smtp_quit(config, buffer, socket_descriptor, ssl_established);
289 my_close(socket_descriptor);
290 exit(result);
291 }
292# endif /* USE_OPENSSL */
299 } 293 }
300#endif 294#endif
301 295
302 if (verbose) 296 if (verbose) {
303 printf ("%s", buffer); 297 printf("%s", buffer);
298 }
304 299
305 /* save buffer for later use */ 300 /* save buffer for later use */
306 xasprintf(&server_response, "%s%s", server_response, buffer); 301 xasprintf(&server_response, "%s%s", server_response, buffer);
307 /* strip the buffer of carriage returns */ 302 /* strip the buffer of carriage returns */
308 strip (server_response); 303 strip(server_response);
309 304
310 /* make sure we find the droids we are looking for */ 305 /* make sure we find the droids we are looking for */
311 if (!strstr (server_response, server_expect)) { 306 if (!strstr(server_response, config.server_expect)) {
312 if (server_port == SMTP_PORT) 307 if (config.server_port == SMTP_PORT) {
313 printf (_("Invalid SMTP response received from host: %s\n"), server_response); 308 printf(_("Invalid SMTP response received from host: %s\n"), server_response);
314 else 309 } else {
315 printf (_("Invalid SMTP response received from host on port %d: %s\n"), 310 printf(_("Invalid SMTP response received from host on port %d: %s\n"),
316 server_port, server_response); 311 config.server_port, server_response);
317 return STATE_WARNING; 312 }
313 exit(STATE_WARNING);
318 } 314 }
319 315
320 if (send_mail_from) { 316 if (config.send_mail_from) {
321 my_send(cmd_str, strlen(cmd_str)); 317 my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established);
322 if (recvlines(buffer, MAX_INPUT_BUFFER) >= 1 && verbose) 318 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >=
323 printf("%s", buffer); 319 1 &&
320 verbose) {
321 printf("%s", buffer);
322 }
324 } 323 }
325 324
326 n = 0; 325 int counter = 0;
327 while (n < ncommands) { 326 while (counter < config.ncommands) {
328 xasprintf (&cmd_str, "%s%s", commands[n], "\r\n"); 327 xasprintf(&cmd_str, "%s%s", config.commands[counter], "\r\n");
329 my_send(cmd_str, strlen(cmd_str)); 328 my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established);
330 if (recvlines(buffer, MAX_INPUT_BUFFER) >= 1 && verbose) 329 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >=
330 1 &&
331 verbose) {
331 printf("%s", buffer); 332 printf("%s", buffer);
332 strip (buffer); 333 }
333 if (n < nresponses) { 334 strip(buffer);
334 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 335 if (counter < config.nresponses) {
335 errcode = regcomp (&preg, responses[n], cflags); 336 int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
337 regex_t preg;
338 int errcode = regcomp(&preg, config.responses[counter], cflags);
339 char errbuf[MAX_INPUT_BUFFER];
336 if (errcode != 0) { 340 if (errcode != 0) {
337 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 341 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
338 printf (_("Could Not Compile Regular Expression")); 342 printf(_("Could Not Compile Regular Expression"));
339 return ERROR; 343 exit(STATE_UNKNOWN);
340 } 344 }
341 excode = regexec (&preg, buffer, 10, pmatch, eflags); 345
346 regmatch_t pmatch[10];
347 int eflags = 0;
348 int excode = regexec(&preg, buffer, 10, pmatch, eflags);
342 if (excode == 0) { 349 if (excode == 0) {
343 result = STATE_OK; 350 result = STATE_OK;
344 } 351 } else if (excode == REG_NOMATCH) {
345 else if (excode == REG_NOMATCH) {
346 result = STATE_WARNING; 352 result = STATE_WARNING;
347 printf (_("SMTP %s - Invalid response '%s' to command '%s'\n"), state_text (result), buffer, commands[n]); 353 printf(_("SMTP %s - Invalid response '%s' to command '%s'\n"),
348 } 354 state_text(result), buffer, config.commands[counter]);
349 else { 355 } else {
350 regerror (excode, &preg, errbuf, MAX_INPUT_BUFFER); 356 regerror(excode, &preg, errbuf, MAX_INPUT_BUFFER);
351 printf (_("Execute Error: %s\n"), errbuf); 357 printf(_("Execute Error: %s\n"), errbuf);
352 result = STATE_UNKNOWN; 358 result = STATE_UNKNOWN;
353 } 359 }
354 } 360 }
355 n++; 361 counter++;
356 } 362 }
357 363
358 if (authtype != NULL) { 364 if (config.authtype != NULL) {
359 if (strcmp (authtype, "LOGIN") == 0) { 365 if (strcmp(config.authtype, "LOGIN") == 0) {
360 char *abuf; 366 char *abuf;
361 int ret; 367 int ret;
362 do { 368 do {
363 if (authuser == NULL) { 369 if (config.authuser == NULL) {
364 result = STATE_CRITICAL; 370 result = STATE_CRITICAL;
365 xasprintf(&error_msg, _("no authuser specified, ")); 371 xasprintf(&error_msg, _("no authuser specified, "));
366 break; 372 break;
367 } 373 }
368 if (authpass == NULL) { 374 if (config.authpass == NULL) {
369 result = STATE_CRITICAL; 375 result = STATE_CRITICAL;
370 xasprintf(&error_msg, _("no authpass specified, ")); 376 xasprintf(&error_msg, _("no authpass specified, "));
371 break; 377 break;
372 } 378 }
373 379
374 /* send AUTH LOGIN */ 380 /* send AUTH LOGIN */
375 my_send(SMTP_AUTH_LOGIN, strlen(SMTP_AUTH_LOGIN)); 381 my_send(config, SMTP_AUTH_LOGIN, strlen(SMTP_AUTH_LOGIN), socket_descriptor,
376 if (verbose) 382 ssl_established);
377 printf (_("sent %s\n"), "AUTH LOGIN"); 383 if (verbose) {
384 printf(_("sent %s\n"), "AUTH LOGIN");
385 }
378 386
379 if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) { 387 if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor,
388 ssl_established)) <= 0) {
380 xasprintf(&error_msg, _("recv() failed after AUTH LOGIN, ")); 389 xasprintf(&error_msg, _("recv() failed after AUTH LOGIN, "));
381 result = STATE_WARNING; 390 result = STATE_WARNING;
382 break; 391 break;
383 } 392 }
384 if (verbose) 393 if (verbose) {
385 printf (_("received %s\n"), buffer); 394 printf(_("received %s\n"), buffer);
395 }
386 396
387 if (strncmp (buffer, "334", 3) != 0) { 397 if (strncmp(buffer, "334", 3) != 0) {
388 result = STATE_CRITICAL; 398 result = STATE_CRITICAL;
389 xasprintf(&error_msg, _("invalid response received after AUTH LOGIN, ")); 399 xasprintf(&error_msg, _("invalid response received after AUTH LOGIN, "));
390 break; 400 break;
391 } 401 }
392 402
393 /* encode authuser with base64 */ 403 /* encode authuser with base64 */
394 base64_encode_alloc (authuser, strlen(authuser), &abuf); 404 base64_encode_alloc(config.authuser, strlen(config.authuser), &abuf);
395 xasprintf(&abuf, "%s\r\n", abuf); 405 xasprintf(&abuf, "%s\r\n", abuf);
396 my_send(abuf, strlen(abuf)); 406 my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established);
397 if (verbose) 407 if (verbose) {
398 printf (_("sent %s\n"), abuf); 408 printf(_("sent %s\n"), abuf);
409 }
399 410
400 if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) { 411 if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor,
412 ssl_established)) <= 0) {
401 result = STATE_CRITICAL; 413 result = STATE_CRITICAL;
402 xasprintf(&error_msg, _("recv() failed after sending authuser, ")); 414 xasprintf(&error_msg, _("recv() failed after sending authuser, "));
403 break; 415 break;
404 } 416 }
405 if (verbose) { 417 if (verbose) {
406 printf (_("received %s\n"), buffer); 418 printf(_("received %s\n"), buffer);
407 } 419 }
408 if (strncmp (buffer, "334", 3) != 0) { 420 if (strncmp(buffer, "334", 3) != 0) {
409 result = STATE_CRITICAL; 421 result = STATE_CRITICAL;
410 xasprintf(&error_msg, _("invalid response received after authuser, ")); 422 xasprintf(&error_msg, _("invalid response received after authuser, "));
411 break; 423 break;
412 } 424 }
413 /* encode authpass with base64 */ 425 /* encode authpass with base64 */
414 base64_encode_alloc (authpass, strlen(authpass), &abuf); 426 base64_encode_alloc(config.authpass, strlen(config.authpass), &abuf);
415 xasprintf(&abuf, "%s\r\n", abuf); 427 xasprintf(&abuf, "%s\r\n", abuf);
416 my_send(abuf, strlen(abuf)); 428 my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established);
417 if (verbose) { 429 if (verbose) {
418 printf (_("sent %s\n"), abuf); 430 printf(_("sent %s\n"), abuf);
419 } 431 }
420 if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) { 432 if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor,
433 ssl_established)) <= 0) {
421 result = STATE_CRITICAL; 434 result = STATE_CRITICAL;
422 xasprintf(&error_msg, _("recv() failed after sending authpass, ")); 435 xasprintf(&error_msg, _("recv() failed after sending authpass, "));
423 break; 436 break;
424 } 437 }
425 if (verbose) { 438 if (verbose) {
426 printf (_("received %s\n"), buffer); 439 printf(_("received %s\n"), buffer);
427 } 440 }
428 if (strncmp (buffer, "235", 3) != 0) { 441 if (strncmp(buffer, "235", 3) != 0) {
429 result = STATE_CRITICAL; 442 result = STATE_CRITICAL;
430 xasprintf(&error_msg, _("invalid response received after authpass, ")); 443 xasprintf(&error_msg, _("invalid response received after authpass, "));
431 break; 444 break;
432 } 445 }
433 break; 446 break;
434 } while (0); 447 } while (false);
435 } else { 448 } else {
436 result = STATE_CRITICAL; 449 result = STATE_CRITICAL;
437 xasprintf(&error_msg, _("only authtype LOGIN is supported, ")); 450 xasprintf(&error_msg, _("only authtype LOGIN is supported, "));
@@ -439,243 +452,249 @@ main (int argc, char **argv)
439 } 452 }
440 453
441 /* tell the server we're done */ 454 /* tell the server we're done */
442 smtp_quit(); 455 smtp_quit(config, buffer, socket_descriptor, ssl_established);
443 456
444 /* finally close the connection */ 457 /* finally close the connection */
445 close (sd); 458 close(socket_descriptor);
446 } 459 }
447 460
448 /* reset the alarm */ 461 /* reset the alarm */
449 alarm (0); 462 alarm(0);
450 463
451 microsec = deltime (tv); 464 long microsec = deltime(start_time);
452 elapsed_time = (double)microsec / 1.0e6; 465 double elapsed_time = (double)microsec / 1.0e6;
453 466
454 if (result == STATE_OK) { 467 if (result == STATE_OK) {
455 if (check_critical_time && elapsed_time > critical_time) 468 if (config.check_critical_time && elapsed_time > config.critical_time) {
456 result = STATE_CRITICAL; 469 result = STATE_CRITICAL;
457 else if (check_warning_time && elapsed_time > warning_time) 470 } else if (config.check_warning_time && elapsed_time > config.warning_time) {
458 result = STATE_WARNING; 471 result = STATE_WARNING;
472 }
459 } 473 }
460 474
461 printf (_("SMTP %s - %s%.3f sec. response time%s%s|%s\n"), 475 printf(_("SMTP %s - %s%.3f sec. response time%s%s|%s\n"), state_text(result), error_msg,
462 state_text (result), 476 elapsed_time, verbose ? ", " : "", verbose ? buffer : "",
463 error_msg, 477 fperfdata("time", elapsed_time, "s", config.check_warning_time, config.warning_time,
464 elapsed_time, 478 config.check_critical_time, 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 479
471 return result; 480 exit(result);
472} 481}
473 482
474
475
476/* process command-line arguments */ 483/* process command-line arguments */
477int 484check_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 { 485 enum {
486 SNI_OPTION 486 SNI_OPTION = CHAR_MAX + 1
487 }; 487 };
488 488
489 int option = 0; 489 int option = 0;
490 static struct option longopts[] = { 490 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
491 {"hostname", required_argument, 0, 'H'}, 491 {"expect", required_argument, 0, 'e'},
492 {"expect", required_argument, 0, 'e'}, 492 {"critical", required_argument, 0, 'c'},
493 {"critical", required_argument, 0, 'c'}, 493 {"warning", required_argument, 0, 'w'},
494 {"warning", required_argument, 0, 'w'}, 494 {"timeout", required_argument, 0, 't'},
495 {"timeout", required_argument, 0, 't'}, 495 {"port", required_argument, 0, 'p'},
496 {"port", required_argument, 0, 'p'}, 496 {"from", required_argument, 0, 'f'},
497 {"from", required_argument, 0, 'f'}, 497 {"fqdn", required_argument, 0, 'F'},
498 {"fqdn", required_argument, 0, 'F'}, 498 {"authtype", required_argument, 0, 'A'},
499 {"authtype", required_argument, 0, 'A'}, 499 {"authuser", required_argument, 0, 'U'},
500 {"authuser", required_argument, 0, 'U'}, 500 {"authpass", required_argument, 0, 'P'},
501 {"authpass", required_argument, 0, 'P'}, 501 {"command", required_argument, 0, 'C'},
502 {"command", required_argument, 0, 'C'}, 502 {"response", required_argument, 0, 'R'},
503 {"response", required_argument, 0, 'R'}, 503 {"verbose", no_argument, 0, 'v'},
504 {"verbose", no_argument, 0, 'v'}, 504 {"version", no_argument, 0, 'V'},
505 {"version", no_argument, 0, 'V'}, 505 {"use-ipv4", no_argument, 0, '4'},
506 {"use-ipv4", no_argument, 0, '4'}, 506 {"use-ipv6", no_argument, 0, '6'},
507 {"use-ipv6", no_argument, 0, '6'}, 507 {"help", no_argument, 0, 'h'},
508 {"help", no_argument, 0, 'h'}, 508 {"lmtp", no_argument, 0, 'L'},
509 {"lmtp", no_argument, 0, 'L'}, 509 {"ssl", no_argument, 0, 's'},
510 {"ssl", no_argument, 0, 's'}, 510 {"tls", no_argument, 0, 's'},
511 {"tls", no_argument, 0, 's'}, 511 {"starttls", no_argument, 0, 'S'},
512 {"starttls",no_argument,0,'S'}, 512 {"sni", no_argument, 0, SNI_OPTION},
513 {"sni", no_argument, 0, SNI_OPTION}, 513 {"certificate", required_argument, 0, 'D'},
514 {"certificate",required_argument,0,'D'}, 514 {"ignore-quit-failure", no_argument, 0, 'q'},
515 {"ignore-quit-failure",no_argument,0,'q'}, 515 {"proxy", no_argument, 0, 'r'},
516 {"proxy",no_argument,0,'r'}, 516 {0, 0, 0, 0}};
517 {0, 0, 0, 0} 517
518 check_smtp_config_wrapper result = {
519 .config = check_smtp_config_init(),
520 .errorcode = OK,
518 }; 521 };
519 522
520 if (argc < 2) 523 if (argc < 2) {
521 return ERROR; 524 result.errorcode = ERROR;
525 return result;
526 }
522 527
523 for (c = 1; c < argc; c++) { 528 for (int index = 1; index < argc; index++) {
524 if (strcmp ("-to", argv[c]) == 0) 529 if (strcmp("-to", argv[index]) == 0) {
525 strcpy (argv[c], "-t"); 530 strcpy(argv[index], "-t");
526 else if (strcmp ("-wt", argv[c]) == 0) 531 } else if (strcmp("-wt", argv[index]) == 0) {
527 strcpy (argv[c], "-w"); 532 strcpy(argv[index], "-w");
528 else if (strcmp ("-ct", argv[c]) == 0) 533 } else if (strcmp("-ct", argv[index]) == 0) {
529 strcpy (argv[c], "-c"); 534 strcpy(argv[index], "-c");
535 }
530 } 536 }
531 537
532 while (1) { 538 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", 539 int response_size = 0;
534 longopts, &option); 540 bool implicit_tls = false;
541 int server_port_option = 0;
542 while (true) {
543 int opt_index =
544 getopt_long(argc, argv, "+hVv46Lrt:p:f:e:c:w:H:C:R:sSD:F:A:U:P:q", longopts, &option);
535 545
536 if (c == -1 || c == EOF) 546 if (opt_index == -1 || opt_index == EOF) {
537 break; 547 break;
548 }
538 549
539 switch (c) { 550 switch (opt_index) {
540 case 'H': /* hostname */ 551 case 'H': /* hostname */
541 if (is_host (optarg)) { 552 if (is_host(optarg)) {
542 server_address = optarg; 553 result.config.server_address = optarg;
543 } 554 } else {
544 else { 555 usage2(_("Invalid hostname/address"), optarg);
545 usage2 (_("Invalid hostname/address"), optarg);
546 } 556 }
547 break; 557 break;
548 case 'p': /* port */ 558 case 'p': /* port */
549 if (is_intpos (optarg)) 559 if (is_intpos(optarg)) {
550 server_port_option = atoi (optarg); 560 server_port_option = atoi(optarg);
551 else 561 } else {
552 usage4 (_("Port must be a positive integer")); 562 usage4(_("Port must be a positive integer"));
563 }
553 break; 564 break;
554 case 'F': 565 case 'F':
555 /* localhostname */ 566 /* localhostname */
556 localhostname = strdup(optarg); 567 result.config.localhostname = strdup(optarg);
557 break; 568 break;
558 case 'f': /* from argument */ 569 case 'f': /* from argument */
559 from_arg = optarg + strspn(optarg, "<"); 570 result.config.from_arg = optarg + strspn(optarg, "<");
560 from_arg = strndup(from_arg, strcspn(from_arg, ">")); 571 result.config.from_arg =
561 send_mail_from = 1; 572 strndup(result.config.from_arg, strcspn(result.config.from_arg, ">"));
573 result.config.send_mail_from = true;
562 break; 574 break;
563 case 'A': 575 case 'A':
564 authtype = optarg; 576 result.config.authtype = optarg;
565 use_ehlo = true; 577 result.config.use_ehlo = true;
566 break; 578 break;
567 case 'U': 579 case 'U':
568 authuser = optarg; 580 result.config.authuser = optarg;
569 break; 581 break;
570 case 'P': 582 case 'P':
571 authpass = optarg; 583 result.config.authpass = optarg;
572 break; 584 break;
573 case 'e': /* server expect string on 220 */ 585 case 'e': /* server expect string on 220 */
574 server_expect = optarg; 586 result.config.server_expect = optarg;
575 break; 587 break;
576 case 'C': /* commands */ 588 case 'C': /* commands */
577 if (ncommands >= command_size) { 589 if (result.config.ncommands >= command_size) {
578 command_size+=8; 590 command_size += 8;
579 commands = realloc (commands, sizeof(char *) * command_size); 591 result.config.commands =
580 if (commands == NULL) 592 realloc(result.config.commands, sizeof(char *) * command_size);
581 die (STATE_UNKNOWN, 593 if (result.config.commands == NULL) {
582 _("Could not realloc() units [%d]\n"), ncommands); 594 die(STATE_UNKNOWN, _("Could not realloc() units [%d]\n"),
595 result.config.ncommands);
596 }
583 } 597 }
584 commands[ncommands] = (char *) malloc (sizeof(char) * 255); 598 result.config.commands[result.config.ncommands] = (char *)malloc(sizeof(char) * 255);
585 strncpy (commands[ncommands], optarg, 255); 599 strncpy(result.config.commands[result.config.ncommands], optarg, 255);
586 ncommands++; 600 result.config.ncommands++;
587 break; 601 break;
588 case 'R': /* server responses */ 602 case 'R': /* server responses */
589 if (nresponses >= response_size) { 603 if (result.config.nresponses >= response_size) {
590 response_size += 8; 604 response_size += 8;
591 responses = realloc (responses, sizeof(char *) * response_size); 605 result.config.responses =
592 if (responses == NULL) 606 realloc(result.config.responses, sizeof(char *) * response_size);
593 die (STATE_UNKNOWN, 607 if (result.config.responses == NULL) {
594 _("Could not realloc() units [%d]\n"), nresponses); 608 die(STATE_UNKNOWN, _("Could not realloc() units [%d]\n"),
609 result.config.nresponses);
610 }
595 } 611 }
596 responses[nresponses] = (char *) malloc (sizeof(char) * 255); 612 result.config.responses[result.config.nresponses] = (char *)malloc(sizeof(char) * 255);
597 strncpy (responses[nresponses], optarg, 255); 613 strncpy(result.config.responses[result.config.nresponses], optarg, 255);
598 nresponses++; 614 result.config.nresponses++;
599 break; 615 break;
600 case 'c': /* critical time threshold */ 616 case 'c': /* critical time threshold */
601 if (!is_nonnegative (optarg)) 617 if (!is_nonnegative(optarg)) {
602 usage4 (_("Critical time must be a positive")); 618 usage4(_("Critical time must be a positive"));
603 else { 619 } else {
604 critical_time = strtod (optarg, NULL); 620 result.config.critical_time = strtod(optarg, NULL);
605 check_critical_time = true; 621 result.config.check_critical_time = true;
606 } 622 }
607 break; 623 break;
608 case 'w': /* warning time threshold */ 624 case 'w': /* warning time threshold */
609 if (!is_nonnegative (optarg)) 625 if (!is_nonnegative(optarg)) {
610 usage4 (_("Warning time must be a positive")); 626 usage4(_("Warning time must be a positive"));
611 else { 627 } else {
612 warning_time = strtod (optarg, NULL); 628 result.config.warning_time = strtod(optarg, NULL);
613 check_warning_time = true; 629 result.config.check_warning_time = true;
614 } 630 }
615 break; 631 break;
616 case 'v': /* verbose */ 632 case 'v': /* verbose */
617 verbose++; 633 verbose++;
618 break; 634 break;
619 case 'q': 635 case 'q':
620 ignore_send_quit_failure = true; /* ignore problem sending QUIT */ 636 result.config.ignore_send_quit_failure = true; /* ignore problem sending QUIT */
621 break; 637 break;
622 case 't': /* timeout */ 638 case 't': /* timeout */
623 if (is_intnonneg (optarg)) { 639 if (is_intnonneg(optarg)) {
624 socket_timeout = atoi (optarg); 640 socket_timeout = atoi(optarg);
625 } 641 } else {
626 else { 642 usage4(_("Timeout interval must be a positive integer"));
627 usage4 (_("Timeout interval must be a positive integer"));
628 } 643 }
629 break; 644 break;
630 case 'D': 645 case 'D': {
631 /* Check SSL cert validity */ 646 /* Check SSL cert validity */
632#ifdef USE_OPENSSL 647#ifdef USE_OPENSSL
633 if ((temp=strchr(optarg,','))!=NULL) { 648 char *temp;
634 *temp='\0'; 649 if ((temp = strchr(optarg, ',')) != NULL) {
635 if (!is_intnonneg (optarg)) 650 *temp = '\0';
636 usage2 ("Invalid certificate expiration period", optarg); 651 if (!is_intnonneg(optarg)) {
637 days_till_exp_warn = atoi(optarg); 652 usage2("Invalid certificate expiration period", optarg);
638 *temp=','; 653 }
639 temp++; 654 result.config.days_till_exp_warn = atoi(optarg);
640 if (!is_intnonneg (temp)) 655 *temp = ',';
641 usage2 (_("Invalid certificate expiration period"), temp); 656 temp++;
642 days_till_exp_crit = atoi (temp); 657 if (!is_intnonneg(temp)) {
643 } 658 usage2(_("Invalid certificate expiration period"), temp);
644 else { 659 }
645 days_till_exp_crit=0; 660 result.config.days_till_exp_crit = atoi(temp);
646 if (!is_intnonneg (optarg)) 661 } else {
647 usage2 ("Invalid certificate expiration period", optarg); 662 result.config.days_till_exp_crit = 0;
648 days_till_exp_warn = atoi (optarg); 663 if (!is_intnonneg(optarg)) {
649 } 664 usage2("Invalid certificate expiration period", optarg);
650 check_cert = true; 665 }
651 ignore_send_quit_failure = true; 666 result.config.days_till_exp_warn = atoi(optarg);
667 }
668 result.config.check_cert = true;
669 result.config.ignore_send_quit_failure = true;
652#else 670#else
653 usage (_("SSL support not available - install OpenSSL and recompile")); 671 usage(_("SSL support not available - install OpenSSL and recompile"));
654#endif 672#endif
655 implicit_tls = true; 673 implicit_tls = true;
656 // fallthrough 674 // fallthrough
657 case 's': 675 case 's':
658 /* ssl */ 676 /* ssl */
659 use_ssl = true; 677 result.config.use_ssl = true;
660 server_port = SMTPS_PORT; 678 result.config.server_port = SMTPS_PORT;
661 break; 679 break;
662 case 'S': 680 case 'S':
663 /* starttls */ 681 /* starttls */
664 use_starttls = true; 682 result.config.use_starttls = true;
665 use_ehlo = true; 683 result.config.use_ehlo = true;
666 break; 684 break;
685 }
667 case SNI_OPTION: 686 case SNI_OPTION:
668#ifdef HAVE_SSL 687#ifdef HAVE_SSL
669 use_sni = true; 688 result.config.use_sni = true;
670#else 689#else
671 usage (_("SSL support not available - install OpenSSL and recompile")); 690 usage(_("SSL support not available - install OpenSSL and recompile"));
672#endif 691#endif
673 break; 692 break;
674 case 'r': 693 case 'r':
675 use_proxy_prefix = true; 694 result.config.use_proxy_prefix = true;
676 break; 695 break;
677 case 'L': 696 case 'L':
678 use_lhlo = true; 697 result.config.use_lhlo = true;
679 break; 698 break;
680 case '4': 699 case '4':
681 address_family = AF_INET; 700 address_family = AF_INET;
@@ -684,102 +703,81 @@ process_arguments (int argc, char **argv)
684#ifdef USE_IPV6 703#ifdef USE_IPV6
685 address_family = AF_INET6; 704 address_family = AF_INET6;
686#else 705#else
687 usage4 (_("IPv6 support not available")); 706 usage4(_("IPv6 support not available"));
688#endif 707#endif
689 break; 708 break;
690 case 'V': /* version */ 709 case 'V': /* version */
691 print_revision (progname, NP_VERSION); 710 print_revision(progname, NP_VERSION);
692 exit (STATE_UNKNOWN); 711 exit(STATE_UNKNOWN);
693 case 'h': /* help */ 712 case 'h': /* help */
694 print_help (); 713 print_help();
695 exit (STATE_UNKNOWN); 714 exit(STATE_UNKNOWN);
696 case '?': /* help */ 715 case '?': /* help */
697 usage5 (); 716 usage5();
698 } 717 }
699 } 718 }
700 719
701 c = optind; 720 int c = optind;
702 if (server_address == NULL) { 721 if (result.config.server_address == NULL) {
703 if (argv[c]) { 722 if (argv[c]) {
704 if (is_host (argv[c])) 723 if (is_host(argv[c])) {
705 server_address = argv[c]; 724 result.config.server_address = argv[c];
706 else 725 } else {
707 usage2 (_("Invalid hostname/address"), argv[c]); 726 usage2(_("Invalid hostname/address"), argv[c]);
708 } 727 }
709 else { 728 } else {
710 xasprintf (&server_address, "127.0.0.1"); 729 result.config.server_address = strdup("localhost");
711 } 730 }
712 } 731 }
713 732
714 if (server_expect == NULL) 733 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) { 734 if (implicit_tls) {
725 use_ssl = false; 735 result.config.use_ssl = false;
726 server_port = SMTP_PORT;
727 } else { 736 } else {
728 usage4 (_("Set either -s/--ssl/--tls or -S/--starttls")); 737 usage4(_("Set either -s/--ssl/--tls or -S/--starttls"));
729 } 738 }
730 } 739 }
731 740
732 if (server_port_option != 0) { 741 if (server_port_option != 0) {
733 server_port = server_port_option; 742 result.config.server_port = server_port_option;
734 } 743 }
735 744
736 return validate_arguments (); 745 return result;
737}
738
739
740
741int
742validate_arguments (void)
743{
744 return OK;
745} 746}
746 747
747 748char *smtp_quit(check_smtp_config config, char buffer[MAX_INPUT_BUFFER], int socket_descriptor,
748void 749 bool ssl_established) {
749smtp_quit(void) 750 int sent_bytes =
750{ 751 my_send(config, SMTP_QUIT, strlen(SMTP_QUIT), socket_descriptor, ssl_established);
751 int bytes; 752 if (sent_bytes < 0) {
752 int n; 753 if (config.ignore_send_quit_failure) {
753 754 if (verbose) {
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")); 755 printf(_("Connection closed by server before sending QUIT command\n"));
759 } 756 }
760 return; 757 return buffer;
761 } 758 }
762 die (STATE_UNKNOWN, 759 die(STATE_UNKNOWN, _("Connection closed by server before sending QUIT command\n"));
763 _("Connection closed by server before sending QUIT command\n"));
764 } 760 }
765 761
766 if (verbose) 762 if (verbose) {
767 printf(_("sent %s\n"), "QUIT"); 763 printf(_("sent %s\n"), "QUIT");
764 }
768 765
769 /* read the response but don't care about problems */ 766 /* read the response but don't care about problems */
770 bytes = recvlines(buffer, MAX_INPUT_BUFFER); 767 int bytes = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established);
771 if (verbose) { 768 if (verbose) {
772 if (bytes < 0) 769 if (bytes < 0) {
773 printf(_("recv() failed after QUIT.")); 770 printf(_("recv() failed after QUIT."));
774 else if (bytes == 0) 771 } else if (bytes == 0) {
775 printf(_("Connection reset by peer.")); 772 printf(_("Connection reset by peer."));
776 else { 773 } else {
777 buffer[bytes] = '\0'; 774 buffer[bytes] = '\0';
778 printf(_("received %s\n"), buffer); 775 printf(_("received %s\n"), buffer);
779 } 776 }
780 } 777 }
781}
782 778
779 return buffer;
780}
783 781
784/* 782/*
785 * Receive one line, copy it into buf and nul-terminate it. Returns the 783 * Receive one line, copy it into buf and nul-terminate it. Returns the
@@ -790,24 +788,23 @@ smtp_quit(void)
790 * function which buffers the data, move that to netutils.c and change 788 * 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. 789 * check_smtp and other plugins to use that. Also, remove (\r)\n.
792 */ 790 */
793int 791int recvline(char *buf, size_t bufsize, check_smtp_config config, int socket_descriptor,
794recvline(char *buf, size_t bufsize) 792 bool ssl_established) {
795{
796 int result; 793 int result;
797 unsigned i; 794 int counter;
798 795
799 for (i = result = 0; i < bufsize - 1; i++) { 796 for (counter = result = 0; counter < bufsize - 1; counter++) {
800 if ((result = my_recv(&buf[i], 1)) != 1) 797 if ((result = my_recv(config, &buf[counter], 1, socket_descriptor, ssl_established)) != 1) {
801 break; 798 break;
802 if (buf[i] == '\n') { 799 }
803 buf[++i] = '\0'; 800 if (buf[counter] == '\n') {
804 return i; 801 buf[++counter] = '\0';
802 return counter;
805 } 803 }
806 } 804 }
807 return (result == 1 || i == 0) ? -2 : result; /* -2 if out of space */ 805 return (result == 1 || counter == 0) ? -2 : result; /* -2 if out of space */
808} 806}
809 807
810
811/* 808/*
812 * Receive one or more lines, copy them into buf and nul-terminate it. Returns 809 * 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 810 * the number of bytes written to buf (excluding the '\0') or 0 on EOF or <0 on
@@ -822,117 +819,110 @@ recvline(char *buf, size_t bufsize)
822 * 819 *
823 * TODO: Move this to netutils.c. Also, remove \r and possibly the final \n. 820 * TODO: Move this to netutils.c. Also, remove \r and possibly the final \n.
824 */ 821 */
825int 822int recvlines(check_smtp_config config, char *buf, size_t bufsize, int socket_descriptor,
826recvlines(char *buf, size_t bufsize) 823 bool ssl_established) {
827{ 824 int result;
828 int result, i; 825 int counter;
829 826
830 for (i = 0; /* forever */; i += result) 827 for (counter = 0; /* forever */; counter += result) {
831 if (!((result = recvline(buf + i, bufsize - i)) > 3 && 828 if (!((result = recvline(buf + counter, bufsize - counter, config, socket_descriptor,
832 isdigit((int)buf[i]) && 829 ssl_established)) > 3 &&
833 isdigit((int)buf[i + 1]) && 830 isdigit((int)buf[counter]) && isdigit((int)buf[counter + 1]) &&
834 isdigit((int)buf[i + 2]) && 831 isdigit((int)buf[counter + 2]) && buf[counter + 3] == '-')) {
835 buf[i + 3] == '-'))
836 break; 832 break;
833 }
834 }
837 835
838 return (result <= 0) ? result : result + i; 836 return (result <= 0) ? result : result + counter;
839} 837}
840 838
841 839int my_close(int socket_descriptor) {
842int
843my_close (void)
844{
845 int result; 840 int result;
846 result = close(sd); 841 result = close(socket_descriptor);
847#ifdef HAVE_SSL 842#ifdef HAVE_SSL
848 np_net_ssl_cleanup(); 843 np_net_ssl_cleanup();
849#endif 844#endif
850 return result; 845 return result;
851} 846}
852 847
853 848void print_help(void) {
854void
855print_help (void)
856{
857 char *myport; 849 char *myport;
858 xasprintf (&myport, "%d", SMTP_PORT); 850 xasprintf(&myport, "%d", SMTP_PORT);
859 851
860 print_revision (progname, NP_VERSION); 852 print_revision(progname, NP_VERSION);
861 853
862 printf ("Copyright (c) 1999-2001 Ethan Galstad <nagios@nagios.org>\n"); 854 printf("Copyright (c) 1999-2001 Ethan Galstad <nagios@nagios.org>\n");
863 printf (COPYRIGHT, copyright, email); 855 printf(COPYRIGHT, copyright, email);
864 856
865 printf("%s\n", _("This plugin will attempt to open an SMTP connection with the host.")); 857 printf("%s\n", _("This plugin will attempt to open an SMTP connection with the host."));
866 858
867 printf ("\n\n"); 859 printf("\n\n");
868 860
869 print_usage (); 861 print_usage();
870 862
871 printf (UT_HELP_VRSN); 863 printf(UT_HELP_VRSN);
872 printf (UT_EXTRA_OPTS); 864 printf(UT_EXTRA_OPTS);
873 865
874 printf (UT_HOST_PORT, 'p', myport); 866 printf(UT_HOST_PORT, 'p', myport);
875 867
876 printf (UT_IPv46); 868 printf(UT_IPv46);
877 869
878 printf (" %s\n", "-e, --expect=STRING"); 870 printf(" %s\n", "-e, --expect=STRING");
879 printf (_(" String to expect in first line of server response (default: '%s')\n"), SMTP_EXPECT); 871 printf(_(" String to expect in first line of server response (default: '%s')\n"),
880 printf (" %s\n", "-C, --command=STRING"); 872 SMTP_EXPECT);
881 printf (" %s\n", _("SMTP command (may be used repeatedly)")); 873 printf(" %s\n", "-C, --command=STRING");
882 printf (" %s\n", "-R, --response=STRING"); 874 printf(" %s\n", _("SMTP command (may be used repeatedly)"));
883 printf (" %s\n", _("Expected response to command (may be used repeatedly)")); 875 printf(" %s\n", "-R, --response=STRING");
884 printf (" %s\n", "-f, --from=STRING"); 876 printf(" %s\n", _("Expected response to command (may be used repeatedly)"));
885 printf (" %s\n", _("FROM-address to include in MAIL command, required by Exchange 2000")), 877 printf(" %s\n", "-f, --from=STRING");
886 printf (" %s\n", "-F, --fqdn=STRING"); 878 printf(" %s\n", _("FROM-address to include in MAIL command, required by Exchange 2000")),
887 printf (" %s\n", _("FQDN used for HELO")); 879 printf(" %s\n", "-F, --fqdn=STRING");
888 printf (" %s\n", "-r, --proxy"); 880 printf(" %s\n", _("FQDN used for HELO"));
889 printf (" %s\n", _("Use PROXY protocol prefix for the connection.")); 881 printf(" %s\n", "-r, --proxy");
882 printf(" %s\n", _("Use PROXY protocol prefix for the connection."));
890#ifdef HAVE_SSL 883#ifdef HAVE_SSL
891 printf (" %s\n", "-D, --certificate=INTEGER[,INTEGER]"); 884 printf(" %s\n", "-D, --certificate=INTEGER[,INTEGER]");
892 printf (" %s\n", _("Minimum number of days a certificate has to be valid.")); 885 printf(" %s\n", _("Minimum number of days a certificate has to be valid."));
893 printf (" %s\n", "-s, --ssl, --tls"); 886 printf(" %s\n", "-s, --ssl, --tls");
894 printf (" %s\n", _("Use SSL/TLS for the connection.")); 887 printf(" %s\n", _("Use SSL/TLS for the connection."));
895 printf (_(" Sets default port to %d.\n"), SMTPS_PORT); 888 printf(_(" Sets default port to %d.\n"), SMTPS_PORT);
896 printf (" %s\n", "-S, --starttls"); 889 printf(" %s\n", "-S, --starttls");
897 printf (" %s\n", _("Use STARTTLS for the connection.")); 890 printf(" %s\n", _("Use STARTTLS for the connection."));
898 printf (" %s\n", "--sni"); 891 printf(" %s\n", "--sni");
899 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)")); 892 printf(" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
900#endif 893#endif
901 894
902 printf (" %s\n", "-A, --authtype=STRING"); 895 printf(" %s\n", "-A, --authtype=STRING");
903 printf (" %s\n", _("SMTP AUTH type to check (default none, only LOGIN supported)")); 896 printf(" %s\n", _("SMTP AUTH type to check (default none, only LOGIN supported)"));
904 printf (" %s\n", "-U, --authuser=STRING"); 897 printf(" %s\n", "-U, --authuser=STRING");
905 printf (" %s\n", _("SMTP AUTH username")); 898 printf(" %s\n", _("SMTP AUTH username"));
906 printf (" %s\n", "-P, --authpass=STRING"); 899 printf(" %s\n", "-P, --authpass=STRING");
907 printf (" %s\n", _("SMTP AUTH password")); 900 printf(" %s\n", _("SMTP AUTH password"));
908 printf (" %s\n", "-L, --lmtp"); 901 printf(" %s\n", "-L, --lmtp");
909 printf (" %s\n", _("Send LHLO instead of HELO/EHLO")); 902 printf(" %s\n", _("Send LHLO instead of HELO/EHLO"));
910 printf (" %s\n", "-q, --ignore-quit-failure"); 903 printf(" %s\n", "-q, --ignore-quit-failure");
911 printf (" %s\n", _("Ignore failure when sending QUIT command to server")); 904 printf(" %s\n", _("Ignore failure when sending QUIT command to server"));
912
913 printf (UT_WARN_CRIT);
914 905
915 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 906 printf(UT_WARN_CRIT);
916 907
917 printf (UT_VERBOSE); 908 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
909
910 printf(UT_VERBOSE);
918 911
919 printf("\n"); 912 printf("\n");
920 printf ("%s\n", _("Successful connects return STATE_OK, refusals and timeouts return")); 913 printf("%s\n", _("Successful connects return STATE_OK, refusals and timeouts return"));
921 printf ("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful")); 914 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")); 915 printf("%s\n", _("connects, but incorrect response messages from the host result in"));
923 printf ("%s\n", _("STATE_WARNING return values.")); 916 printf("%s\n", _("STATE_WARNING return values."));
924 917
925 printf (UT_SUPPORT); 918 printf(UT_SUPPORT);
926} 919}
927 920
928 921void print_usage(void) {
929 922 printf("%s\n", _("Usage:"));
930void 923 printf("%s -H host [-p port] [-4|-6] [-e expect] [-C command] [-R response] [-f from addr]\n",
931print_usage (void) 924 progname);
932{ 925 printf("[-A authtype -U authuser -P authpass] [-w warn] [-c crit] [-t timeout] [-q]\n");
933 printf ("%s\n", _("Usage:")); 926 printf("[-F fqdn] [-S] [-L] [-D warn days cert expire[,crit days cert expire]] [-r] [--sni] "
934 printf ("%s -H host [-p port] [-4|-6] [-e expect] [-C command] [-R response] [-f from addr]\n", progname); 927 "[-v] \n");
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} 928}
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 937b3a5d..f470d222 100644
--- a/plugins/check_snmp.c
+++ b/plugins/check_snmp.c
@@ -1,699 +1,395 @@
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"
36#include "runcmd.h" 36#include "./runcmd.h"
37#include "utils.h" 37#include "./utils.h"
38#include "utils_cmd.h" 38#include "../lib/states.h"
39 39
40#define DEFAULT_COMMUNITY "public" 40#include "../lib/utils_base.h"
41#define DEFAULT_PORT "161" 41#include "../lib/output.h"
42#define DEFAULT_MIBLIST "ALL" 42#include "check_snmp.d/check_snmp_helpers.h"
43#define DEFAULT_PROTOCOL "1" 43
44#define DEFAULT_RETRIES 5 44#include <strings.h>
45#include <stdint.h>
46
47#include "check_snmp.d/config.h"
48#include <stdlib.h>
49#include <arpa/inet.h>
50#include <net-snmp/library/parse.h>
51#include <net-snmp/net-snmp-config.h>
52#include <net-snmp/net-snmp-includes.h>
53#include <net-snmp/library/snmp.h>
54#include <net-snmp/library/keytools.h>
55#include <net-snmp/library/snmp_api.h>
56#include <net-snmp/session_api.h>
57#include <net-snmp/definitions.h>
58#include <net-snmp/library/asn1.h>
59#include <net-snmp/mib_api.h>
60#include <net-snmp/library/snmp_impl.h>
61#include <string.h>
62#include "../gl/regex.h"
63#include "../gl/base64.h"
64#include <assert.h>
65
66const char DEFAULT_COMMUNITY[] = "public";
67const char DEFAULT_MIBLIST[] = "ALL";
45#define DEFAULT_AUTH_PROTOCOL "MD5" 68#define DEFAULT_AUTH_PROTOCOL "MD5"
46#define DEFAULT_PRIV_PROTOCOL "DES"
47#define DEFAULT_DELIMITER "="
48#define DEFAULT_OUTPUT_DELIMITER " "
49#define DEFAULT_BUFFER_SIZE 100
50
51#define mark(a) ((a)!=0?"*":"")
52
53#define CHECK_UNDEF 0
54#define CRIT_PRESENT 1
55#define CRIT_STRING 2
56#define CRIT_REGEX 4
57#define WARN_PRESENT 8
58#define WARN_STRING 16
59#define WARN_REGEX 32
60
61#define OID_COUNT_STEP 8
62
63/* Longopts only arguments */
64#define L_CALCULATE_RATE CHAR_MAX+1
65#define L_RATE_MULTIPLIER CHAR_MAX+2
66#define L_INVERT_SEARCH CHAR_MAX+3
67#define L_OFFSET CHAR_MAX+4
68#define L_IGNORE_MIB_PARSING_ERRORS CHAR_MAX+5
69
70/* Gobble to string - stop incrementing c when c[0] match one of the
71 * characters in s */
72#define GOBBLE_TOS(c, s) while(c[0]!='\0' && strchr(s, c[0])==NULL) { c++; }
73/* Given c, keep track of backslashes (bk) and double-quotes (dq)
74 * from c[0] */
75#define COUNT_SEQ(c, bk, dq) switch(c[0]) {\
76 case '\\': \
77 if (bk) bk--; \
78 else bk++; \
79 break; \
80 case '"': \
81 if (!dq) { dq++; } \
82 else if(!bk) { dq--; } \
83 else { bk--; } \
84 break; \
85 }
86
87
88 69
89int process_arguments (int, char **); 70#ifdef HAVE_USM_DES_PRIV_PROTOCOL
90int validate_arguments (void); 71# define DEFAULT_PRIV_PROTOCOL "DES"
91char *thisarg (char *str); 72#else
92char *nextarg (char *str); 73# define DEFAULT_PRIV_PROTOCOL "AES"
93void print_usage (void); 74#endif
94void print_help (void);
95char *multiply (char *str);
96
97#include "regex.h"
98char regex_expect[MAX_INPUT_BUFFER] = "";
99regex_t preg;
100regmatch_t pmatch[10];
101char errbuf[MAX_INPUT_BUFFER] = "";
102char perfstr[MAX_INPUT_BUFFER] = "| ";
103int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
104int eflags = 0;
105int errcode, excode;
106
107char *server_address = NULL;
108char *community = NULL;
109char **contextargs = NULL;
110char *context = NULL;
111char **authpriv = NULL;
112char *proto = NULL;
113char *seclevel = NULL;
114char *secname = NULL;
115char *authproto = NULL;
116char *privproto = NULL;
117char *authpasswd = NULL;
118char *privpasswd = NULL;
119int nulloid = STATE_UNKNOWN;
120char **oids = NULL;
121size_t oids_size = 0;
122char *label;
123char *units;
124char *port;
125char *snmpcmd;
126char string_value[MAX_INPUT_BUFFER] = "";
127int invert_search=0;
128char **labels = NULL;
129char **unitv = NULL;
130size_t nlabels = 0;
131size_t labels_size = OID_COUNT_STEP;
132size_t nunits = 0;
133size_t unitv_size = OID_COUNT_STEP;
134size_t numoids = 0;
135int numauthpriv = 0;
136int numcontext = 0;
137int verbose = 0;
138bool usesnmpgetnext = false;
139char *warning_thresholds = NULL;
140char *critical_thresholds = NULL;
141thresholds **thlds;
142size_t thlds_size = OID_COUNT_STEP;
143double *response_value;
144size_t response_size = OID_COUNT_STEP;
145int retries = 0;
146int *eval_method;
147size_t eval_size = OID_COUNT_STEP;
148char *delimiter;
149char *output_delim;
150char *miblist = NULL;
151bool needmibs = false;
152int calculate_rate = 0;
153double offset = 0.0;
154int rate_multiplier = 1;
155state_data *previous_state;
156double *previous_value;
157size_t previous_size = OID_COUNT_STEP;
158int perf_labels = 1;
159char* ip_version = "";
160double multiplier = 1.0;
161char *fmtstr = "";
162bool fmtstr_set = false;
163char buffer[DEFAULT_BUFFER_SIZE];
164bool ignore_mib_parsing_errors = false;
165
166static char *fix_snmp_range(char *th)
167{
168 double left, right;
169 char *colon, *ret;
170
171 if ((colon = strchr(th, ':')) == NULL || *(colon + 1) == '\0')
172 return th;
173
174 left = strtod(th, NULL);
175 right = strtod(colon + 1, NULL);
176 if (right >= left)
177 return th;
178
179 if ((ret = malloc(strlen(th) + 2)) == NULL)
180 die(STATE_UNKNOWN, _("Cannot malloc"));
181 *colon = '\0';
182 sprintf(ret, "@%s:%s", colon + 1, th);
183 free(th);
184 return ret;
185}
186 75
187int 76typedef struct proces_arguments_wrapper {
188main (int argc, char **argv) 77 int errorcode;
189{ 78 check_snmp_config config;
190 int len, total_oids; 79} process_arguments_wrapper;
191 size_t line;
192 unsigned int bk_count = 0, dq_count = 0;
193 int iresult = STATE_UNKNOWN;
194 int result = STATE_UNKNOWN;
195 int return_code = 0;
196 int external_error = 0;
197 char **command_line = NULL;
198 char *cl_hidden_auth = NULL;
199 char *oidname = NULL;
200 char *response = NULL;
201 char *mult_resp = NULL;
202 char *outbuff;
203 char *ptr = NULL;
204 char *show = NULL;
205 char *th_warn=NULL;
206 char *th_crit=NULL;
207 char type[8] = "";
208 output chld_out, chld_err;
209 char *previous_string=NULL;
210 char *ap=NULL;
211 char *state_string=NULL;
212 size_t response_length, current_length, string_length;
213 char *temp_string=NULL;
214 char *quote_string=NULL;
215 time_t current_time;
216 double temp_double;
217 time_t duration;
218 char *conv = "12345678";
219 int is_counter=0;
220
221 setlocale (LC_ALL, "");
222 bindtextdomain (PACKAGE, LOCALEDIR);
223 textdomain (PACKAGE);
224
225 labels = malloc (labels_size * sizeof(*labels));
226 unitv = malloc (unitv_size * sizeof(*unitv));
227 thlds = malloc (thlds_size * sizeof(*thlds));
228 response_value = malloc (response_size * sizeof(*response_value));
229 previous_value = malloc (previous_size * sizeof(*previous_value));
230 eval_method = calloc (eval_size, sizeof(*eval_method));
231 oids = calloc(oids_size, sizeof (char *));
232
233 label = strdup ("SNMP");
234 units = strdup ("");
235 port = strdup (DEFAULT_PORT);
236 outbuff = strdup ("");
237 delimiter = strdup (" = ");
238 output_delim = strdup (DEFAULT_OUTPUT_DELIMITER);
239 timeout_interval = DEFAULT_SOCKET_TIMEOUT;
240 retries = DEFAULT_RETRIES;
241 80
242 np_init( (char *) progname, argc, argv ); 81static process_arguments_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
82static char *trim_whitespaces_and_check_quoting(char *str);
83static char *get_next_argument(char *str);
84void print_usage(void);
85void print_help(void);
243 86
244 /* Parse extra opts if any */ 87int verbose = 0;
245 argv=np_extra_opts (&argc, argv, progname);
246
247 np_set_args(argc, argv);
248 88
249 time(&current_time); 89typedef struct {
90 int errorcode;
91 char *state_string;
92} gen_state_string_type;
93gen_state_string_type gen_state_string(check_snmp_state_entry *entries, size_t num_of_entries) {
94 char *encoded_string = NULL;
95 gen_state_string_type result = {.errorcode = OK, .state_string = NULL};
96
97 if (verbose > 1) {
98 printf("%s:\n", __FUNCTION__);
99 for (size_t i = 0; i < num_of_entries; i++) {
100 printf("Entry timestamp %lu: %s", entries[i].timestamp, ctime(&entries[i].timestamp));
101 switch (entries[i].type) {
102 case ASN_GAUGE:
103 printf("Type GAUGE\n");
104 break;
105 case ASN_TIMETICKS:
106 printf("Type TIMETICKS\n");
107 break;
108 case ASN_COUNTER:
109 printf("Type COUNTER\n");
110 break;
111 case ASN_UINTEGER:
112 printf("Type UINTEGER\n");
113 break;
114 case ASN_COUNTER64:
115 printf("Type COUNTER64\n");
116 break;
117 case ASN_FLOAT:
118 printf("Type FLOAT\n");
119 case ASN_DOUBLE:
120 printf("Type DOUBLE\n");
121 break;
122 case ASN_INTEGER:
123 printf("Type INTEGER\n");
124 break;
125 }
250 126
251 if (process_arguments (argc, argv) == ERROR) 127 switch (entries[i].type) {
252 usage4 (_("Could not parse arguments")); 128 case ASN_GAUGE:
253 129 case ASN_TIMETICKS:
254 if(calculate_rate) { 130 case ASN_COUNTER:
255 if (!strcmp(label, "SNMP")) 131 case ASN_UINTEGER:
256 label = strdup("SNMP RATE"); 132 case ASN_COUNTER64:
257 133 printf("Value %llu\n", entries[i].value.uIntVal);
258 size_t i = 0; 134 break;
259 135 case ASN_FLOAT:
260 previous_state = np_state_read(); 136 case ASN_DOUBLE:
261 if(previous_state!=NULL) { 137 printf("Value %f\n", entries[i].value.doubleVal);
262 /* Split colon separated values */ 138 break;
263 previous_string = strdup((char *) previous_state->data); 139 case ASN_INTEGER:
264 while((ap = strsep(&previous_string, ":")) != NULL) { 140 printf("Value %lld\n", entries[i].value.intVal);
265 if(verbose>2) 141 break;
266 printf("State for %zd=%s\n", i, ap);
267 while (i >= previous_size) {
268 previous_size += OID_COUNT_STEP;
269 previous_value = realloc(previous_value, previous_size * sizeof(*previous_value));
270 }
271 previous_value[i++]=strtod(ap,NULL);
272 } 142 }
273 } 143 }
274 } 144 }
275 145
276 /* Populate the thresholds */ 146 idx_t encoded = base64_encode_alloc((const char *)entries,
277 th_warn=warning_thresholds; 147 (idx_t)(num_of_entries * sizeof(check_snmp_state_entry)),
278 th_crit=critical_thresholds; 148 &encoded_string);
279 for (size_t i = 0; i < numoids; i++) {
280 char *w = th_warn ? strndup(th_warn, strcspn(th_warn, ",")) : NULL;
281 char *c = th_crit ? strndup(th_crit, strcspn(th_crit, ",")) : NULL;
282 /* translate "2:1" to "@1:2" for backwards compatibility */
283 w = w ? fix_snmp_range(w) : NULL;
284 c = c ? fix_snmp_range(c) : NULL;
285
286 while (i >= thlds_size) {
287 thlds_size += OID_COUNT_STEP;
288 thlds = realloc(thlds, thlds_size * sizeof(*thlds));
289 }
290 149
291 /* Skip empty thresholds, while avoiding segfault */ 150 if (encoded > 0 && encoded_string != NULL) {
292 set_thresholds(&thlds[i], 151 // success
293 w ? strpbrk(w, NP_THRESHOLDS_CHARS) : NULL, 152 if (verbose > 1) {
294 c ? strpbrk(c, NP_THRESHOLDS_CHARS) : NULL); 153 printf("encoded string: %s\n", encoded_string);
295 if (w) { 154 printf("encoded string length: %lu\n", strlen(encoded_string));
296 th_warn=strchr(th_warn, ',');
297 if (th_warn) th_warn++;
298 free(w);
299 }
300 if (c) {
301 th_crit=strchr(th_crit, ',');
302 if (th_crit) th_crit++;
303 free(c);
304 } 155 }
156 result.state_string = encoded_string;
157 return result;
305 } 158 }
159 result.errorcode = ERROR;
160 return result;
161}
306 162
307 /* Create the command array to execute */ 163typedef struct {
308 if(usesnmpgetnext) { 164 int errorcode;
309 snmpcmd = strdup (PATH_TO_SNMPGETNEXT); 165 check_snmp_state_entry *state;
310 }else{ 166} recover_state_data_type;
311 snmpcmd = strdup (PATH_TO_SNMPGET); 167recover_state_data_type recover_state_data(char *state_string, idx_t state_string_length) {
168 recover_state_data_type result = {.errorcode = OK, .state = NULL};
169
170 if (verbose > 1) {
171 printf("%s:\n", __FUNCTION__);
172 printf("State string: %s\n", state_string);
173 printf("State string length: %lu\n", state_string_length);
312 } 174 }
313 175
314 /* 10 arguments to pass before context and authpriv options + 1 for host and numoids. Add one for terminating NULL */ 176 idx_t outlen = 0;
177 bool decoded =
178 base64_decode_alloc(state_string, state_string_length, (char **)&result.state, &outlen);
315 179
316 unsigned index = 0; 180 if (!decoded) {
317 command_line = calloc (11 + numcontext + numauthpriv + 1 + numoids + 1, sizeof (char *)); 181 if (verbose) {
182 printf("Failed to decode state string\n");
183 }
184 // failure to decode
185 result.errorcode = ERROR;
186 return result;
187 }
318 188
319 command_line[index++] = snmpcmd; 189 if (result.state == NULL) {
320 command_line[index++] = strdup ("-Le"); 190 // Memory Error?
321 command_line[index++] = strdup ("-t"); 191 result.errorcode = ERROR;
322 xasprintf (&command_line[index++], "%d", timeout_interval); 192 return result;
323 command_line[index++] = strdup ("-r"); 193 }
324 xasprintf (&command_line[index++], "%d", retries);
325 command_line[index++] = strdup ("-m");
326 command_line[index++] = strdup (miblist);
327 command_line[index++] = "-v";
328 command_line[index++] = strdup (proto);
329 194
330 xasprintf(&cl_hidden_auth, "%s -Le -t %d -r %d -m %s -v %s", 195 if (verbose > 1) {
331 snmpcmd, timeout_interval, retries, strlen(miblist) ? miblist : "''", proto); 196 printf("Recovered %lu entries of size %lu\n",
197 (size_t)outlen / sizeof(check_snmp_state_entry), outlen);
198
199 for (size_t i = 0; i < (size_t)outlen / sizeof(check_snmp_state_entry); i++) {
200 printf("Entry timestamp %lu: %s", result.state[i].timestamp,
201 ctime(&result.state[i].timestamp));
202 switch (result.state[i].type) {
203 case ASN_GAUGE:
204 printf("Type GAUGE\n");
205 break;
206 case ASN_TIMETICKS:
207 printf("Type TIMETICKS\n");
208 break;
209 case ASN_COUNTER:
210 printf("Type COUNTER\n");
211 break;
212 case ASN_UINTEGER:
213 printf("Type UINTEGER\n");
214 break;
215 case ASN_COUNTER64:
216 printf("Type COUNTER64\n");
217 break;
218 case ASN_FLOAT:
219 printf("Type FLOAT\n");
220 case ASN_DOUBLE:
221 printf("Type DOUBLE\n");
222 break;
223 case ASN_INTEGER:
224 printf("Type INTEGER\n");
225 break;
226 }
332 227
333 if (ignore_mib_parsing_errors) { 228 switch (result.state[i].type) {
334 command_line[index++] = "-Pe"; 229 case ASN_GAUGE:
335 xasprintf(&cl_hidden_auth, "%s -Pe", cl_hidden_auth); 230 case ASN_TIMETICKS:
231 case ASN_COUNTER:
232 case ASN_UINTEGER:
233 case ASN_COUNTER64:
234 printf("Value %llu\n", result.state[i].value.uIntVal);
235 break;
236 case ASN_FLOAT:
237 case ASN_DOUBLE:
238 printf("Value %f\n", result.state[i].value.doubleVal);
239 break;
240 case ASN_INTEGER:
241 printf("Value %lld\n", result.state[i].value.intVal);
242 break;
243 }
244 }
336 } 245 }
337 246
247 return result;
248}
338 249
339 for (int i = 0; i < numcontext; i++) { 250int main(int argc, char **argv) {
340 command_line[index++] = contextargs[i]; 251 setlocale(LC_ALL, "");
341 } 252 bindtextdomain(PACKAGE, LOCALEDIR);
253 textdomain(PACKAGE);
342 254
343 for (int i = 0; i < numauthpriv; i++) { 255 timeout_interval = DEFAULT_SOCKET_TIMEOUT;
344 command_line[index++] = authpriv[i];
345 }
346 256
347 xasprintf (&command_line[index++], "%s:%s", server_address, port); 257 np_init((char *)progname, argc, argv);
348 258
349 xasprintf(&cl_hidden_auth, "%s [context] [authpriv] %s:%s", 259 state_key stateKey = np_enable_state(NULL, 1, progname, argc, argv);
350 cl_hidden_auth,
351 server_address,
352 port);
353 260
354 for (size_t i = 0; i < numoids; i++) { 261 /* Parse extra opts if any */
355 command_line[index++] = oids[i]; 262 argv = np_extra_opts(&argc, argv, progname);
356 xasprintf(&cl_hidden_auth, "%s %s", cl_hidden_auth, oids[i]);
357 }
358 263
359 command_line[index++] = NULL; 264 np_set_args(argc, argv);
360 265
361 if (verbose) { 266 // Initialize net-snmp before touching the session we are going to use
362 printf ("%s\n", cl_hidden_auth); 267 init_snmp("check_snmp");
363 }
364 268
365 /* Set signal handling and alarm */ 269 process_arguments_wrapper paw_tmp = process_arguments(argc, argv);
366 if (signal (SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) { 270 if (paw_tmp.errorcode == ERROR) {
367 usage4 (_("Cannot catch SIGALRM")); 271 usage4(_("Could not parse arguments"));
368 }
369 alarm(timeout_interval * retries + 5);
370
371 /* Run the command */
372 return_code = cmd_run_array (command_line, &chld_out, &chld_err, 0);
373
374 /* disable alarm again */
375 alarm(0);
376
377 /* Due to net-snmp sometimes showing stderr messages with poorly formed MIBs,
378 only return state unknown if return code is non zero or there is no stdout.
379 Do this way so that if there is stderr, will get added to output, which helps problem diagnosis
380 */
381 if (return_code != 0)
382 external_error=1;
383 if (chld_out.lines == 0)
384 external_error=1;
385 if (external_error) {
386 if (chld_err.lines > 0) {
387 printf (_("External command error: %s\n"), chld_err.line[0]);
388 for (size_t i = 1; i < chld_err.lines; i++) {
389 printf ("%s\n", chld_err.line[i]);
390 }
391 } else {
392 printf(_("External command error with no output (return code: %d)\n"), return_code);
393 }
394 exit (STATE_UNKNOWN);
395 } 272 }
396 273
397 if (verbose) { 274 check_snmp_config config = paw_tmp.config;
398 for (size_t i = 0; i < chld_out.lines; i++) { 275
399 printf ("%s\n", chld_out.line[i]); 276 if (config.output_format_is_set) {
400 } 277 mp_set_format(config.output_format);
401 } 278 }
402 279
403 line = 0; 280 /* Set signal handling and alarm */
404 total_oids = 0; 281 if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
405 for (size_t i = 0; line < chld_out.lines && i < numoids ; line++, i++, total_oids++) { 282 usage4(_("Cannot catch SIGALRM"));
406 if(calculate_rate) 283 }
407 conv = "%.10g";
408 else
409 conv = "%.0f";
410
411 ptr = chld_out.line[line];
412 oidname = strpcpy (oidname, ptr, delimiter);
413 response = strstr (ptr, delimiter);
414 if (response == NULL)
415 break;
416 284
417 if (verbose > 2) { 285 time_t current_time;
418 printf("Processing oid %zi (line %zi)\n oidname: %s\n response: %s\n", i+1, line+1, oidname, response); 286 time(&current_time);
419 }
420 287
421 /* Clean up type array - Sol10 does not necessarily zero it out */ 288 if (verbose > 2) {
422 bzero(type, sizeof(type)); 289 printf("current time: %s (timestamp: %lu)\n", ctime(&current_time), current_time);
290 }
423 291
424 is_counter=0; 292 snmp_responces response = do_snmp_query(config.snmp_params);
425 /* We strip out the datatype indicator for PHBs */
426 if (strstr (response, "Gauge: ")) {
427 show = multiply (strstr (response, "Gauge: ") + 7);
428 }
429 else if (strstr (response, "Gauge32: ")) {
430 show = multiply (strstr (response, "Gauge32: ") + 9);
431 }
432 else if (strstr (response, "Counter32: ")) {
433 show = strstr (response, "Counter32: ") + 11;
434 is_counter=1;
435 if(!calculate_rate)
436 strcpy(type, "c");
437 }
438 else if (strstr (response, "Counter64: ")) {
439 show = strstr (response, "Counter64: ") + 11;
440 is_counter=1;
441 if(!calculate_rate)
442 strcpy(type, "c");
443 }
444 else if (strstr (response, "INTEGER: ")) {
445 show = multiply (strstr (response, "INTEGER: ") + 9);
446 293
447 if (fmtstr_set) { 294 mp_check overall = mp_check_init();
448 conv = fmtstr;
449 }
450 }
451 else if (strstr (response, "OID: ")) {
452 show = strstr (response, "OID: ") + 5;
453 }
454 else if (strstr (response, "STRING: ")) {
455 show = strstr (response, "STRING: ") + 8;
456 conv = "%.10g";
457
458 /* Get the rest of the string on multi-line strings */
459 ptr = show;
460 COUNT_SEQ(ptr, bk_count, dq_count)
461 while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
462 ptr++;
463 GOBBLE_TOS(ptr, "\n\"\\")
464 COUNT_SEQ(ptr, bk_count, dq_count)
465 }
466 295
467 if (dq_count) { /* unfinished line */ 296 if (response.errorcode == OK) {
468 /* copy show verbatim first */ 297 mp_subcheck sc_successfull_query = mp_subcheck_init();
469 if (!mult_resp) mult_resp = strdup(""); 298 xasprintf(&sc_successfull_query.output, "SNMP query was successful");
470 xasprintf (&mult_resp, "%s%s:\n%s\n", mult_resp, oids[i], show); 299 sc_successfull_query = mp_set_subcheck_state(sc_successfull_query, STATE_OK);
471 /* then strip out unmatched double-quote from single-line output */ 300 mp_add_subcheck_to_check(&overall, sc_successfull_query);
472 if (show[0] == '"') show++; 301 } else {
473 302 // Error treatment here, either partial or whole
474 /* Keep reading until we match end of double-quoted string */ 303 mp_subcheck sc_failed_query = mp_subcheck_init();
475 for (line++; line < chld_out.lines; line++) { 304 xasprintf(&sc_failed_query.output, "SNMP query failed");
476 ptr = chld_out.line[line]; 305 sc_failed_query = mp_set_subcheck_state(sc_failed_query, STATE_OK);
477 xasprintf (&mult_resp, "%s%s\n", mult_resp, ptr); 306 mp_add_subcheck_to_check(&overall, sc_failed_query);
478 307 mp_exit(overall);
479 COUNT_SEQ(ptr, bk_count, dq_count) 308 }
480 while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
481 ptr++;
482 GOBBLE_TOS(ptr, "\n\"\\")
483 COUNT_SEQ(ptr, bk_count, dq_count)
484 }
485 /* Break for loop before next line increment when done */
486 if (!dq_count) break;
487 }
488 }
489 309
490 } 310 check_snmp_state_entry *prev_state = NULL;
491 else if (strstr (response, "Timeticks: ")) { 311 bool have_previous_state = false;
492 show = strstr (response, "Timeticks: ");
493 }
494 else
495 show = response + 3;
496 312
497 iresult = STATE_DEPENDENT; 313 if (config.evaluation_params.calculate_rate) {
314 state_data *previous_state = np_state_read(stateKey);
315 if (previous_state == NULL) {
316 // failed to recover state
317 // or no previous state
318 have_previous_state = false;
319 } else {
320 // sanity check
321 recover_state_data_type prev_state_wrapper =
322 recover_state_data(previous_state->data, (idx_t)previous_state->length);
498 323
499 /* Process this block for numeric comparisons */ 324 if (prev_state_wrapper.errorcode == OK) {
500 /* Make some special values,like Timeticks numeric only if a threshold is defined */ 325 have_previous_state = true;
501 if (thlds[i]->warning || thlds[i]->critical || calculate_rate) { 326 prev_state = prev_state_wrapper.state;
502 if (verbose > 2) {
503 print_thresholds(" thresholds", thlds[i]);
504 }
505 ptr = strpbrk (show, "-0123456789");
506 if (ptr == NULL){
507 if (nulloid == 3)
508 die (STATE_UNKNOWN,_("No valid data returned (%s)\n"), show);
509 else if (nulloid == 0)
510 die (STATE_OK,_("No valid data returned (%s)\n"), show);
511 else if (nulloid == 1)
512 die (STATE_WARNING,_("No valid data returned (%s)\n"), show);
513 else if (nulloid == 2)
514 die (STATE_CRITICAL,_("No valid data returned (%s)\n"), show);
515 }
516 while (i >= response_size) {
517 response_size += OID_COUNT_STEP;
518 response_value = realloc(response_value, response_size * sizeof(*response_value));
519 }
520 response_value[i] = strtod (ptr, NULL) + offset;
521
522 if(calculate_rate) {
523 if (previous_state!=NULL) {
524 duration = current_time-previous_state->time;
525 if(duration<=0)
526 die(STATE_UNKNOWN,_("Time duration between plugin calls is invalid"));
527 temp_double = response_value[i]-previous_value[i];
528 /* Simple overflow catcher (same as in rrdtool, rrd_update.c) */
529 if(is_counter) {
530 if(temp_double<(double)0.0)
531 temp_double+=(double)4294967296.0; /* 2^32 */
532 if(temp_double<(double)0.0)
533 temp_double+=(double)18446744069414584320.0; /* 2^64-2^32 */;
534 }
535 /* Convert to per second, then use multiplier */
536 temp_double = temp_double/duration*rate_multiplier;
537 iresult = get_status(temp_double, thlds[i]);
538 xasprintf (&show, conv, temp_double);
539 }
540 } else { 327 } else {
541 iresult = get_status(response_value[i], thlds[i]); 328 have_previous_state = false;
542 xasprintf (&show, conv, response_value[i]); 329 prev_state = NULL;
543 } 330 }
544 } 331 }
332 }
545 333
546 /* Process this block for string matching */ 334 check_snmp_state_entry *new_state = NULL;
547 else if (eval_size > i && eval_method[i] & CRIT_STRING) { 335 if (config.evaluation_params.calculate_rate) {
548 if (strcmp (show, string_value)) 336 new_state = calloc(config.snmp_params.num_of_test_units, sizeof(check_snmp_state_entry));
549 iresult = (invert_search==0) ? STATE_CRITICAL : STATE_OK; 337 if (new_state == NULL) {
550 else 338 die(STATE_UNKNOWN, "memory allocation failed");
551 iresult = (invert_search==0) ? STATE_OK : STATE_CRITICAL;
552 } 339 }
340 }
553 341
554 /* Process this block for regex matching */ 342 // We got the the query results, now process them
555 else if (eval_size > i && eval_method[i] & CRIT_REGEX) { 343 for (size_t loop_index = 0; loop_index < config.snmp_params.num_of_test_units; loop_index++) {
556 excode = regexec (&preg, response, 10, pmatch, eflags); 344 if (verbose > 0) {
557 if (excode == 0) { 345 printf("loop_index: %zu\n", loop_index);
558 iresult = (invert_search==0) ? STATE_OK : STATE_CRITICAL;
559 }
560 else if (excode != REG_NOMATCH) {
561 regerror (excode, &preg, errbuf, MAX_INPUT_BUFFER);
562 printf (_("Execute Error: %s\n"), errbuf);
563 exit (STATE_CRITICAL);
564 }
565 else {
566 iresult = (invert_search==0) ? STATE_CRITICAL : STATE_OK;
567 }
568 } 346 }
569 347
570 /* Process this block for existence-nonexistence checks */ 348 check_snmp_state_entry previous_unit_state = {};
571 /* TV: Should this be outside of this else block? */ 349 if (config.evaluation_params.calculate_rate && have_previous_state) {
572 else { 350 previous_unit_state = prev_state[loop_index];
573 if (eval_size > i && eval_method[i] & CRIT_PRESENT)
574 iresult = STATE_CRITICAL;
575 else if (eval_size > i && eval_method[i] & WARN_PRESENT)
576 iresult = STATE_WARNING;
577 else if (response && iresult == STATE_DEPENDENT)
578 iresult = STATE_OK;
579 } 351 }
580 352
581 /* Result is the worst outcome of all the OIDs tested */ 353 check_snmp_evaluation single_eval =
582 result = max_state (result, iresult); 354 evaluate_single_unit(response.response_values[loop_index], config.evaluation_params,
583 355 config.snmp_params.test_units[loop_index], current_time,
584 /* Prepend a label for this OID if there is one */ 356 previous_unit_state, have_previous_state);
585 if (nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
586 xasprintf (&outbuff, "%s%s%s %s%s%s", outbuff,
587 (i == 0) ? " " : output_delim,
588 labels[i], mark (iresult), show, mark (iresult));
589 else
590 xasprintf (&outbuff, "%s%s%s%s%s", outbuff, (i == 0) ? " " : output_delim,
591 mark (iresult), show, mark (iresult));
592
593 /* Append a unit string for this OID if there is one */
594 if (nunits > (size_t)0 && (size_t)i < nunits && unitv[i] != NULL)
595 xasprintf (&outbuff, "%s %s", outbuff, unitv[i]);
596
597 /* Write perfdata with whatever can be parsed by strtod, if possible */
598 ptr = NULL;
599 strtod(show, &ptr);
600 if (ptr > show) {
601 if (perf_labels && nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
602 temp_string=labels[i];
603 else
604 temp_string=oidname;
605 if (strpbrk (temp_string, " ='\"") == NULL) {
606 strncat(perfstr, temp_string, sizeof(perfstr)-strlen(perfstr)-1);
607 } else {
608 if (strpbrk (temp_string, "'") == NULL) {
609 quote_string="'";
610 } else {
611 quote_string="\"";
612 }
613 strncat(perfstr, quote_string, sizeof(perfstr)-strlen(perfstr)-1);
614 strncat(perfstr, temp_string, sizeof(perfstr)-strlen(perfstr)-1);
615 strncat(perfstr, quote_string, sizeof(perfstr)-strlen(perfstr)-1);
616 }
617 strncat(perfstr, "=", sizeof(perfstr)-strlen(perfstr)-1);
618 len = sizeof(perfstr)-strlen(perfstr)-1;
619 strncat(perfstr, show, len>ptr-show ? ptr-show : len);
620
621 if (strcmp(type, "") != 0) {
622 strncat(perfstr, type, sizeof(perfstr)-strlen(perfstr)-1);
623 }
624
625 if (warning_thresholds) {
626 strncat(perfstr, ";", sizeof(perfstr)-strlen(perfstr)-1);
627 if(thlds[i]->warning && thlds[i]->warning->text)
628 strncat(perfstr, thlds[i]->warning->text, sizeof(perfstr)-strlen(perfstr)-1);
629 }
630
631 if (critical_thresholds) {
632 if (!warning_thresholds)
633 strncat(perfstr, ";", sizeof(perfstr)-strlen(perfstr)-1);
634 strncat(perfstr, ";", sizeof(perfstr)-strlen(perfstr)-1);
635 if(thlds[i]->critical && thlds[i]->critical->text)
636 strncat(perfstr, thlds[i]->critical->text, sizeof(perfstr)-strlen(perfstr)-1);
637 }
638 357
639 strncat(perfstr, " ", sizeof(perfstr)-strlen(perfstr)-1); 358 if (config.evaluation_params.calculate_rate &&
359 mp_compute_subcheck_state(single_eval.sc) != STATE_UNKNOWN) {
360 new_state[loop_index] = single_eval.state;
640 } 361 }
641 }
642 362
643 /* Save state data, as all data collected now */ 363 mp_add_subcheck_to_check(&overall, single_eval.sc);
644 if(calculate_rate) {
645 string_length=1024;
646 state_string=malloc(string_length);
647 if(state_string==NULL)
648 die(STATE_UNKNOWN, _("Cannot malloc"));
649
650 current_length=0;
651 for(int i = 0; i < total_oids; i++) {
652 xasprintf(&temp_string,"%.0f",response_value[i]);
653 if(temp_string==NULL)
654 die(STATE_UNKNOWN,_("Cannot asprintf()"));
655 response_length = strlen(temp_string);
656 if(current_length+response_length>string_length) {
657 string_length=current_length+1024;
658 state_string=realloc(state_string,string_length);
659 if(state_string==NULL)
660 die(STATE_UNKNOWN, _("Cannot realloc()"));
661 }
662 strcpy(&state_string[current_length],temp_string);
663 current_length=current_length+response_length;
664 state_string[current_length]=':';
665 current_length++;
666 free(temp_string);
667 }
668 state_string[--current_length]='\0';
669 if (verbose > 2)
670 printf("State string=%s\n",state_string);
671
672 /* This is not strictly the same as time now, but any subtle variations will cancel out */
673 np_state_write_string(current_time, state_string );
674 if(previous_state==NULL) {
675 /* Or should this be highest state? */
676 die( STATE_OK, _("No previous data to calculate rate - assume okay" ) );
677 }
678 } 364 }
679 365
680 printf ("%s %s -%s %s\n", label, state_text (result), outbuff, perfstr); 366 if (config.evaluation_params.calculate_rate) {
681 if (mult_resp) printf ("%s", mult_resp); 367 // store state
368 gen_state_string_type current_state_wrapper =
369 gen_state_string(new_state, config.snmp_params.num_of_test_units);
682 370
683 return result; 371 if (current_state_wrapper.errorcode == OK) {
372 np_state_write_string(stateKey, current_time, current_state_wrapper.state_string);
373 } else {
374 die(STATE_UNKNOWN, "failed to create state string");
375 }
376 }
377 mp_exit(overall);
684} 378}
685 379
686
687
688/* process command-line arguments */ 380/* process command-line arguments */
689int 381static process_arguments_wrapper process_arguments(int argc, char **argv) {
690process_arguments (int argc, char **argv) 382 enum {
691{ 383 /* Longopts only arguments */
692 char *ptr; 384 invert_search_index = CHAR_MAX + 1,
693 int c = 1; 385 offset_index,
694 size_t j = 0, jj = 0; 386 ignore_mib_parsing_errors_index,
387 connection_prefix_index,
388 output_format_index,
389 calculate_rate,
390 rate_multiplier
391 };
695 392
696 int option = 0;
697 static struct option longopts[] = { 393 static struct option longopts[] = {
698 STD_LONG_OPTS, 394 STD_LONG_OPTS,
699 {"community", required_argument, 0, 'C'}, 395 {"community", required_argument, 0, 'C'},
@@ -721,662 +417,738 @@ process_arguments (int argc, char **argv)
721 {"authpasswd", required_argument, 0, 'A'}, 417 {"authpasswd", required_argument, 0, 'A'},
722 {"privpasswd", required_argument, 0, 'X'}, 418 {"privpasswd", required_argument, 0, 'X'},
723 {"next", no_argument, 0, 'n'}, 419 {"next", no_argument, 0, 'n'},
724 {"rate", no_argument, 0, L_CALCULATE_RATE}, 420 {"offset", required_argument, 0, offset_index},
725 {"rate-multiplier", required_argument, 0, L_RATE_MULTIPLIER}, 421 {"invert-search", no_argument, 0, invert_search_index},
726 {"offset", required_argument, 0, L_OFFSET},
727 {"invert-search", no_argument, 0, L_INVERT_SEARCH},
728 {"perf-oids", no_argument, 0, 'O'}, 422 {"perf-oids", no_argument, 0, 'O'},
729 {"ipv4", no_argument, 0, '4'}, 423 {"ipv4", no_argument, 0, '4'},
730 {"ipv6", no_argument, 0, '6'}, 424 {"ipv6", no_argument, 0, '6'},
731 {"multiplier", required_argument, 0, 'M'}, 425 {"multiplier", required_argument, 0, 'M'},
732 {"fmtstr", required_argument, 0, 'f'}, 426 {"ignore-mib-parsing-errors", no_argument, 0, ignore_mib_parsing_errors_index},
733 {"ignore-mib-parsing-errors", no_argument, false, L_IGNORE_MIB_PARSING_ERRORS}, 427 {"connection-prefix", required_argument, 0, connection_prefix_index},
734 {0, 0, 0, 0} 428 {"output-format", required_argument, 0, output_format_index},
735 }; 429 {"rate", no_argument, 0, calculate_rate},
430 {"rate-multiplier", required_argument, 0, rate_multiplier},
431 {0, 0, 0, 0}};
432
433 if (argc < 2) {
434 process_arguments_wrapper result = {
435 .errorcode = ERROR,
436 };
437 return result;
438 }
439
440 // Count number of OIDs here first
441 int option = 0;
442 size_t oid_counter = 0;
443 while (true) {
444 int option_char = getopt_long(
445 argc, argv,
446 "nhvVO46t:c:w:H:C:o:e:E:d:D:s:t:R:r:l:u:p:m:P:N:L:U:a:x:A:X:M:f:z:", longopts, &option);
447
448 if (option_char == -1 || option_char == EOF) {
449 break;
450 }
451
452 switch (option_char) {
453 case 'o': {
454 // we are going to parse this again, so we work on a copy of that string
455 char *tmp_oids = strdup(optarg);
456 if (tmp_oids == NULL) {
457 die(STATE_UNKNOWN, "strdup failed");
458 }
459
460 for (char *ptr = strtok(tmp_oids, ", "); ptr != NULL;
461 ptr = strtok(NULL, ", "), oid_counter++) {
462 }
463 break;
464 }
465 case '?': /* usage */
466 usage5();
467 // fallthrough
468 case 'h': /* help */
469 print_help();
470 exit(STATE_UNKNOWN);
471 case 'V': /* version */
472 print_revision(progname, NP_VERSION);
473 exit(STATE_UNKNOWN);
474
475 default:
476 continue;
477 }
478 }
736 479
737 if (argc < 2) 480 /* Check whether at least one OID was given */
738 return ERROR; 481 if (oid_counter == 0) {
739 482 die(STATE_UNKNOWN, _("No OIDs specified\n"));
740 /* reverse compatibility for very old non-POSIX usage forms */
741 for (c = 1; c < argc; c++) {
742 if (strcmp ("-to", argv[c]) == 0)
743 strcpy (argv[c], "-t");
744 if (strcmp ("-wv", argv[c]) == 0)
745 strcpy (argv[c], "-w");
746 if (strcmp ("-cv", argv[c]) == 0)
747 strcpy (argv[c], "-c");
748 } 483 }
749 484
750 while (1) { 485 // Allocate space for test units
751 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:", 486 check_snmp_test_unit *tmp = calloc(oid_counter, sizeof(check_snmp_test_unit));
752 longopts, &option); 487 if (tmp == NULL) {
488 die(STATE_UNKNOWN, "Failed to calloc");
489 }
753 490
754 if (c == -1 || c == EOF) 491 for (size_t i = 0; i < oid_counter; i++) {
492 tmp[i] = check_snmp_test_unit_init();
493 }
494
495 check_snmp_config config = check_snmp_config_init();
496 config.snmp_params.test_units = tmp;
497 config.snmp_params.num_of_test_units = oid_counter;
498
499 option = 0;
500 optind = 1; // Reset argument scanner
501 size_t tmp_oid_counter = 0;
502 size_t eval_counter = 0;
503 size_t unitv_counter = 0;
504 size_t labels_counter = 0;
505 unsigned char *authpasswd = NULL;
506 unsigned char *privpasswd = NULL;
507 int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
508 char *port = NULL;
509 char *miblist = NULL;
510 char *connection_prefix = NULL;
511 bool snmp_version_set_explicitely = false;
512 // TODO error checking
513 while (true) {
514 int option_char = getopt_long(
515 argc, argv,
516 "nhvVO46t:c:w:H:C:o:e:E:d:D:s:t:R:r:l:u:p:m:P:N:L:U:a:x:A:X:M:f:z:", longopts, &option);
517
518 if (option_char == -1 || option_char == EOF) {
755 break; 519 break;
520 }
756 521
757 switch (c) { 522 switch (option_char) {
758 case '?': /* usage */ 523 case '?': /* usage */
759 usage5 (); 524 usage5();
760 case 'h': /* help */ 525 case 'h': /* help */
761 print_help (); 526 print_help();
762 exit (STATE_UNKNOWN); 527 exit(STATE_UNKNOWN);
763 case 'V': /* version */ 528 case 'V': /* version */
764 print_revision (progname, NP_VERSION); 529 print_revision(progname, NP_VERSION);
765 exit (STATE_UNKNOWN); 530 exit(STATE_UNKNOWN);
766 case 'v': /* verbose */ 531 case 'v': /* verbose */
767 verbose++; 532 verbose++;
768 break; 533 break;
769 534
770 /* Connection info */ 535 /* Connection info */
771 case 'C': /* group or community */ 536 case 'C': /* group or community */
772 community = optarg; 537 config.snmp_params.snmp_session.community = (unsigned char *)optarg;
538 config.snmp_params.snmp_session.community_len = strlen(optarg);
773 break; 539 break;
774 case 'H': /* Host or server */ 540 case 'H': /* Host or server */
775 server_address = optarg; 541 config.snmp_params.snmp_session.peername = optarg;
776 break; 542 break;
777 case 'p': /* TCP port number */ 543 case 'p': /*port number */
544 // Add port to "peername" below to not rely on argument order
778 port = optarg; 545 port = optarg;
779 break; 546 break;
780 case 'm': /* List of MIBS */ 547 case 'm': /* List of MIBS */
781 miblist = optarg; 548 miblist = optarg;
782 break; 549 break;
783 case 'n': /* usesnmpgetnext */ 550 case 'n': /* use_getnext instead of get */
784 usesnmpgetnext = true; 551 config.snmp_params.use_getnext = true;
785 break; 552 break;
786 case 'P': /* SNMP protocol version */ 553 case 'P': /* SNMP protocol version */
787 proto = optarg; 554 if (strcasecmp("1", optarg) == 0) {
555 config.snmp_params.snmp_session.version = SNMP_VERSION_1;
556 } else if (strcasecmp("2c", optarg) == 0) {
557 config.snmp_params.snmp_session.version = SNMP_VERSION_2c;
558 } else if (strcasecmp("3", optarg) == 0) {
559 config.snmp_params.snmp_session.version = SNMP_VERSION_3;
560 } else {
561 die(STATE_UNKNOWN, "invalid SNMP version/protocol: %s", optarg);
562 }
563 snmp_version_set_explicitely = true;
564
788 break; 565 break;
789 case 'N': /* SNMPv3 context */ 566 case 'N': /* SNMPv3 context name */
790 context = optarg; 567 config.snmp_params.snmp_session.contextName = optarg;
568 config.snmp_params.snmp_session.contextNameLen = strlen(optarg);
791 break; 569 break;
792 case 'L': /* security level */ 570 case 'L': /* security level */
793 seclevel = optarg; 571 if (strcasecmp("noAuthNoPriv", optarg) == 0) {
572 config.snmp_params.snmp_session.securityLevel = SNMP_SEC_LEVEL_NOAUTH;
573 } else if (strcasecmp("authNoPriv", optarg) == 0) {
574 config.snmp_params.snmp_session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
575 } else if (strcasecmp("authPriv", optarg) == 0) {
576 config.snmp_params.snmp_session.securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
577 } else {
578 die(STATE_UNKNOWN, "invalid security level: %s", optarg);
579 }
794 break; 580 break;
795 case 'U': /* security username */ 581 case 'U': /* security username */
796 secname = optarg; 582 config.snmp_params.snmp_session.securityName = optarg;
583 config.snmp_params.snmp_session.securityNameLen = strlen(optarg);
797 break; 584 break;
798 case 'a': /* auth protocol */ 585 case 'a': /* auth protocol */
799 authproto = optarg; 586 // SNMPv3: SHA or MD5
587 // TODO Test for availability of individual protocols
588 if (strcasecmp("MD5", optarg) == 0) {
589 config.snmp_params.snmp_session.securityAuthProto = usmHMACMD5AuthProtocol;
590 config.snmp_params.snmp_session.securityAuthProtoLen =
591 OID_LENGTH(usmHMACMD5AuthProtocol);
592 } else if (strcasecmp("SHA", optarg) == 0) {
593 config.snmp_params.snmp_session.securityAuthProto = usmHMACSHA1AuthProtocol;
594 config.snmp_params.snmp_session.securityAuthProtoLen =
595 OID_LENGTH(usmHMACSHA1AuthProtocol);
596 } else if (strcasecmp("SHA224", optarg) == 0) {
597 config.snmp_params.snmp_session.securityAuthProto = usmHMAC128SHA224AuthProtocol;
598 config.snmp_params.snmp_session.securityAuthProtoLen =
599 OID_LENGTH(usmHMAC128SHA224AuthProtocol);
600 } else if (strcasecmp("SHA256", optarg) == 0) {
601 config.snmp_params.snmp_session.securityAuthProto = usmHMAC192SHA256AuthProtocol;
602 config.snmp_params.snmp_session.securityAuthProtoLen =
603 OID_LENGTH(usmHMAC192SHA256AuthProtocol);
604 } else if (strcasecmp("SHA384", optarg) == 0) {
605 config.snmp_params.snmp_session.securityAuthProto = usmHMAC256SHA384AuthProtocol;
606 config.snmp_params.snmp_session.securityAuthProtoLen =
607 OID_LENGTH(usmHMAC256SHA384AuthProtocol);
608 } else if (strcasecmp("SHA512", optarg) == 0) {
609 config.snmp_params.snmp_session.securityAuthProto = usmHMAC384SHA512AuthProtocol;
610 config.snmp_params.snmp_session.securityAuthProtoLen =
611 OID_LENGTH(usmHMAC384SHA512AuthProtocol);
612 } else {
613 die(STATE_UNKNOWN, "Unknown authentication protocol");
614 }
800 break; 615 break;
801 case 'x': /* priv protocol */ 616 case 'x': /* priv protocol */
802 privproto = optarg; 617 if (strcasecmp("DES", optarg) == 0) {
618#ifdef HAVE_USM_DES_PRIV_PROTOCOL
619 config.snmp_params.snmp_session.securityAuthProto = usmDESPrivProtocol;
620 config.snmp_params.snmp_session.securityAuthProtoLen =
621 OID_LENGTH(usmDESPrivProtocol);
622#else
623 die(STATE_UNKNOWN, "DES Privacy Protocol not available on this platform");
624#endif
625 } else if (strcasecmp("AES", optarg) == 0) {
626 config.snmp_params.snmp_session.securityAuthProto = usmAESPrivProtocol;
627 config.snmp_params.snmp_session.securityAuthProtoLen =
628 OID_LENGTH(usmAESPrivProtocol);
629 // } else if (strcasecmp("AES128", optarg)) {
630 // config.snmp_session.securityAuthProto = usmAES128PrivProtocol;
631 // config.snmp_session.securityAuthProtoLen = OID_LENGTH(usmAES128PrivProtocol)
632 // / OID_LENGTH(oid);
633 } else if (strcasecmp("AES192", optarg) == 0) {
634 config.snmp_params.snmp_session.securityAuthProto = usmAES192PrivProtocol;
635 config.snmp_params.snmp_session.securityAuthProtoLen =
636 OID_LENGTH(usmAES192PrivProtocol);
637 } else if (strcasecmp("AES256", optarg) == 0) {
638 config.snmp_params.snmp_session.securityAuthProto = usmAES256PrivProtocol;
639 config.snmp_params.snmp_session.securityAuthProtoLen =
640 OID_LENGTH(usmAES256PrivProtocol);
641 // } else if (strcasecmp("AES192Cisco", optarg)) {
642 // config.snmp_session.securityAuthProto = usmAES192CiscoPrivProtocol;
643 // config.snmp_session.securityAuthProtoLen =
644 // sizeof(usmAES192CiscoPrivProtocol) / sizeof(oid); } else if
645 // (strcasecmp("AES256Cisco", optarg)) { config.snmp_session.securityAuthProto =
646 // usmAES256CiscoPrivProtocol; config.snmp_session.securityAuthProtoLen =
647 // sizeof(usmAES256CiscoPrivProtocol) / sizeof(oid); } else if
648 // (strcasecmp("AES192Cisco2", optarg)) { config.snmp_session.securityAuthProto
649 // = usmAES192Cisco2PrivProtocol; config.snmp_session.securityAuthProtoLen =
650 // sizeof(usmAES192Cisco2PrivProtocol) / sizeof(oid); } else if
651 // (strcasecmp("AES256Cisco2", optarg)) { config.snmp_session.securityAuthProto
652 // = usmAES256Cisco2PrivProtocol; config.snmp_session.securityAuthProtoLen =
653 // sizeof(usmAES256Cisco2PrivProtocol) / sizeof(oid);
654 } else {
655 die(STATE_UNKNOWN, "Unknown privacy protocol");
656 }
803 break; 657 break;
804 case 'A': /* auth passwd */ 658 case 'A': /* auth passwd */
805 authpasswd = optarg; 659 authpasswd = (unsigned char *)optarg;
806 break; 660 break;
807 case 'X': /* priv passwd */ 661 case 'X': /* priv passwd */
808 privpasswd = optarg; 662 privpasswd = (unsigned char *)optarg;
809 break; 663 break;
810 case 't': /* timeout period */ 664 case 'e':
811 if (!is_integer (optarg)) 665 case 'E':
812 usage2 (_("Timeout interval must be a positive integer"), optarg); 666 if (!is_integer(optarg)) {
813 else 667 usage2(_("Retries interval must be a positive integer"), optarg);
814 timeout_interval = atoi (optarg); 668 } else {
669 config.snmp_params.snmp_session.retries = atoi(optarg);
670 }
815 break; 671 break;
816 672 case 't': /* timeout period */
817 /* Test parameters */ 673 if (!is_integer(optarg)) {
818 case 'c': /* critical threshold */ 674 usage2(_("Timeout interval must be a positive integer"), optarg);
819 critical_thresholds = optarg; 675 } else {
676 timeout_interval = (unsigned int)atoi(optarg);
677 }
820 break; 678 break;
821 case 'w': /* warning threshold */ 679
822 warning_thresholds = optarg; 680 /* Test parameters */
681 case 'c': /* critical threshold */
682 check_snmp_set_thresholds(optarg, config.snmp_params.test_units, oid_counter, true);
823 break; 683 break;
824 case 'e': /* PRELIMINARY - may change */ 684 case 'w': /* warning threshold */
825 case 'E': /* PRELIMINARY - may change */ 685 check_snmp_set_thresholds(optarg, config.snmp_params.test_units, oid_counter, false);
826 if (!is_integer (optarg))
827 usage2 (_("Retries interval must be a positive integer"), optarg);
828 else
829 retries = atoi(optarg);
830 break; 686 break;
831 case 'o': /* object identifier */ 687 case 'o': /* object identifier */
832 if ( strspn( optarg, "0123456789.," ) != strlen( optarg ) ) { 688 if (strspn(optarg, "0123456789.,") != strlen(optarg)) {
833 /* 689 /*
834 * we have something other than digits, periods and comas, 690 * we have something other than digits, periods and comas,
835 * so we have a mib variable, rather than just an SNMP OID, 691 * so we have a mib variable, rather than just an SNMP OID,
836 * so we have to actually read the mib files 692 * so we have to actually read the mib files
837 */ 693 */
838 needmibs = true; 694 config.snmp_params.need_mibs = true;
839 } 695 }
840 for (ptr = strtok(optarg, ", "); ptr != NULL; ptr = strtok(NULL, ", "), j++) { 696
841 while (j >= oids_size) { 697 for (char *ptr = strtok(optarg, ", "); ptr != NULL;
842 oids_size += OID_COUNT_STEP; 698 ptr = strtok(NULL, ", "), tmp_oid_counter++) {
843 oids = realloc(oids, oids_size * sizeof (*oids)); 699 config.snmp_params.test_units[tmp_oid_counter].oid = strdup(ptr);
844 }
845 oids[j] = strdup(ptr);
846 }
847 numoids = j;
848 if (c == 'E' || c == 'e') {
849 jj++;
850 while (j+1 >= eval_size) {
851 eval_size += OID_COUNT_STEP;
852 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method));
853 memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8);
854 }
855 if (c == 'E')
856 eval_method[j+1] |= WARN_PRESENT;
857 else if (c == 'e')
858 eval_method[j+1] |= CRIT_PRESENT;
859 } 700 }
860 break; 701 break;
861 case 'z': /* Null OID Return Check */ 702 case 'z': /* Null OID Return Check */
862 if (!is_integer (optarg)) 703 if (!is_integer(optarg)) {
863 usage2 (_("Exit status must be a positive integer"), optarg); 704 usage2(_("Exit status must be a positive integer"), optarg);
864 else 705 } else {
865 nulloid = atoi(optarg); 706 config.evaluation_params.nulloid_result = atoi(optarg);
866 break;
867 case 's': /* string or substring */
868 strncpy (string_value, optarg, sizeof (string_value) - 1);
869 string_value[sizeof (string_value) - 1] = 0;
870 while (jj >= eval_size) {
871 eval_size += OID_COUNT_STEP;
872 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method));
873 memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8);
874 } 707 }
875 eval_method[jj++] = CRIT_STRING;
876 break; 708 break;
877 case 'R': /* regex */ 709 case 's': /* string or substring */
710 strncpy(config.evaluation_params.string_cmp_value, optarg,
711 sizeof(config.evaluation_params.string_cmp_value) - 1);
712 config.evaluation_params
713 .string_cmp_value[sizeof(config.evaluation_params.string_cmp_value) - 1] = 0;
714 config.snmp_params.test_units[eval_counter++].eval_mthd.crit_string = true;
715 break;
716 case 'R': /* regex */
878 cflags = REG_ICASE; 717 cflags = REG_ICASE;
879 // fall through 718 // fall through
880 case 'r': /* regex */ 719 case 'r': /* regex */
720 {
721 char regex_expect[MAX_INPUT_BUFFER] = "";
881 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 722 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
882 strncpy (regex_expect, optarg, sizeof (regex_expect) - 1); 723 strncpy(regex_expect, optarg, sizeof(regex_expect) - 1);
883 regex_expect[sizeof (regex_expect) - 1] = 0; 724 regex_expect[sizeof(regex_expect) - 1] = 0;
884 errcode = regcomp (&preg, regex_expect, cflags); 725 int errcode = regcomp(&config.evaluation_params.regex_cmp_value, regex_expect, cflags);
885 if (errcode != 0) { 726 if (errcode != 0) {
886 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 727 char errbuf[MAX_INPUT_BUFFER] = "";
887 printf (_("Could Not Compile Regular Expression")); 728 regerror(errcode, &config.evaluation_params.regex_cmp_value, errbuf,
888 return ERROR; 729 MAX_INPUT_BUFFER);
730 printf("Could Not Compile Regular Expression: %s", errbuf);
731 process_arguments_wrapper result = {
732 .errorcode = ERROR,
733 };
734 return result;
889 } 735 }
890 while (jj >= eval_size) { 736 config.snmp_params.test_units[eval_counter++].eval_mthd.crit_regex = true;
891 eval_size += OID_COUNT_STEP; 737 } break;
892 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method)); 738 case 'l': /* label */
893 memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8); 739 {
740 if (labels_counter >= config.snmp_params.num_of_test_units) {
741 break;
894 } 742 }
895 eval_method[jj++] = CRIT_REGEX; 743 char *ptr = trim_whitespaces_and_check_quoting(optarg);
896 break; 744 if (ptr[0] == '\'') {
897 745 config.snmp_params.test_units[labels_counter].label = ptr + 1;
898 /* Format */ 746 } else {
899 case 'd': /* delimiter */ 747 config.snmp_params.test_units[labels_counter].label = ptr;
900 delimiter = strscpy (delimiter, optarg);
901 break;
902 case 'D': /* output-delimiter */
903 output_delim = strscpy (output_delim, optarg);
904 break;
905 case 'l': /* label */
906 nlabels++;
907 if (nlabels > labels_size) {
908 labels_size += 8;
909 labels = realloc (labels, labels_size * sizeof(*labels));
910 if (labels == NULL)
911 die (STATE_UNKNOWN, _("Could not reallocate labels[%d]"), (int)nlabels);
912 } 748 }
913 labels[nlabels - 1] = optarg; 749
914 ptr = thisarg (optarg); 750 while (ptr && (ptr = get_next_argument(ptr))) {
915 labels[nlabels - 1] = ptr; 751 labels_counter++;
916 if (ptr[0] == '\'') 752 ptr = trim_whitespaces_and_check_quoting(ptr);
917 labels[nlabels - 1] = ptr + 1; 753 if (ptr[0] == '\'') {
918 while (ptr && (ptr = nextarg (ptr))) { 754 config.snmp_params.test_units[labels_counter].label = ptr + 1;
919 nlabels++; 755 } else {
920 if (nlabels > labels_size) { 756 config.snmp_params.test_units[labels_counter].label = ptr;
921 labels_size += 8;
922 labels = realloc (labels, labels_size * sizeof(*labels));
923 if (labels == NULL)
924 die (STATE_UNKNOWN, _("Could not reallocate labels\n"));
925 } 757 }
926 ptr = thisarg (ptr);
927 if (ptr[0] == '\'')
928 labels[nlabels - 1] = ptr + 1;
929 else
930 labels[nlabels - 1] = ptr;
931 } 758 }
932 break; 759 labels_counter++;
933 case 'u': /* units */ 760 } break;
934 units = optarg; 761 case 'u': /* units */
935 nunits++; 762 {
936 if (nunits > unitv_size) { 763 if (unitv_counter >= config.snmp_params.num_of_test_units) {
937 unitv_size += 8; 764 break;
938 unitv = realloc (unitv, unitv_size * sizeof(*unitv)); 765 }
939 if (unitv == NULL) 766 char *ptr = trim_whitespaces_and_check_quoting(optarg);
940 die (STATE_UNKNOWN, _("Could not reallocate units [%d]\n"), (int)nunits); 767 if (ptr[0] == '\'') {
768 config.snmp_params.test_units[unitv_counter].unit_value = ptr + 1;
769 } else {
770 config.snmp_params.test_units[unitv_counter].unit_value = ptr;
941 } 771 }
942 unitv[nunits - 1] = optarg; 772 while (ptr && (ptr = get_next_argument(ptr))) {
943 ptr = thisarg (optarg); 773 unitv_counter++;
944 unitv[nunits - 1] = ptr; 774 ptr = trim_whitespaces_and_check_quoting(ptr);
945 if (ptr[0] == '\'') 775 if (ptr[0] == '\'') {
946 unitv[nunits - 1] = ptr + 1; 776 config.snmp_params.test_units[unitv_counter].unit_value = ptr + 1;
947 while (ptr && (ptr = nextarg (ptr))) { 777 } else {
948 if (nunits > unitv_size) { 778 config.snmp_params.test_units[unitv_counter].unit_value = ptr;
949 unitv_size += 8;
950 unitv = realloc (unitv, unitv_size * sizeof(*unitv));
951 if (units == NULL)
952 die (STATE_UNKNOWN, _("Could not realloc() units\n"));
953 } 779 }
954 nunits++;
955 ptr = thisarg (ptr);
956 if (ptr[0] == '\'')
957 unitv[nunits - 1] = ptr + 1;
958 else
959 unitv[nunits - 1] = ptr;
960 } 780 }
781 unitv_counter++;
782 } break;
783 case offset_index:
784 config.evaluation_params.offset = strtod(optarg, NULL);
785 config.evaluation_params.offset_set = true;
961 break; 786 break;
962 case L_CALCULATE_RATE: 787 case invert_search_index:
963 if(calculate_rate==0) 788 config.evaluation_params.invert_search = false;
964 np_enable_state(NULL, 1);
965 calculate_rate = 1;
966 break;
967 case L_RATE_MULTIPLIER:
968 if(!is_integer(optarg)||((rate_multiplier=atoi(optarg))<=0))
969 usage2(_("Rate multiplier must be a positive integer"),optarg);
970 break;
971 case L_OFFSET:
972 offset=strtod(optarg,NULL);
973 break;
974 case L_INVERT_SEARCH:
975 invert_search=1;
976 break; 789 break;
977 case 'O': 790 case 'O':
978 perf_labels=0; 791 config.evaluation_params.use_oid_as_perf_data_label = true;
979 break; 792 break;
980 case '4': 793 case '4':
794 // The default, do something here to be exclusive to -6 instead of doing nothing?
795 connection_prefix = "udp";
981 break; 796 break;
982 case '6': 797 case '6':
983 xasprintf(&ip_version, "udp6:"); 798 connection_prefix = "udp6";
984 if(verbose>2) 799 break;
985 printf("IPv6 detected! Will pass \"udp6:\" to snmpget.\n"); 800 case connection_prefix_index:
801 connection_prefix = optarg;
986 break; 802 break;
987 case 'M': 803 case 'M':
988 if ( strspn( optarg, "0123456789.," ) == strlen( optarg ) ) { 804 if (strspn(optarg, "0123456789.,") == strlen(optarg)) {
989 multiplier=strtod(optarg,NULL); 805 config.evaluation_params.multiplier = strtod(optarg, NULL);
806 config.evaluation_params.multiplier_set = true;
990 } 807 }
991 break; 808 break;
992 case 'f': 809 case ignore_mib_parsing_errors_index:
993 if (multiplier != 1.0) { 810 config.snmp_params.ignore_mib_parsing_errors = true;
994 fmtstr=optarg; 811 break;
995 fmtstr_set = true; 812 case 'f': // Deprecated format option for floating point values
813 break;
814 case output_format_index: {
815 parsed_output_format parser = mp_parse_output_format(optarg);
816 if (!parser.parsing_success) {
817 // TODO List all available formats here, maybe add anothoer usage function
818 printf("Invalid output format: %s\n", optarg);
819 exit(STATE_UNKNOWN);
820 }
821
822 config.output_format_is_set = true;
823 config.output_format = parser.output_format;
824 break;
825 }
826 case calculate_rate:
827 config.evaluation_params.calculate_rate = true;
828 break;
829 case rate_multiplier:
830 if (!is_integer(optarg) ||
831 ((config.evaluation_params.rate_multiplier = (unsigned int)atoi(optarg)) <= 0)) {
832 usage2(_("Rate multiplier must be a positive integer"), optarg);
996 } 833 }
997 break; 834 break;
998 case L_IGNORE_MIB_PARSING_ERRORS: 835 default:
999 ignore_mib_parsing_errors = true; 836 die(STATE_UNKNOWN, "Unknown option");
1000 } 837 }
1001 } 838 }
1002 839
1003 if (server_address == NULL) 840 if (config.snmp_params.snmp_session.peername == NULL) {
1004 server_address = argv[optind]; 841 config.snmp_params.snmp_session.peername = argv[optind];
1005 842 }
1006 if (community == NULL)
1007 community = strdup (DEFAULT_COMMUNITY);
1008
1009 return validate_arguments ();
1010}
1011
1012
1013/******************************************************************************
1014
1015@@-
1016<sect3>
1017<title>validate_arguments</title>
1018
1019<para>&PROTO_validate_arguments;</para>
1020
1021<para>Checks to see if the default miblist needs to be loaded. Also verifies
1022the authentication and authorization combinations based on protocol version
1023selected.</para>
1024
1025<para></para>
1026
1027</sect3>
1028-@@
1029******************************************************************************/
1030
1031
1032 843
1033int 844 // Build true peername here if necessary
1034validate_arguments () 845 if (connection_prefix != NULL) {
1035{ 846 // We got something in the connection prefix
1036 /* check whether to load locally installed MIBS (CPU/disk intensive) */ 847 if (strcasecmp(connection_prefix, "udp") == 0) {
1037 if (miblist == NULL) { 848 // The default, do nothing
1038 if (needmibs) { 849 } else if (strcasecmp(connection_prefix, "tcp") == 0) {
1039 miblist = strdup (DEFAULT_MIBLIST); 850 // use tcp/ipv4
1040 }else{ 851 xasprintf(&config.snmp_params.snmp_session.peername, "tcp:%s",
1041 miblist = ""; /* don't read any mib files for numeric oids */ 852 config.snmp_params.snmp_session.peername);
853 } else if (strcasecmp(connection_prefix, "tcp6") == 0 ||
854 strcasecmp(connection_prefix, "tcpv6") == 0 ||
855 strcasecmp(connection_prefix, "tcpipv6") == 0 ||
856 strcasecmp(connection_prefix, "udp6") == 0 ||
857 strcasecmp(connection_prefix, "udpipv6") == 0 ||
858 strcasecmp(connection_prefix, "udpv6") == 0) {
859 // Man page (or net-snmp) code says IPv6 addresses should be wrapped in [], but it
860 // works anyway therefore do nothing here
861 xasprintf(&config.snmp_params.snmp_session.peername, "%s:%s", connection_prefix,
862 config.snmp_params.snmp_session.peername);
863 } else if (strcmp(connection_prefix, "tls") == 0) {
864 // TODO: Anything else to do here?
865 xasprintf(&config.snmp_params.snmp_session.peername, "tls:%s",
866 config.snmp_params.snmp_session.peername);
867 } else if (strcmp(connection_prefix, "dtls") == 0) {
868 // TODO: Anything else to do here?
869 xasprintf(&config.snmp_params.snmp_session.peername, "dtls:%s",
870 config.snmp_params.snmp_session.peername);
871 } else if (strcmp(connection_prefix, "unix") == 0) {
872 // TODO: Check whether this is a valid path?
873 xasprintf(&config.snmp_params.snmp_session.peername, "unix:%s",
874 config.snmp_params.snmp_session.peername);
875 } else if (strcmp(connection_prefix, "ipx") == 0) {
876 xasprintf(&config.snmp_params.snmp_session.peername, "ipx:%s",
877 config.snmp_params.snmp_session.peername);
878 } else {
879 // Don't know that prefix, die here
880 die(STATE_UNKNOWN, "Unknown connection prefix");
1042 } 881 }
1043 } 882 }
1044 883
1045 /* Check server_address is given */ 884 /* Check server_address is given */
1046 if (server_address == NULL) 885 if (config.snmp_params.snmp_session.peername == NULL) {
1047 die(STATE_UNKNOWN, _("No host specified\n")); 886 die(STATE_UNKNOWN, _("No host specified\n"));
887 }
1048 888
1049 /* Check oid is given */ 889 if (port != NULL) {
1050 if (numoids == 0) 890 xasprintf(&config.snmp_params.snmp_session.peername, "%s:%s",
1051 die(STATE_UNKNOWN, _("No OIDs specified\n")); 891 config.snmp_params.snmp_session.peername, port);
1052
1053 if (proto == NULL)
1054 xasprintf(&proto, DEFAULT_PROTOCOL);
1055
1056 if ((strcmp(proto,"1") == 0) || (strcmp(proto, "2c")==0)) { /* snmpv1 or snmpv2c */
1057 numauthpriv = 2;
1058 authpriv = calloc (numauthpriv, sizeof (char *));
1059 authpriv[0] = strdup ("-c");
1060 authpriv[1] = strdup (community);
1061 } 892 }
1062 else if ( strcmp (proto, "3") == 0 ) { /* snmpv3 args */ 893
1063 if (!(context == NULL)) { 894 /* check whether to load locally installed MIBS (CPU/disk intensive) */
1064 numcontext = 2; 895 if (miblist == NULL) {
1065 contextargs = calloc (numcontext, sizeof (char *)); 896 if (config.snmp_params.need_mibs) {
1066 contextargs[0] = strdup ("-n"); 897 setenv("MIBLS", DEFAULT_MIBLIST, 1);
1067 contextargs[1] = strdup (context); 898 } else {
899 setenv("MIBLS", "NONE", 1);
900 miblist = ""; /* don't read any mib files for numeric oids */
1068 } 901 }
902 } else {
903 // Blatantly stolen from snmplib/snmp_parse_args
904 setenv("MIBS", miblist, 1);
905 }
1069 906
1070 if (seclevel == NULL) 907 // Historical default is SNMP v2c
1071 xasprintf(&seclevel, "noAuthNoPriv"); 908 if (!snmp_version_set_explicitely && config.snmp_params.snmp_session.community != NULL) {
909 config.snmp_params.snmp_session.version = SNMP_VERSION_2c;
910 }
1072 911
1073 if (secname == NULL) 912 if ((config.snmp_params.snmp_session.version == SNMP_VERSION_1) ||
913 (config.snmp_params.snmp_session.version == SNMP_VERSION_2c)) { /* snmpv1 or snmpv2c */
914 /*
915 config.numauthpriv = 2;
916 config.authpriv = calloc(config.numauthpriv, sizeof(char *));
917 config.authpriv[0] = strdup("-c");
918 config.authpriv[1] = strdup(community);
919 */
920 } else if (config.snmp_params.snmp_session.version == SNMP_VERSION_3) { /* snmpv3 args */
921 // generate keys for priv and auth here (if demanded)
922
923 if (config.snmp_params.snmp_session.securityName == NULL) {
1074 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "secname"); 924 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "secname");
925 }
1075 926
1076 if (strcmp(seclevel, "noAuthNoPriv") == 0) { 927 switch (config.snmp_params.snmp_session.securityLevel) {
1077 numauthpriv = 4; 928 case SNMP_SEC_LEVEL_AUTHPRIV: {
1078 authpriv = calloc (numauthpriv, sizeof (char *)); 929 if (authpasswd == NULL) {
1079 authpriv[0] = strdup ("-l"); 930 die(STATE_UNKNOWN,
1080 authpriv[1] = strdup ("noAuthNoPriv"); 931 "No authentication passphrase was given, but authorization was requested");
1081 authpriv[2] = strdup ("-u");
1082 authpriv[3] = strdup (secname);
1083 } else {
1084 if (! ( (strcmp(seclevel, "authNoPriv")==0) || (strcmp(seclevel, "authPriv")==0) ) ) {
1085 usage2 (_("Invalid seclevel"), seclevel);
1086 } 932 }
1087 933 // auth and priv
1088 if (authproto == NULL ) 934 int priv_key_generated = generate_Ku(
1089 xasprintf(&authproto, DEFAULT_AUTH_PROTOCOL); 935 config.snmp_params.snmp_session.securityPrivProto,
1090 936 (unsigned int)config.snmp_params.snmp_session.securityPrivProtoLen, authpasswd,
1091 if (authpasswd == NULL) 937 strlen((const char *)authpasswd), config.snmp_params.snmp_session.securityPrivKey,
1092 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "authpasswd"); 938 &config.snmp_params.snmp_session.securityPrivKeyLen);
1093 939
1094 if ( strcmp(seclevel, "authNoPriv") == 0 ) { 940 if (priv_key_generated != SNMPERR_SUCCESS) {
1095 numauthpriv = 8; 941 die(STATE_UNKNOWN, "Failed to generate privacy key");
1096 authpriv = calloc (numauthpriv, sizeof (char *));
1097 authpriv[0] = strdup ("-l");
1098 authpriv[1] = strdup ("authNoPriv");
1099 authpriv[2] = strdup ("-a");
1100 authpriv[3] = strdup (authproto);
1101 authpriv[4] = strdup ("-u");
1102 authpriv[5] = strdup (secname);
1103 authpriv[6] = strdup ("-A");
1104 authpriv[7] = strdup (authpasswd);
1105 } else if ( strcmp(seclevel, "authPriv") == 0 ) {
1106 if (privproto == NULL )
1107 xasprintf(&privproto, DEFAULT_PRIV_PROTOCOL);
1108
1109 if (privpasswd == NULL)
1110 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "privpasswd");
1111
1112 numauthpriv = 12;
1113 authpriv = calloc (numauthpriv, sizeof (char *));
1114 authpriv[0] = strdup ("-l");
1115 authpriv[1] = strdup ("authPriv");
1116 authpriv[2] = strdup ("-a");
1117 authpriv[3] = strdup (authproto);
1118 authpriv[4] = strdup ("-u");
1119 authpriv[5] = strdup (secname);
1120 authpriv[6] = strdup ("-A");
1121 authpriv[7] = strdup (authpasswd);
1122 authpriv[8] = strdup ("-x");
1123 authpriv[9] = strdup (privproto);
1124 authpriv[10] = strdup ("-X");
1125 authpriv[11] = strdup (privpasswd);
1126 } 942 }
1127 } 943 }
1128 944 // fall through
1129 } 945 case SNMP_SEC_LEVEL_AUTHNOPRIV: {
1130 else { 946 if (privpasswd == NULL) {
1131 usage2 (_("Invalid SNMP version"), proto); 947 die(STATE_UNKNOWN, "No privacy passphrase was given, but privacy was requested");
948 }
949 int auth_key_generated = generate_Ku(
950 config.snmp_params.snmp_session.securityAuthProto,
951 (unsigned int)config.snmp_params.snmp_session.securityAuthProtoLen, privpasswd,
952 strlen((const char *)privpasswd), config.snmp_params.snmp_session.securityAuthKey,
953 &config.snmp_params.snmp_session.securityAuthKeyLen);
954
955 if (auth_key_generated != SNMPERR_SUCCESS) {
956 die(STATE_UNKNOWN, "Failed to generate privacy key");
957 }
958 } break;
959 case SNMP_SEC_LEVEL_NOAUTH:
960 // No auth, no priv, not much todo
961 break;
962 }
1132 } 963 }
1133 964
1134 return OK; 965 process_arguments_wrapper result = {
966 .config = config,
967 .errorcode = OK,
968 };
969 return result;
1135} 970}
1136 971
1137
1138
1139/* trim leading whitespace 972/* trim leading whitespace
1140 if there is a leading quote, make sure it balances */ 973 if there is a leading quote, make sure it balances */
1141 974char *trim_whitespaces_and_check_quoting(char *str) {
1142char * 975 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */
1143thisarg (char *str) 976 if (str[0] == '\'') { /* handle SIMPLE quoted strings */
1144{ 977 if (strlen(str) == 1 || !strstr(str + 1, "'")) {
1145 str += strspn (str, " \t\r\n"); /* trim any leading whitespace */ 978 die(STATE_UNKNOWN, _("Unbalanced quotes\n"));
1146 if (str[0] == '\'') { /* handle SIMPLE quoted strings */ 979 }
1147 if (strlen (str) == 1 || !strstr (str + 1, "'"))
1148 die (STATE_UNKNOWN, _("Unbalanced quotes\n"));
1149 } 980 }
1150 return str; 981 return str;
1151} 982}
1152 983
1153
1154
1155/* if there's a leading quote, advance to the trailing quote 984/* if there's a leading quote, advance to the trailing quote
1156 set the trailing quote to '\x0' 985 set the trailing quote to '\x0'
1157 if the string continues, advance beyond the comma */ 986 if the string continues, advance beyond the comma */
1158 987
1159char * 988char *get_next_argument(char *str) {
1160nextarg (char *str)
1161{
1162 if (str[0] == '\'') { 989 if (str[0] == '\'') {
1163 str[0] = 0; 990 str[0] = 0;
1164 if (strlen (str) > 1) { 991 if (strlen(str) > 1) {
1165 str = strstr (str + 1, "'"); 992 str = strstr(str + 1, "'");
1166 return (++str); 993 return (++str);
1167 } 994 }
1168 else { 995 return NULL;
1169 return NULL;
1170 }
1171 } 996 }
1172 if (str[0] == ',') { 997 if (str[0] == ',') {
1173 str[0] = 0; 998 str[0] = 0;
1174 if (strlen (str) > 1) { 999 if (strlen(str) > 1) {
1175 return (++str); 1000 return (++str);
1176 } 1001 }
1177 else { 1002 return NULL;
1178 return NULL;
1179 }
1180 } 1003 }
1181 if ((str = strstr (str, ",")) && strlen (str) > 1) { 1004 if ((str = strstr(str, ",")) && strlen(str) > 1) {
1182 str[0] = 0; 1005 str[0] = 0;
1183 return (++str); 1006 return (++str);
1184 } 1007 }
1185 return NULL; 1008 return NULL;
1186} 1009}
1187 1010
1011void print_help(void) {
1012 print_revision(progname, NP_VERSION);
1188 1013
1014 printf(COPYRIGHT, copyright, email);
1189 1015
1190/* multiply result (values 0 < n < 1 work as divider) */ 1016 printf("%s\n", _("Check status of remote machines and obtain system information via SNMP"));
1191char *
1192multiply (char *str)
1193{
1194 char *endptr;
1195 double val;
1196 char *conv = "%f";
1197
1198 if(multiplier == 1)
1199 return(str);
1200
1201 if(verbose>2)
1202 printf(" multiply input: %s\n", str);
1203
1204 val = strtod (str, &endptr);
1205 if ((val == 0.0) && (endptr == str)) {
1206 die(STATE_UNKNOWN, _("multiplier set (%.1f), but input is not a number: %s"), multiplier, str);
1207 }
1208
1209 if(verbose>2)
1210 printf(" multiply extracted double: %f\n", val);
1211 val *= multiplier;
1212 if (fmtstr_set) {
1213 conv = fmtstr;
1214 }
1215 if (val == (int)val) {
1216 snprintf(buffer, DEFAULT_BUFFER_SIZE, "%.0f", val);
1217 } else {
1218 if(verbose>2)
1219 printf(" multiply using format: %s\n", conv);
1220 snprintf(buffer, DEFAULT_BUFFER_SIZE, conv, val);
1221 }
1222 if(verbose>2)
1223 printf(" multiply result: %s\n", buffer);
1224 return buffer;
1225}
1226
1227
1228void
1229print_help (void)
1230{
1231 print_revision (progname, NP_VERSION);
1232
1233 printf (COPYRIGHT, copyright, email);
1234
1235 printf ("%s\n", _("Check status of remote machines and obtain system information via SNMP"));
1236 1017
1237 printf ("\n\n"); 1018 printf("\n\n");
1238 1019
1239 print_usage (); 1020 print_usage();
1240 1021
1241 printf (UT_HELP_VRSN); 1022 printf(UT_HELP_VRSN);
1242 printf (UT_EXTRA_OPTS); 1023 printf(UT_EXTRA_OPTS);
1243 printf (UT_IPv46); 1024 printf(UT_HOST_PORT, 'p', DEFAULT_PORT);
1244
1245 printf (UT_HOST_PORT, 'p', DEFAULT_PORT);
1246 1025
1247 /* SNMP and Authentication Protocol */ 1026 /* SNMP and Authentication Protocol */
1248 printf (" %s\n", "-n, --next"); 1027 printf(" %s\n", "-n, --next");
1249 printf (" %s\n", _("Use SNMP GETNEXT instead of SNMP GET")); 1028 printf(" %s\n", _("Use SNMP GETNEXT instead of SNMP GET"));
1250 printf (" %s\n", "-P, --protocol=[1|2c|3]"); 1029 printf(" %s\n", "-P, --protocol=[1|2c|3]");
1251 printf (" %s\n", _("SNMP protocol version")); 1030 printf(" %s\n", _("SNMP protocol version"));
1252 printf (" %s\n", "-N, --context=CONTEXT"); 1031 printf(" %s\n", "-N, --context=CONTEXT");
1253 printf (" %s\n", _("SNMPv3 context")); 1032 printf(" %s\n", _("SNMPv3 context"));
1254 printf (" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]"); 1033 printf(" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]");
1255 printf (" %s\n", _("SNMPv3 securityLevel")); 1034 printf(" %s\n", _("SNMPv3 securityLevel"));
1256 printf (" %s\n", "-a, --authproto=AUTHENTICATION_PROTOCOL"); 1035 printf(" %s\n", "-a, --authproto=[MD5|SHA]");
1257 printf (" %s\n", _("SNMPv3 authentication protocol (default MD5), available options depend on the specific version of the net-snmp tools")); 1036 printf(" %s\n", _("SNMPv3 auth proto"));
1258 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")); 1037#ifdef HAVE_USM_DES_PRIV_PROTOCOL
1259 printf (" %s\n", "-x, --privproto=PRIVACY_PROTOCOL"); 1038 printf(" %s\n", "-x, --privproto=[DES|AES]");
1260 printf (" %s\n", _("SNMPv3 privacy protocol (default DES), available options depend on the specific version of the net-snmp tools")); 1039 printf(" %s\n", _("SNMPv3 priv proto (default DES)"));
1261 printf (" %s\n", _("if < 5.8 DES and AES should be available, if >= 5.8 additionally AES-192 and AES-256")); 1040#else
1041 printf(" %s\n", "-x, --privproto=[AES]");
1042 printf(" %s\n", _("SNMPv3 priv proto (default AES)"));
1043#endif
1262 1044
1263 /* Authentication Tokens*/ 1045 /* Authentication Tokens*/
1264 printf (" %s\n", "-C, --community=STRING"); 1046 printf(" %s\n", "-C, --community=STRING");
1265 printf (" %s ", _("Optional community string for SNMP communication")); 1047 printf(" %s ", _("Optional community string for SNMP communication"));
1266 printf ("(%s \"%s\")\n", _("default is") ,DEFAULT_COMMUNITY); 1048 printf("(%s \"%s\")\n", _("default is"), DEFAULT_COMMUNITY);
1267 printf (" %s\n", "-U, --secname=USERNAME"); 1049 printf(" %s\n", "-U, --secname=USERNAME");
1268 printf (" %s\n", _("SNMPv3 username")); 1050 printf(" %s\n", _("SNMPv3 username"));
1269 printf (" %s\n", "-A, --authpasswd=PASSWORD"); 1051 printf(" %s\n", "-A, --authpasswd=PASSWORD");
1270 printf (" %s\n", _("SNMPv3 authentication password")); 1052 printf(" %s\n", _("SNMPv3 authentication password"));
1271 printf (" %s\n", "-X, --privpasswd=PASSWORD"); 1053 printf(" %s\n", "-X, --privpasswd=PASSWORD");
1272 printf (" %s\n", _("SNMPv3 privacy password")); 1054 printf(" %s\n", _("SNMPv3 privacy password"));
1055 printf(" %s\n", "--connection-prefix");
1056 printf(" Connection prefix, may be one of udp, udp6, tcp, unix, ipx, udp6, udpv6, udpipv6, "
1057 "tcp6, tcpv6, tcpipv6, tls, dtls - "
1058 "default is \"udp\"\n");
1273 1059
1274 /* OID Stuff */ 1060 /* OID Stuff */
1275 printf (" %s\n", "-o, --oid=OID(s)"); 1061 printf(" %s\n", "-o, --oid=OID(s)");
1276 printf (" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query")); 1062 printf(" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query"));
1277 printf (" %s\n", "-m, --miblist=STRING"); 1063 printf(" %s\n", "-m, --miblist=STRING");
1278 printf (" %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'")); 1064 printf(" %s\n",
1279 printf (" %s\n", _("for symbolic OIDs.)")); 1065 _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'"));
1280 printf (" %s\n", "-d, --delimiter=STRING"); 1066 printf(" %s\n", _("for symbolic OIDs.)"));
1281 printf (" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER); 1067 printf(" %s\n", _("Any data on the right hand side of the delimiter is considered"));
1282 printf (" %s\n", _("Any data on the right hand side of the delimiter is considered")); 1068 printf(" %s\n", _("to be the data that should be used in the evaluation."));
1283 printf (" %s\n", _("to be the data that should be used in the evaluation.")); 1069 printf(" %s\n", "-z, --nulloid=#");
1284 printf (" %s\n", "-z, --nulloid=#"); 1070 printf(" %s\n", _("If the check returns a 0 length string or NULL value"));
1285 printf (" %s\n", _("If the check returns a 0 length string or NULL value")); 1071 printf(" %s\n", _("This option allows you to choose what status you want it to exit"));
1286 printf (" %s\n", _("This option allows you to choose what status you want it to exit")); 1072 printf(" %s\n", _("Excluding this option renders the default exit of 3(STATE_UNKNOWN)"));
1287 printf (" %s\n", _("Excluding this option renders the default exit of 3(STATE_UNKNOWN)")); 1073 printf(" %s\n", _("0 = OK"));
1288 printf (" %s\n", _("0 = OK")); 1074 printf(" %s\n", _("1 = WARNING"));
1289 printf (" %s\n", _("1 = WARNING")); 1075 printf(" %s\n", _("2 = CRITICAL"));
1290 printf (" %s\n", _("2 = CRITICAL")); 1076 printf(" %s\n", _("3 = UNKNOWN"));
1291 printf (" %s\n", _("3 = UNKNOWN"));
1292 1077
1293 /* Tests Against Integers */ 1078 /* Tests Against Integers */
1294 printf (" %s\n", "-w, --warning=THRESHOLD(s)"); 1079 printf(" %s\n", "-w, --warning=THRESHOLD(s)");
1295 printf (" %s\n", _("Warning threshold range(s)")); 1080 printf(" %s\n", _("Warning threshold range(s)"));
1296 printf (" %s\n", "-c, --critical=THRESHOLD(s)"); 1081 printf(" %s\n", "-c, --critical=THRESHOLD(s)");
1297 printf (" %s\n", _("Critical threshold range(s)")); 1082 printf(" %s\n", _("Critical threshold range(s)"));
1298 printf (" %s\n", "--rate"); 1083 printf(" %s\n", "--offset=OFFSET");
1299 printf (" %s\n", _("Enable rate calculation. See 'Rate Calculation' below")); 1084 printf(" %s\n", _("Add/subtract the specified OFFSET to numeric sensor data"));
1300 printf (" %s\n", "--rate-multiplier");
1301 printf (" %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute"));
1302 printf (" %s\n", "--offset=OFFSET");
1303 printf (" %s\n", _("Add/subtract the specified OFFSET to numeric sensor data"));
1304 1085
1305 /* Tests Against Strings */ 1086 /* Tests Against Strings */
1306 printf (" %s\n", "-s, --string=STRING"); 1087 printf(" %s\n", "-s, --string=STRING");
1307 printf (" %s\n", _("Return OK state (for that OID) if STRING is an exact match")); 1088 printf(" %s\n", _("Return OK state (for that OID) if STRING is an exact match"));
1308 printf (" %s\n", "-r, --ereg=REGEX"); 1089 printf(" %s\n", "-r, --ereg=REGEX");
1309 printf (" %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches")); 1090 printf(" %s\n",
1310 printf (" %s\n", "-R, --eregi=REGEX"); 1091 _("Return OK state (for that OID) if extended regular expression REGEX matches"));
1311 printf (" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches")); 1092 printf(" %s\n", "-R, --eregi=REGEX");
1312 printf (" %s\n", "--invert-search"); 1093 printf(" %s\n",
1313 printf (" %s\n", _("Invert search result (CRITICAL if found)")); 1094 _("Return OK state (for that OID) if case-insensitive extended REGEX matches"));
1095 printf(" %s\n", "--invert-search");
1096 printf(" %s\n", _("Invert search result (CRITICAL if found)"));
1314 1097
1315 /* Output Formatting */ 1098 /* Output Formatting */
1316 printf (" %s\n", "-l, --label=STRING"); 1099 printf(" %s\n", "-l, --label=STRING");
1317 printf (" %s\n", _("Prefix label for output from plugin")); 1100 printf(" %s\n", _("Prefix label for output from plugin"));
1318 printf (" %s\n", "-u, --units=STRING"); 1101 printf(" %s\n", "-u, --units=STRING");
1319 printf (" %s\n", _("Units label(s) for output data (e.g., 'sec.').")); 1102 printf(" %s\n", _("Units label(s) for output data (e.g., 'sec.')."));
1320 printf (" %s\n", "-D, --output-delimiter=STRING"); 1103 printf(" %s\n", "-M, --multiplier=FLOAT");
1321 printf (" %s\n", _("Separates output on multiple OID requests")); 1104 printf(" %s\n", _("Multiplies current value, 0 < n < 1 works as divider, defaults to 1"));
1322 printf (" %s\n", "-M, --multiplier=FLOAT"); 1105 printf(UT_OUTPUT_FORMAT);
1323 printf (" %s\n", _("Multiplies current value, 0 < n < 1 works as divider, defaults to 1"));
1324 printf (" %s\n", "-f, --fmtstr=STRING");
1325 printf (" %s\n", _("C-style format string for float values (see option -M)"));
1326
1327 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1328 printf (" %s\n", _("NOTE the final timeout value is calculated using this formula: timeout_interval * retries + 5"));
1329 printf (" %s\n", "-e, --retries=INTEGER");
1330 printf (" %s%i\n", _("Number of retries to be used in the requests, default: "), DEFAULT_RETRIES);
1331
1332 printf (" %s\n", "-O, --perf-oids");
1333 printf (" %s\n", _("Label performance data with OIDs instead of --label's"));
1334
1335 printf (" %s\n", "--ignore-mib-parsing-errors");
1336 printf (" %s\n", _("Tell snmpget to not print errors encountered when parsing MIB files"));
1337
1338 printf (UT_VERBOSE);
1339
1340 printf ("\n");
1341 printf ("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package."));
1342 printf ("%s\n", _("if you don't have the package installed, you will need to download it from"));
1343 printf ("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin."));
1344
1345 printf ("\n");
1346 printf ("%s\n", _("Notes:"));
1347 printf (" %s\n", _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited "));
1348 printf (" %s\n", _("list (lists with internal spaces must be quoted)."));
1349 1106
1350 printf(" -%s", UT_THRESHOLDS_NOTES); 1107 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1108 printf(" %s\n", _("NOTE the final timeout value is calculated using this formula: "
1109 "timeout_interval * retries + 5"));
1110 printf(" %s\n", "-e, --retries=INTEGER");
1111 printf(" %s%i\n", _("Number of retries to be used in the requests, default: "),
1112 DEFAULT_RETRIES);
1113
1114 printf(" %s\n", "-O, --perf-oids");
1115 printf(" %s\n", _("Label performance data with OIDs instead of --label's"));
1351 1116
1352 printf (" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'")); 1117 printf(" %s\n", "--ignore-mib-parsing-errors");
1353 printf (" %s\n", _("- Note that only one string and one regex may be checked at present")); 1118 printf(" %s\n", _("Do to not print errors encountered when parsing MIB files"));
1354 printf (" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value")); 1119
1355 printf (" %s\n", _("returned from the SNMP query is an unsigned integer.")); 1120 printf(UT_VERBOSE);
1356 1121
1357 printf("\n"); 1122 printf("\n");
1358 printf("%s\n", _("Rate Calculation:")); 1123 printf("%s\n", _("This plugin relies (links against) on the NET-SNMP libraries."));
1359 printf(" %s\n", _("In many places, SNMP returns counters that are only meaningful when")); 1124 printf("%s\n",
1360 printf(" %s\n", _("calculating the counter difference since the last check. check_snmp")); 1125 _("if you don't have the libraries installed, you will need to download them from"));
1361 printf(" %s\n", _("saves the last state information in a file so that the rate per second")); 1126 printf("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin."));
1362 printf(" %s\n", _("can be calculated. Use the --rate option to save state information."));
1363 printf(" %s\n", _("On the first run, there will be no prior state - this will return with OK."));
1364 printf(" %s\n", _("The state is uniquely determined by the arguments to the plugin, so"));
1365 printf(" %s\n", _("changing the arguments will create a new state file."));
1366
1367 printf (UT_SUPPORT);
1368}
1369 1127
1128 printf("\n");
1129 printf("%s\n", _("Notes:"));
1130 printf(" %s\n",
1131 _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited "));
1132 printf(" %s\n", _("list (lists with internal spaces must be quoted)."));
1370 1133
1134 printf(" -%s", UT_THRESHOLDS_NOTES);
1135
1136 printf(" %s\n",
1137 _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'"));
1138 printf(" %s\n", _("- Note that only one string and one regex may be checked at present"));
1139 printf(" %s\n",
1140 _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value"));
1141 printf(" %s\n", _("returned from the SNMP query is an unsigned integer."));
1142
1143 printf(UT_SUPPORT);
1144}
1371 1145
1372void 1146void print_usage(void) {
1373print_usage (void) 1147 printf("%s\n", _("Usage:"));
1374{ 1148 printf("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n", progname);
1375 printf ("%s\n", _("Usage:")); 1149 printf("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n");
1376 printf ("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n",progname); 1150 printf("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
1377 printf ("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n"); 1151 printf("[-m miblist] [-P snmp version] [-N context] [-L seclevel] [-U secname]\n");
1378 printf ("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n"); 1152 printf("[-a authproto] [-A authpasswd] [-x privproto] [-X privpasswd] [-4|6]\n");
1379 printf ("[-m miblist] [-P snmp version] [-N context] [-L seclevel] [-U secname]\n"); 1153 printf("[-M multiplier]\n");
1380 printf ("[-a authproto] [-A authpasswd] [-x privproto] [-X privpasswd] [-4|6]\n");
1381 printf ("[-M multiplier [-f format]]\n");
1382} 1154}
diff --git a/plugins/check_snmp.d/check_snmp_helpers.c b/plugins/check_snmp.d/check_snmp_helpers.c
new file mode 100644
index 00000000..ecbfc5dd
--- /dev/null
+++ b/plugins/check_snmp.d/check_snmp_helpers.c
@@ -0,0 +1,934 @@
1#include "./check_snmp_helpers.h"
2#include <string.h>
3#include "../../lib/utils_base.h"
4#include "config.h"
5#include <assert.h>
6#include "../utils.h"
7#include "output.h"
8#include "states.h"
9#include <sys/stat.h>
10#include <ctype.h>
11
12extern int verbose;
13
14check_snmp_test_unit check_snmp_test_unit_init() {
15 check_snmp_test_unit tmp = {
16 .threshold = mp_thresholds_init(),
17 };
18 return tmp;
19}
20
21int check_snmp_set_thresholds(const char *threshold_string, check_snmp_test_unit test_units[],
22 size_t max_test_units, bool is_critical) {
23
24 if (threshold_string == NULL || strlen(threshold_string) == 0) {
25 // No input, do nothing
26 return 0;
27 }
28
29 if (strchr(threshold_string, ',') != NULL) {
30 // Got a comma in the string, should be multiple values
31 size_t tu_index = 0;
32
33 while (threshold_string[0] == ',') {
34 // got commas at the beginning, so skip some values
35 tu_index++;
36 threshold_string++;
37 }
38
39 for (char *ptr = strtok(threshold_string, ", "); ptr != NULL;
40 ptr = strtok(NULL, ", "), tu_index++) {
41
42 if (tu_index > max_test_units) {
43 // More thresholds then values, just ignore them
44 return 0;
45 }
46
47 // edge case: maybe we got `,,` to skip a value
48 if (strlen(ptr) == 0) {
49 // no threshold given, do not set it then
50 continue;
51 }
52
53 mp_range_parsed tmp = mp_parse_range_string(ptr);
54 if (tmp.error != MP_PARSING_SUCCES) {
55 die(STATE_UNKNOWN, "Unable to parse critical threshold range: %s", ptr);
56 }
57
58 if (is_critical) {
59 test_units[tu_index].threshold.critical = tmp.range;
60 test_units[tu_index].threshold.critical_is_set = true;
61 } else {
62 test_units[tu_index].threshold.warning = tmp.range;
63 test_units[tu_index].threshold.warning_is_set = true;
64 }
65 }
66
67 } else {
68 // Single value
69 // only valid for the first test unit
70 mp_range_parsed tmp = mp_parse_range_string(threshold_string);
71 if (tmp.error != MP_PARSING_SUCCES) {
72 die(STATE_UNKNOWN, "Unable to parse critical threshold range: %s", threshold_string);
73 }
74
75 if (is_critical) {
76 test_units[0].threshold.critical = tmp.range;
77 test_units[0].threshold.critical_is_set = true;
78 } else {
79 test_units[0].threshold.warning = tmp.range;
80 test_units[0].threshold.warning_is_set = true;
81 }
82 }
83
84 return 0;
85}
86
87const int DEFAULT_PROTOCOL = SNMP_VERSION_1;
88const char DEFAULT_OUTPUT_DELIMITER[] = " ";
89
90const int RANDOM_STATE_DATA_LENGTH_PREDICTION = 8192;
91
92check_snmp_config check_snmp_config_init() {
93 check_snmp_config tmp = {
94 .snmp_params =
95 {
96 .use_getnext = false,
97
98 .ignore_mib_parsing_errors = false,
99 .need_mibs = false,
100
101 .test_units = NULL,
102 .num_of_test_units = 0,
103 },
104
105 .evaluation_params =
106 {
107 .nulloid_result = STATE_UNKNOWN, // state to return if no result for query
108
109 .invert_search = true,
110 .regex_cmp_value = {},
111 .string_cmp_value = "",
112
113 .multiplier = 1.0,
114 .multiplier_set = false,
115 .offset = 0,
116 .offset_set = false,
117
118 .use_oid_as_perf_data_label = false,
119
120 .calculate_rate = false,
121 .rate_multiplier = 1,
122 },
123 };
124
125 snmp_sess_init(&tmp.snmp_params.snmp_session);
126
127 tmp.snmp_params.snmp_session.retries = DEFAULT_RETRIES;
128 tmp.snmp_params.snmp_session.version = DEFAULT_SNMP_VERSION;
129 tmp.snmp_params.snmp_session.securityLevel = SNMP_SEC_LEVEL_NOAUTH;
130 tmp.snmp_params.snmp_session.community = (unsigned char *)"public";
131 tmp.snmp_params.snmp_session.community_len = strlen("public");
132 return tmp;
133}
134
135snmp_responces do_snmp_query(check_snmp_config_snmp_parameters parameters) {
136 if (parameters.ignore_mib_parsing_errors) {
137 char *opt_toggle_res = snmp_mib_toggle_options("e");
138 if (opt_toggle_res != NULL) {
139 die(STATE_UNKNOWN, "Unable to disable MIB parsing errors");
140 }
141 }
142
143 struct snmp_pdu *pdu = NULL;
144 if (parameters.use_getnext) {
145 pdu = snmp_pdu_create(SNMP_MSG_GETNEXT);
146 } else {
147 pdu = snmp_pdu_create(SNMP_MSG_GET);
148 }
149
150 for (size_t i = 0; i < parameters.num_of_test_units; i++) {
151 assert(parameters.test_units[i].oid != NULL);
152 if (verbose > 0) {
153 printf("OID %zu to parse: %s\n", i, parameters.test_units[i].oid);
154 }
155
156 oid tmp_OID[MAX_OID_LEN];
157 size_t tmp_OID_len = MAX_OID_LEN;
158 if (snmp_parse_oid(parameters.test_units[i].oid, tmp_OID, &tmp_OID_len) != NULL) {
159 // success
160 snmp_add_null_var(pdu, tmp_OID, tmp_OID_len);
161 } else {
162 // failed
163 snmp_perror("Parsing failure");
164 die(STATE_UNKNOWN, "Failed to parse OID\n");
165 }
166 }
167
168 const int timeout_safety_tolerance = 5;
169 alarm((timeout_interval * (unsigned int)parameters.snmp_session.retries) +
170 timeout_safety_tolerance);
171
172 struct snmp_session *active_session = snmp_open(&parameters.snmp_session);
173 if (active_session == NULL) {
174 int pcliberr = 0;
175 int psnmperr = 0;
176 char *pperrstring = NULL;
177 snmp_error(&parameters.snmp_session, &pcliberr, &psnmperr, &pperrstring);
178 die(STATE_UNKNOWN, "Failed to open SNMP session: %s\n", pperrstring);
179 }
180
181 struct snmp_pdu *response = NULL;
182 int snmp_query_status = snmp_synch_response(active_session, pdu, &response);
183
184 if (!(snmp_query_status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR)) {
185 int pcliberr = 0;
186 int psnmperr = 0;
187 char *pperrstring = NULL;
188 snmp_error(active_session, &pcliberr, &psnmperr, &pperrstring);
189
190 if (psnmperr == SNMPERR_TIMEOUT) {
191 // We exit with critical here for some historical reason
192 die(STATE_CRITICAL, "SNMP query ran into a timeout\n");
193 }
194 die(STATE_UNKNOWN, "SNMP query failed: %s\n", pperrstring);
195 }
196
197 snmp_close(active_session);
198
199 /* disable alarm again */
200 alarm(0);
201
202 snmp_responces result = {
203 .errorcode = OK,
204 .response_values = calloc(parameters.num_of_test_units, sizeof(response_value)),
205 };
206
207 if (result.response_values == NULL) {
208 result.errorcode = ERROR;
209 return result;
210 }
211
212 // We got the the query results, now process them
213 size_t loop_index = 0;
214 for (netsnmp_variable_list *vars = response->variables; vars;
215 vars = vars->next_variable, loop_index++) {
216
217 for (size_t jdx = 0; jdx < vars->name_length; jdx++) {
218 result.response_values[loop_index].oid[jdx] = vars->name[jdx];
219 }
220 result.response_values[loop_index].oid_length = vars->name_length;
221
222 switch (vars->type) {
223 case ASN_OCTET_STR: {
224 result.response_values[loop_index].string_response = strdup((char *)vars->val.string);
225 result.response_values[loop_index].type = vars->type;
226 if (verbose) {
227 printf("Debug: Got a string as response: %s\n", vars->val.string);
228 }
229 }
230 continue;
231 case ASN_OPAQUE:
232 if (verbose) {
233 printf("Debug: Got OPAQUE\n");
234 }
235 break;
236 /* Numerical values */
237 case ASN_COUNTER64: {
238 if (verbose) {
239 printf("Debug: Got counter64\n");
240 }
241 struct counter64 tmp = *(vars->val.counter64);
242 uint64_t counter = (tmp.high << 32) + tmp.low;
243 result.response_values[loop_index].value.uIntVal = counter;
244 result.response_values[loop_index].type = vars->type;
245 } break;
246 case ASN_GAUGE: // same as ASN_UNSIGNED
247 case ASN_TIMETICKS:
248 case ASN_COUNTER:
249 case ASN_UINTEGER: {
250 if (verbose) {
251 printf("Debug: Got a Integer like\n");
252 }
253 result.response_values[loop_index].value.uIntVal = (unsigned long)*(vars->val.integer);
254 result.response_values[loop_index].type = vars->type;
255 } break;
256 case ASN_INTEGER: {
257 if (verbose) {
258 printf("Debug: Got a Integer\n");
259 }
260 result.response_values[loop_index].value.intVal = *(vars->val.integer);
261 result.response_values[loop_index].type = vars->type;
262 } break;
263 case ASN_FLOAT: {
264 if (verbose) {
265 printf("Debug: Got a float\n");
266 }
267 result.response_values[loop_index].value.doubleVal = *(vars->val.floatVal);
268 result.response_values[loop_index].type = vars->type;
269 } break;
270 case ASN_DOUBLE: {
271 if (verbose) {
272 printf("Debug: Got a double\n");
273 }
274 result.response_values[loop_index].value.doubleVal = *(vars->val.doubleVal);
275 result.response_values[loop_index].type = vars->type;
276 } break;
277 case ASN_IPADDRESS:
278 if (verbose) {
279 printf("Debug: Got an IP address\n");
280 }
281 result.response_values[loop_index].type = vars->type;
282
283 // TODO: print address here, state always ok? or regex match?
284 break;
285 default:
286 if (verbose) {
287 printf("Debug: Got a unmatched result type: %hhu\n", vars->type);
288 }
289 // TODO: Error here?
290 break;
291 }
292 }
293
294 return result;
295}
296
297check_snmp_evaluation evaluate_single_unit(response_value response,
298 check_snmp_evaluation_parameters eval_params,
299 check_snmp_test_unit test_unit, time_t query_timestamp,
300 check_snmp_state_entry prev_state,
301 bool have_previous_state) {
302 mp_subcheck sc_oid_test = mp_subcheck_init();
303
304 if ((test_unit.label != NULL) && (strcmp(test_unit.label, "") != 0)) {
305 xasprintf(&sc_oid_test.output, "%s - ", test_unit.label);
306 } else {
307 sc_oid_test.output = strdup("");
308 }
309
310 char oid_string[(MAX_OID_LEN * 2) + 1] = {};
311
312 int oid_string_result =
313 snprint_objid(oid_string, (MAX_OID_LEN * 2) + 1, response.oid, response.oid_length);
314 if (oid_string_result <= 0) {
315 // TODO error here
316 die(STATE_UNKNOWN, "snprint_objid failed\n");
317 }
318
319 xasprintf(&sc_oid_test.output, "%sOID: %s", sc_oid_test.output, oid_string);
320 sc_oid_test = mp_set_subcheck_default_state(sc_oid_test, STATE_OK);
321
322 if (verbose > 2) {
323 printf("Processing oid %s\n", oid_string);
324 }
325
326 bool got_a_numerical_value = false;
327 mp_perfdata_value pd_result_val = {0};
328
329 check_snmp_state_entry result_state = {
330 .timestamp = query_timestamp,
331 .oid_length = response.oid_length,
332 .type = response.type,
333 };
334
335 for (size_t i = 0; i < response.oid_length; i++) {
336 result_state.oid[i] = response.oid[i];
337 }
338
339 if (have_previous_state) {
340 if (query_timestamp == prev_state.timestamp) {
341 // somehow we have the same timestamp again, that can't be good
342 sc_oid_test = mp_set_subcheck_state(sc_oid_test, STATE_UNKNOWN);
343 xasprintf(&sc_oid_test.output, "Time duration between plugin calls is invalid");
344
345 check_snmp_evaluation result = {
346 .sc = sc_oid_test,
347 .state = result_state,
348 };
349
350 return result;
351 }
352 }
353 // compute rate time difference
354 double timeDiff = 0;
355 if (have_previous_state) {
356 if (verbose) {
357 printf("Previous timestamp: %s", ctime(&prev_state.timestamp));
358 printf("Current timestamp: %s", ctime(&query_timestamp));
359 }
360 timeDiff = difftime(query_timestamp, prev_state.timestamp) / eval_params.rate_multiplier;
361 }
362
363 mp_perfdata pd_num_val = {};
364
365 switch (response.type) {
366 case ASN_OCTET_STR: {
367 char *tmp = response.string_response;
368 if (strchr(tmp, '"') != NULL) {
369 // got double quote in the string
370 if (strchr(tmp, '\'') != NULL) {
371 // got single quote in the string too
372 // dont quote that at all to avoid even more confusion
373 xasprintf(&sc_oid_test.output, "%s - Value: %s", sc_oid_test.output, tmp);
374 } else {
375 // quote with single quotes
376 xasprintf(&sc_oid_test.output, "%s - Value: '%s'", sc_oid_test.output, tmp);
377 }
378 } else {
379 // quote with double quotes
380 xasprintf(&sc_oid_test.output, "%s - Value: \"%s\"", sc_oid_test.output, tmp);
381 }
382
383 if (strlen(tmp) == 0) {
384 sc_oid_test = mp_set_subcheck_state(sc_oid_test, eval_params.nulloid_result);
385 }
386
387 // String matching test
388 if ((test_unit.eval_mthd.crit_string)) {
389 if (strcmp(tmp, eval_params.string_cmp_value)) {
390 sc_oid_test = mp_set_subcheck_state(
391 sc_oid_test, (eval_params.invert_search) ? STATE_CRITICAL : STATE_OK);
392 } else {
393 sc_oid_test = mp_set_subcheck_state(
394 sc_oid_test, (eval_params.invert_search) ? STATE_OK : STATE_CRITICAL);
395 }
396 } else if (test_unit.eval_mthd.crit_regex) {
397 const size_t nmatch = eval_params.regex_cmp_value.re_nsub + 1;
398 regmatch_t pmatch[nmatch];
399 memset(pmatch, '\0', sizeof(regmatch_t) * nmatch);
400
401 int excode = regexec(&eval_params.regex_cmp_value, tmp, nmatch, pmatch, 0);
402 if (excode == 0) {
403 sc_oid_test = mp_set_subcheck_state(
404 sc_oid_test, (eval_params.invert_search) ? STATE_OK : STATE_CRITICAL);
405 } else if (excode != REG_NOMATCH) {
406 char errbuf[MAX_INPUT_BUFFER] = "";
407 regerror(excode, &eval_params.regex_cmp_value, errbuf, MAX_INPUT_BUFFER);
408 printf(_("Execute Error: %s\n"), errbuf);
409 exit(STATE_CRITICAL);
410 } else { // REG_NOMATCH
411 sc_oid_test = mp_set_subcheck_state(
412 sc_oid_test, eval_params.invert_search ? STATE_CRITICAL : STATE_OK);
413 }
414 }
415 } break;
416 case ASN_COUNTER64:
417 got_a_numerical_value = true;
418
419 result_state.value.uIntVal = response.value.uIntVal;
420 result_state.type = response.type;
421
422 // TODO: perfdata unit counter
423 if (eval_params.calculate_rate && have_previous_state) {
424 if (prev_state.value.uIntVal > response.value.uIntVal) {
425 // overflow
426 unsigned long long tmp =
427 (UINT64_MAX - prev_state.value.uIntVal) + response.value.uIntVal;
428
429 tmp /= timeDiff;
430 pd_result_val = mp_create_pd_value(tmp);
431 } else {
432 pd_result_val = mp_create_pd_value(
433 (response.value.uIntVal - prev_state.value.uIntVal) / timeDiff);
434 }
435 } else {
436 // It's only a counter if we cont compute rate
437 pd_num_val.uom = "c";
438 pd_result_val = mp_create_pd_value(response.value.uIntVal);
439 }
440 break;
441 case ASN_GAUGE: // same as ASN_UNSIGNED
442 case ASN_TIMETICKS:
443 case ASN_COUNTER:
444 case ASN_UINTEGER: {
445 got_a_numerical_value = true;
446 long long treated_value = (long long)response.value.uIntVal;
447
448 if (eval_params.multiplier_set || eval_params.offset_set) {
449 double processed = 0;
450 if (eval_params.offset_set) {
451 processed += eval_params.offset;
452 }
453
454 if (eval_params.multiplier_set) {
455 processed = processed * eval_params.multiplier;
456 }
457
458 treated_value = lround(processed);
459 }
460
461 result_state.value.intVal = treated_value;
462
463 if (eval_params.calculate_rate && have_previous_state) {
464 if (verbose > 2) {
465 printf("%s: Rate calculation (int/counter/gauge): prev: %lli\n", __FUNCTION__,
466 prev_state.value.intVal);
467 printf("%s: Rate calculation (int/counter/gauge): current: %lli\n", __FUNCTION__,
468 treated_value);
469 }
470 double rate = (treated_value - prev_state.value.intVal) / timeDiff;
471 pd_result_val = mp_create_pd_value(rate);
472 } else {
473 pd_result_val = mp_create_pd_value(treated_value);
474
475 if (response.type == ASN_COUNTER) {
476 pd_num_val.uom = "c";
477 }
478 }
479
480 } break;
481 case ASN_INTEGER: {
482 if (eval_params.multiplier_set || eval_params.offset_set) {
483 double processed = 0;
484 if (eval_params.multiplier_set) {
485 processed = (double)response.value.intVal * eval_params.multiplier;
486 }
487
488 if (eval_params.offset_set) {
489 processed += eval_params.offset;
490 }
491
492 result_state.value.doubleVal = processed;
493
494 if (eval_params.calculate_rate && have_previous_state) {
495 pd_result_val =
496 mp_create_pd_value((processed - prev_state.value.doubleVal) / timeDiff);
497 } else {
498 pd_result_val = mp_create_pd_value(processed);
499 }
500 } else {
501 result_state.value.intVal = response.value.intVal;
502
503 if (eval_params.calculate_rate && have_previous_state) {
504 pd_result_val = mp_create_pd_value(
505 (response.value.intVal - prev_state.value.intVal) / timeDiff);
506 } else {
507 pd_result_val = mp_create_pd_value(response.value.intVal);
508 }
509 }
510
511 got_a_numerical_value = true;
512 } break;
513 case ASN_FLOAT: // fallthrough
514 case ASN_DOUBLE: {
515 got_a_numerical_value = true;
516 double tmp = response.value.doubleVal;
517 if (eval_params.offset_set) {
518 tmp += eval_params.offset;
519 }
520
521 if (eval_params.multiplier_set) {
522 tmp *= eval_params.multiplier;
523 }
524
525 if (eval_params.calculate_rate && have_previous_state) {
526 pd_result_val = mp_create_pd_value((tmp - prev_state.value.doubleVal) / timeDiff);
527 } else {
528 pd_result_val = mp_create_pd_value(tmp);
529 }
530 got_a_numerical_value = true;
531
532 result_state.value.doubleVal = tmp;
533 } break;
534 case ASN_IPADDRESS:
535 // TODO
536 break;
537 }
538
539 if (got_a_numerical_value) {
540 if (eval_params.use_oid_as_perf_data_label) {
541 // Use oid for perdata label
542 pd_num_val.label = strdup(oid_string);
543 // TODO strdup error checking
544 } else if (test_unit.label != NULL && strcmp(test_unit.label, "") != 0) {
545 pd_num_val.label = strdup(test_unit.label);
546 } else {
547 pd_num_val.label = strdup(test_unit.oid);
548 }
549
550 if (!(eval_params.calculate_rate && !have_previous_state)) {
551 // some kind of numerical value
552 if (test_unit.unit_value != NULL && strcmp(test_unit.unit_value, "") != 0) {
553 pd_num_val.uom = test_unit.unit_value;
554 }
555
556 pd_num_val.value = pd_result_val;
557
558 xasprintf(&sc_oid_test.output, "%s Value: %s", sc_oid_test.output,
559 pd_value_to_string(pd_result_val));
560
561 if (test_unit.unit_value != NULL && strcmp(test_unit.unit_value, "") != 0) {
562 xasprintf(&sc_oid_test.output, "%s%s", sc_oid_test.output, test_unit.unit_value);
563 }
564
565 if (test_unit.threshold.warning_is_set || test_unit.threshold.critical_is_set) {
566 pd_num_val = mp_pd_set_thresholds(pd_num_val, test_unit.threshold);
567 mp_state_enum tmp_state = mp_get_pd_status(pd_num_val);
568
569 if (tmp_state == STATE_WARNING) {
570 sc_oid_test = mp_set_subcheck_state(sc_oid_test, STATE_WARNING);
571 xasprintf(&sc_oid_test.output, "%s - number violates warning threshold",
572 sc_oid_test.output);
573 } else if (tmp_state == STATE_CRITICAL) {
574 sc_oid_test = mp_set_subcheck_state(sc_oid_test, STATE_CRITICAL);
575 xasprintf(&sc_oid_test.output, "%s - number violates critical threshold",
576 sc_oid_test.output);
577 }
578 }
579
580 mp_add_perfdata_to_subcheck(&sc_oid_test, pd_num_val);
581 } else {
582 // should calculate rate, but there is no previous state, so first run
583 // exit with ok now
584 sc_oid_test = mp_set_subcheck_state(sc_oid_test, STATE_OK);
585 xasprintf(&sc_oid_test.output, "%s - No previous data to calculate rate - assume okay",
586 sc_oid_test.output);
587 }
588 }
589
590 check_snmp_evaluation result = {
591 .sc = sc_oid_test,
592 .state = result_state,
593 };
594
595 return result;
596}
597
598char *_np_state_generate_key(int argc, char **argv);
599
600/*
601 * If time=NULL, use current time. Create state file, with state format
602 * version, default text. Writes version, time, and data. Avoid locking
603 * problems - use mv to write and then swap. Possible loss of state data if
604 * two things writing to same key at same time.
605 * Will die with UNKNOWN if errors
606 */
607void np_state_write_string(state_key stateKey, time_t timestamp, char *stringToStore) {
608 time_t current_time;
609 if (timestamp == 0) {
610 time(&current_time);
611 } else {
612 current_time = timestamp;
613 }
614
615 int result = 0;
616
617 /* If file doesn't currently exist, create directories */
618 if (access(stateKey._filename, F_OK) != 0) {
619 char *directories = NULL;
620 result = asprintf(&directories, "%s", stateKey._filename);
621 if (result < 0) {
622 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
623 }
624
625 for (char *p = directories + 1; *p; p++) {
626 if (*p == '/') {
627 *p = '\0';
628 if ((access(directories, F_OK) != 0) && (mkdir(directories, S_IRWXU) != 0)) {
629 /* Can't free this! Otherwise error message is wrong! */
630 /* np_free(directories); */
631 die(STATE_UNKNOWN, _("Cannot create directory: %s"), directories);
632 }
633 *p = '/';
634 }
635 }
636
637 if (directories) {
638 free(directories);
639 }
640 }
641
642 char *temp_file = NULL;
643 result = asprintf(&temp_file, "%s.XXXXXX", stateKey._filename);
644 if (result < 0) {
645 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
646 }
647
648 int temp_file_desc = 0;
649 if ((temp_file_desc = mkstemp(temp_file)) == -1) {
650 if (temp_file) {
651 free(temp_file);
652 }
653 die(STATE_UNKNOWN, _("Cannot create temporary filename"));
654 }
655
656 FILE *temp_file_pointer = fdopen(temp_file_desc, "w");
657 if (temp_file_pointer == NULL) {
658 close(temp_file_desc);
659 unlink(temp_file);
660 if (temp_file) {
661 free(temp_file);
662 }
663 die(STATE_UNKNOWN, _("Unable to open temporary state file"));
664 }
665
666 fprintf(temp_file_pointer, "# NP State file\n");
667 fprintf(temp_file_pointer, "%d\n", NP_STATE_FORMAT_VERSION);
668 fprintf(temp_file_pointer, "%d\n", stateKey.data_version);
669 fprintf(temp_file_pointer, "%lu\n", current_time);
670 fprintf(temp_file_pointer, "%s\n", stringToStore);
671
672 fchmod(temp_file_desc, S_IRUSR | S_IWUSR | S_IRGRP);
673
674 fflush(temp_file_pointer);
675
676 result = fclose(temp_file_pointer);
677
678 fsync(temp_file_desc);
679
680 if (result != 0) {
681 unlink(temp_file);
682 if (temp_file) {
683 free(temp_file);
684 }
685 die(STATE_UNKNOWN, _("Error writing temp file"));
686 }
687
688 if (rename(temp_file, stateKey._filename) != 0) {
689 unlink(temp_file);
690 if (temp_file) {
691 free(temp_file);
692 }
693 die(STATE_UNKNOWN, _("Cannot rename state temp file"));
694 }
695
696 if (temp_file) {
697 free(temp_file);
698 }
699}
700
701/*
702 * Read the state file
703 */
704bool _np_state_read_file(FILE *state_file, state_key stateKey) {
705 time_t current_time;
706 time(&current_time);
707
708 /* Note: This introduces a limit of 8192 bytes in the string data */
709 char *line = (char *)calloc(1, 8192);
710 if (line == NULL) {
711 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
712 }
713
714 bool status = false;
715 enum {
716 STATE_FILE_VERSION,
717 STATE_DATA_VERSION,
718 STATE_DATA_TIME,
719 STATE_DATA_TEXT,
720 STATE_DATA_END
721 } expected = STATE_FILE_VERSION;
722
723 int failure = 0;
724 while (!failure && (fgets(line, 8192, state_file)) != NULL) {
725 size_t pos = strlen(line);
726 if (line[pos - 1] == '\n') {
727 line[pos - 1] = '\0';
728 }
729
730 if (line[0] == '#') {
731 continue;
732 }
733
734 switch (expected) {
735 case STATE_FILE_VERSION: {
736 int i = atoi(line);
737 if (i != NP_STATE_FORMAT_VERSION) {
738 failure++;
739 } else {
740 expected = STATE_DATA_VERSION;
741 }
742 } break;
743 case STATE_DATA_VERSION: {
744 int i = atoi(line);
745 if (i != stateKey.data_version) {
746 failure++;
747 } else {
748 expected = STATE_DATA_TIME;
749 }
750 } break;
751 case STATE_DATA_TIME: {
752 /* If time > now, error */
753 time_t data_time = strtoul(line, NULL, 10);
754 if (data_time > current_time) {
755 failure++;
756 } else {
757 stateKey.state_data->time = data_time;
758 expected = STATE_DATA_TEXT;
759 }
760 } break;
761 case STATE_DATA_TEXT:
762 stateKey.state_data->data = strdup(line);
763 if (stateKey.state_data->data == NULL) {
764 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
765 }
766 stateKey.state_data->length = strlen(line);
767 expected = STATE_DATA_END;
768 status = true;
769 break;
770 case STATE_DATA_END:;
771 }
772 }
773
774 if (line) {
775 free(line);
776 }
777 return status;
778}
779/*
780 * Will return NULL if no data is available (first run). If key currently
781 * exists, read data. If state file format version is not expected, return
782 * as if no data. Get state data version number and compares to expected.
783 * If numerically lower, then return as no previous state. die with UNKNOWN
784 * if exceptional error.
785 */
786state_data *np_state_read(state_key stateKey) {
787 /* Open file. If this fails, no previous state found */
788 FILE *statefile = fopen(stateKey._filename, "r");
789 state_data *this_state_data = (state_data *)calloc(1, sizeof(state_data));
790 if (statefile != NULL) {
791
792 if (this_state_data == NULL) {
793 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
794 }
795
796 this_state_data->data = NULL;
797 stateKey.state_data = this_state_data;
798
799 if (_np_state_read_file(statefile, stateKey)) {
800 this_state_data->errorcode = OK;
801 } else {
802 this_state_data->errorcode = ERROR;
803 }
804
805 fclose(statefile);
806 } else {
807 // Failed to open state file
808 this_state_data->errorcode = ERROR;
809 }
810
811 return stateKey.state_data;
812}
813
814/*
815 * Internal function. Returns either:
816 * envvar NAGIOS_PLUGIN_STATE_DIRECTORY
817 * statically compiled shared state directory
818 */
819char *_np_state_calculate_location_prefix(void) {
820 char *env_dir;
821
822 /* Do not allow passing MP_STATE_PATH in setuid plugins
823 * for security reasons */
824 if (!mp_suid()) {
825 env_dir = getenv("MP_STATE_PATH");
826 if (env_dir && env_dir[0] != '\0') {
827 return env_dir;
828 }
829 /* This is the former ENV, for backward-compatibility */
830 env_dir = getenv("NAGIOS_PLUGIN_STATE_DIRECTORY");
831 if (env_dir && env_dir[0] != '\0') {
832 return env_dir;
833 }
834 }
835
836 return NP_STATE_DIR_PREFIX;
837}
838
839/*
840 * Initiatializer for state routines.
841 * Sets variables. Generates filename. Returns np_state_key. die with
842 * UNKNOWN if exception
843 */
844state_key np_enable_state(char *keyname, int expected_data_version, char *plugin_name, int argc,
845 char **argv) {
846 state_key *this_state = (state_key *)calloc(1, sizeof(state_key));
847 if (this_state == NULL) {
848 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
849 }
850
851 char *temp_keyname = NULL;
852 if (keyname == NULL) {
853 temp_keyname = _np_state_generate_key(argc, argv);
854 } else {
855 temp_keyname = strdup(keyname);
856 if (temp_keyname == NULL) {
857 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
858 }
859 }
860
861 /* Die if invalid characters used for keyname */
862 char *tmp_char = temp_keyname;
863 while (*tmp_char != '\0') {
864 if (!(isalnum(*tmp_char) || *tmp_char == '_')) {
865 die(STATE_UNKNOWN, _("Invalid character for keyname - only alphanumerics or '_'"));
866 }
867 tmp_char++;
868 }
869 this_state->name = temp_keyname;
870 this_state->plugin_name = plugin_name;
871 this_state->data_version = expected_data_version;
872 this_state->state_data = NULL;
873
874 /* Calculate filename */
875 char *temp_filename = NULL;
876 int error = asprintf(&temp_filename, "%s/%lu/%s/%s", _np_state_calculate_location_prefix(),
877 (unsigned long)geteuid(), plugin_name, this_state->name);
878 if (error < 0) {
879 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
880 }
881
882 this_state->_filename = temp_filename;
883
884 return *this_state;
885}
886
887/*
888 * Returns a string to use as a keyname, based on an md5 hash of argv, thus
889 * hopefully a unique key per service/plugin invocation. Use the extra-opts
890 * parse of argv, so that uniqueness in parameters are reflected there.
891 */
892char *_np_state_generate_key(int argc, char **argv) {
893 unsigned char result[256];
894
895#ifdef USE_OPENSSL
896 /*
897 * This code path is chosen if openssl is available (which should be the most common
898 * scenario). Alternatively, the gnulib implementation/
899 *
900 */
901 EVP_MD_CTX *ctx = EVP_MD_CTX_new();
902
903 EVP_DigestInit(ctx, EVP_sha256());
904
905 for (int i = 0; i < argc; i++) {
906 EVP_DigestUpdate(ctx, argv[i], strlen(argv[i]));
907 }
908
909 EVP_DigestFinal(ctx, result, NULL);
910#else
911
912 struct sha256_ctx ctx;
913
914 for (int i = 0; i < this_monitoring_plugin->argc; i++) {
915 sha256_process_bytes(argv[i], strlen(argv[i]), &ctx);
916 }
917
918 sha256_finish_ctx(&ctx, result);
919#endif // FOUNDOPENSSL
920
921 char keyname[41];
922 for (int i = 0; i < 20; ++i) {
923 sprintf(&keyname[2 * i], "%02x", result[i]);
924 }
925
926 keyname[40] = '\0';
927
928 char *keyname_copy = strdup(keyname);
929 if (keyname_copy == NULL) {
930 die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
931 }
932
933 return keyname_copy;
934}
diff --git a/plugins/check_snmp.d/check_snmp_helpers.h b/plugins/check_snmp.d/check_snmp_helpers.h
new file mode 100644
index 00000000..0f7780b1
--- /dev/null
+++ b/plugins/check_snmp.d/check_snmp_helpers.h
@@ -0,0 +1,71 @@
1#pragma once
2
3#include "./config.h"
4#include <net-snmp/library/asn1.h>
5
6check_snmp_test_unit check_snmp_test_unit_init();
7int check_snmp_set_thresholds(const char *, check_snmp_test_unit[], size_t, bool);
8check_snmp_config check_snmp_config_init();
9
10typedef struct {
11 oid oid[MAX_OID_LEN];
12 size_t oid_length;
13 unsigned char type;
14 union {
15 uint64_t uIntVal;
16 int64_t intVal;
17 double doubleVal;
18 } value;
19 char *string_response;
20} response_value;
21
22typedef struct {
23 int errorcode;
24 response_value *response_values;
25} snmp_responces;
26snmp_responces do_snmp_query(check_snmp_config_snmp_parameters parameters);
27
28// state is similar to response, but only numerics and a timestamp
29typedef struct {
30 time_t timestamp;
31 oid oid[MAX_OID_LEN];
32 size_t oid_length;
33 unsigned char type;
34 union {
35 unsigned long long uIntVal;
36 long long intVal;
37 double doubleVal;
38 } value;
39} check_snmp_state_entry;
40
41typedef struct {
42 check_snmp_state_entry state;
43 mp_subcheck sc;
44} check_snmp_evaluation;
45check_snmp_evaluation evaluate_single_unit(response_value response,
46 check_snmp_evaluation_parameters eval_params,
47 check_snmp_test_unit test_unit, time_t query_timestamp,
48 check_snmp_state_entry prev_state,
49 bool have_previous_state);
50
51#define NP_STATE_FORMAT_VERSION 1
52
53typedef struct state_data_struct {
54 time_t time;
55 void *data;
56 size_t length; /* Of binary data */
57 int errorcode;
58} state_data;
59
60typedef struct state_key_struct {
61 char *name;
62 char *plugin_name;
63 int data_version;
64 char *_filename;
65 state_data *state_data;
66} state_key;
67
68state_data *np_state_read(state_key stateKey);
69state_key np_enable_state(char *keyname, int expected_data_version, char *plugin_name, int argc,
70 char **argv);
71void np_state_write_string(state_key stateKey, time_t timestamp, char *stringToStore);
diff --git a/plugins/check_snmp.d/config.h b/plugins/check_snmp.d/config.h
new file mode 100644
index 00000000..e7b6d1b3
--- /dev/null
+++ b/plugins/check_snmp.d/config.h
@@ -0,0 +1,81 @@
1#pragma once
2
3#include "../../lib/thresholds.h"
4#include "../../lib/states.h"
5#include <stdlib.h>
6#include <stdbool.h>
7#include <regex.h>
8#include "../common.h"
9
10// defines for snmp libs
11#define u_char unsigned char
12#define u_long unsigned long
13#define u_short unsigned short
14#define u_int unsigned int
15
16#include <net-snmp/net-snmp-config.h>
17#include <net-snmp/net-snmp-includes.h>
18#include <net-snmp/library/snmp.h>
19#include <net-snmp/session_api.h>
20
21#define DEFAULT_PORT "161"
22#define DEFAULT_RETRIES 5
23
24typedef struct eval_method {
25 bool crit_string;
26 bool crit_regex;
27} eval_method;
28
29typedef struct check_snmp_test_unit {
30 char *oid;
31 char *label;
32 char *unit_value;
33 eval_method eval_mthd;
34 mp_thresholds threshold;
35} check_snmp_test_unit;
36
37typedef struct {
38 struct snmp_session snmp_session;
39 // use getnet instead of get
40 bool use_getnext;
41
42 // TODO actually make these useful
43 bool ignore_mib_parsing_errors;
44 bool need_mibs;
45
46 check_snmp_test_unit *test_units;
47 size_t num_of_test_units;
48} check_snmp_config_snmp_parameters;
49
50typedef struct {
51 // State if an empty value is encountered
52 mp_state_enum nulloid_result;
53
54 // String evaluation stuff
55 bool invert_search;
56 regex_t regex_cmp_value; // regex to match query results against
57 char string_cmp_value[MAX_INPUT_BUFFER];
58
59 // Modify data
60 double multiplier;
61 bool multiplier_set;
62 double offset;
63 bool offset_set;
64
65 // Modify output
66 bool use_oid_as_perf_data_label;
67
68 // activate rate calculation
69 bool calculate_rate;
70 unsigned int rate_multiplier;
71} check_snmp_evaluation_parameters;
72
73typedef struct check_snmp_config {
74 // SNMP session to use
75 check_snmp_config_snmp_parameters snmp_params;
76
77 check_snmp_evaluation_parameters evaluation_params;
78
79 mp_output_format output_format;
80 bool output_format_is_set;
81} check_snmp_config;
diff --git a/plugins/check_ssh.c b/plugins/check_ssh.c
index 34ef37b7..f6c8d551 100644
--- a/plugins/check_ssh.c
+++ b/plugins/check_ssh.c
@@ -1,103 +1,107 @@
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,
61main (int argc, char **argv) 61 char *remote_protocol);
62{
63 int result = STATE_UNKNOWN;
64 62
65 setlocale (LC_ALL, ""); 63int main(int argc, char **argv) {
66 bindtextdomain (PACKAGE, LOCALEDIR); 64 setlocale(LC_ALL, "");
67 textdomain (PACKAGE); 65 bindtextdomain(PACKAGE, LOCALEDIR);
66 textdomain(PACKAGE);
68 67
69 /* Parse extra opts if any */ 68 /* Parse extra opts if any */
70 argv=np_extra_opts (&argc, argv, progname); 69 argv = np_extra_opts(&argc, argv, progname);
71 70
72 if (process_arguments (argc, argv) == ERROR) 71 process_arguments_wrapper tmp_config = process_arguments(argc, argv);
73 usage4 (_("Could not parse arguments"));
74 72
75 /* initialize alarm signal handling */ 73 if (tmp_config.errorcode == ERROR) {
76 signal (SIGALRM, socket_timeout_alarm_handler); 74 usage4(_("Could not parse arguments"));
75 }
77 76
78 alarm (socket_timeout); 77 check_ssh_config config = tmp_config.config;
78
79 mp_check overall = mp_check_init();
80 if (config.output_format_is_set) {
81 mp_set_format(config.output_format);
82 }
83
84 /* initialize alarm signal handling */
85 signal(SIGALRM, socket_timeout_alarm_handler);
86 alarm(socket_timeout);
79 87
80 /* ssh_connect exits if error is found */ 88 /* ssh_connect exits if error is found */
81 result = ssh_connect (server_name, port, remote_version, remote_protocol); 89 ssh_connect(&overall, config.server_name, config.port, config.remote_version,
90 config.remote_protocol);
82 91
83 alarm (0); 92 alarm(0);
84 93
85 return (result); 94 mp_exit(overall);
86} 95}
87 96
88 97#define output_format_index CHAR_MAX + 1
89 98
90/* process command-line arguments */ 99/* process command-line arguments */
91int 100process_arguments_wrapper process_arguments(int argc, char **argv) {
92process_arguments (int argc, char **argv)
93{
94 int c;
95
96 int option = 0;
97 static struct option longopts[] = { 101 static struct option longopts[] = {
98 {"help", no_argument, 0, 'h'}, 102 {"help", no_argument, 0, 'h'},
99 {"version", no_argument, 0, 'V'}, 103 {"version", no_argument, 0, 'V'},
100 {"host", required_argument, 0, 'H'}, /* backward compatibility */ 104 {"host", required_argument, 0, 'H'}, /* backward compatibility */
101 {"hostname", required_argument, 0, 'H'}, 105 {"hostname", required_argument, 0, 'H'},
102 {"port", required_argument, 0, 'p'}, 106 {"port", required_argument, 0, 'p'},
103 {"use-ipv4", no_argument, 0, '4'}, 107 {"use-ipv4", no_argument, 0, '4'},
@@ -106,39 +110,52 @@ process_arguments (int argc, char **argv)
106 {"verbose", no_argument, 0, 'v'}, 110 {"verbose", no_argument, 0, 'v'},
107 {"remote-version", required_argument, 0, 'r'}, 111 {"remote-version", required_argument, 0, 'r'},
108 {"remote-protocol", required_argument, 0, 'P'}, 112 {"remote-protocol", required_argument, 0, 'P'},
109 {0, 0, 0, 0} 113 {"output-format", required_argument, 0, output_format_index},
114 {0, 0, 0, 0}};
115
116 process_arguments_wrapper result = {
117 .config = check_ssh_config_init(),
118 .errorcode = OK,
110 }; 119 };
111 120
112 if (argc < 2) 121 if (argc < 2) {
113 return ERROR; 122 result.errorcode = ERROR;
123 return result;
124 }
114 125
115 for (c = 1; c < argc; c++) 126 for (int i = 1; i < argc; i++) {
116 if (strcmp ("-to", argv[c]) == 0) 127 if (strcmp("-to", argv[i]) == 0) {
117 strcpy (argv[c], "-t"); 128 strcpy(argv[i], "-t");
129 }
130 }
118 131
119 while (1) { 132 int option_char;
120 c = getopt_long (argc, argv, "+Vhv46t:r:H:p:P:", longopts, &option); 133 while (true) {
134 int option = 0;
135 option_char = getopt_long(argc, argv, "+Vhv46t:r:H:p:P:", longopts, &option);
121 136
122 if (c == -1 || c == EOF) 137 if (option_char == -1 || option_char == EOF) {
123 break; 138 break;
139 }
124 140
125 switch (c) { 141 switch (option_char) {
126 case '?': /* help */ 142 case '?': /* help */
127 usage5 (); 143 usage5();
128 case 'V': /* version */ 144 case 'V': /* version */
129 print_revision (progname, NP_VERSION); 145 print_revision(progname, NP_VERSION);
130 exit (STATE_UNKNOWN); 146 exit(STATE_UNKNOWN);
131 case 'h': /* help */ 147 case 'h': /* help */
132 print_help (); 148 print_help();
133 exit (STATE_UNKNOWN); 149 exit(STATE_UNKNOWN);
134 case 'v': /* verbose */ 150 case 'v': /* verbose */
135 verbose = true; 151 verbose = true;
136 break; 152 break;
137 case 't': /* timeout period */ 153 case 't': /* timeout period */
138 if (!is_integer (optarg)) 154 if (!is_intpos(optarg)) {
139 usage2 (_("Timeout interval must be a positive integer"), optarg); 155 usage2(_("Timeout interval must be a positive integer"), optarg);
140 else 156 } else {
141 socket_timeout = atoi (optarg); 157 socket_timeout = (unsigned int)atoi(optarg);
158 }
142 break; 159 break;
143 case '4': 160 case '4':
144 address_family = AF_INET; 161 address_family = AF_INET;
@@ -147,139 +164,153 @@ process_arguments (int argc, char **argv)
147#ifdef USE_IPV6 164#ifdef USE_IPV6
148 address_family = AF_INET6; 165 address_family = AF_INET6;
149#else 166#else
150 usage4 (_("IPv6 support not available")); 167 usage4(_("IPv6 support not available"));
151#endif 168#endif
152 break; 169 break;
153 case 'r': /* remote version */ 170 case 'r': /* remote version */
154 remote_version = optarg; 171 result.config.remote_version = optarg;
155 break; 172 break;
156 case 'P': /* remote version */ 173 case 'P': /* remote version */
157 remote_protocol = optarg; 174 result.config.remote_protocol = optarg;
158 break; 175 break;
159 case 'H': /* host */ 176 case 'H': /* host */
160 if (!is_host (optarg)) 177 if (!is_host(optarg)) {
161 usage2 (_("Invalid hostname/address"), optarg); 178 usage2(_("Invalid hostname/address"), optarg);
162 server_name = optarg; 179 }
180 result.config.server_name = optarg;
163 break; 181 break;
164 case 'p': /* port */ 182 case 'p': /* port */
165 if (is_intpos (optarg)) { 183 if (is_intpos(optarg)) {
166 port = atoi (optarg); 184 result.config.port = atoi(optarg);
185 } else {
186 usage2(_("Port number must be a positive integer"), optarg);
167 } 187 }
168 else { 188 break;
169 usage2 (_("Port number must be a positive integer"), optarg); 189 case output_format_index: {
190 parsed_output_format parser = mp_parse_output_format(optarg);
191 if (!parser.parsing_success) {
192 // TODO List all available formats here, maybe add anothoer usage function
193 printf("Invalid output format: %s\n", optarg);
194 exit(STATE_UNKNOWN);
170 } 195 }
196
197 result.config.output_format_is_set = true;
198 result.config.output_format = parser.output_format;
199 break;
200 }
171 } 201 }
172 } 202 }
173 203
174 c = optind; 204 option_char = optind;
175 if (server_name == NULL && c < argc) { 205 if (result.config.server_name == NULL && option_char < argc) {
176 if (is_host (argv[c])) { 206 if (is_host(argv[option_char])) {
177 server_name = argv[c++]; 207 result.config.server_name = argv[option_char++];
178 } 208 }
179 } 209 }
180 210
181 if (port == -1 && c < argc) { 211 if (result.config.port == -1 && option_char < argc) {
182 if (is_intpos (argv[c])) { 212 if (is_intpos(argv[option_char])) {
183 port = atoi (argv[c++]); 213 result.config.port = atoi(argv[option_char++]);
184 } 214 } else {
185 else { 215 print_usage();
186 print_usage (); 216 exit(STATE_UNKNOWN);
187 exit (STATE_UNKNOWN);
188 } 217 }
189 } 218 }
190 219
191 return validate_arguments (); 220 if (result.config.server_name == NULL) {
192} 221 result.errorcode = ERROR;
222 return result;
223 }
193 224
194int 225 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} 226}
203 227
204
205/************************************************************************ 228/************************************************************************
206* 229 *
207* Try to connect to SSH server at specified server and port 230 * Try to connect to SSH server at specified server and port
208* 231 *
209*-----------------------------------------------------------------------*/ 232 *-----------------------------------------------------------------------*/
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 233
234int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_version,
235 char *desired_remote_protocol) {
236 struct timeval tv;
227 gettimeofday(&tv, NULL); 237 gettimeofday(&tv, NULL);
228 238
229 result = my_tcp_connect (haddr, hport, &sd); 239 int socket;
240 int result = my_tcp_connect(haddr, hport, &socket);
230 241
231 if (result != STATE_OK) 242 mp_subcheck connection_sc = mp_subcheck_init();
243 if (result != STATE_OK) {
244 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL);
245 xasprintf(&connection_sc.output,
246 "Failed to establish TCP connection to Host %s and Port %d", haddr, hport);
247 mp_add_subcheck_to_check(overall, connection_sc);
232 return result; 248 return result;
249 }
233 250
234 char *output = (char *) calloc (BUFF_SZ + 1, sizeof(char)); 251 char *output = (char *)calloc(BUFF_SZ + 1, sizeof(char));
235 252 char *buffer = NULL;
236 unsigned int iteration = 0; 253 ssize_t recv_ret = 0;
237 ssize_t byte_offset = 0; 254 char *version_control_string = NULL;
238 255 size_t byte_offset = 0;
239 while ((version_control_string == NULL) && (recv_ret = recv(sd, output+byte_offset, BUFF_SZ - byte_offset, 0) > 0)) { 256 while ((version_control_string == NULL) &&
257 (recv_ret = recv(socket, output + byte_offset, (unsigned long)(BUFF_SZ - byte_offset),
258 0) > 0)) {
240 259
241 if (strchr(output, '\n')) { /* we've got at least one full line, start parsing*/ 260 if (strchr(output, '\n')) { /* we've got at least one full line, start parsing*/
242 byte_offset = 0; 261 byte_offset = 0;
243 262
244 char *index = NULL; 263 char *index = NULL;
245 while ((index = strchr(output+byte_offset, '\n')) != NULL) { 264 while ((index = strchr(output + byte_offset, '\n')) != NULL) {
246 /*Partition the buffer so that this line is a separate string, 265 /*Partition the buffer so that this line is a separate string,
247 * by replacing the newline with NUL*/ 266 * by replacing the newline with NUL*/
248 output[(index - output)] = '\0'; 267 output[(index - output)] = '\0';
249 len = strlen(output + byte_offset); 268 size_t len = strlen(output + byte_offset);
250 269
251 if ((len >= 4) && (strncmp (output+byte_offset, "SSH-", 4) == 0)) { 270 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*/ 271 /*if the string starts with SSH-, this _should_ be a valid version control
253 version_control_string = output+byte_offset; 272 * string*/
254 break; 273 version_control_string = output + byte_offset;
274 break;
255 } 275 }
256 276
257 /*the start of the next line (if one exists) will be after the current one (+ NUL)*/ 277 /*the start of the next line (if one exists) will be after the current one (+ NUL)*/
258 byte_offset += (len + 1); 278 byte_offset += (len + 1);
259 } 279 }
260 280
261 if(version_control_string == NULL) { 281 if (version_control_string == NULL) {
262 /* move unconsumed data to beginning of buffer, null rest */ 282 /* move unconsumed data to beginning of buffer */
263 memmove((void *)output, (void *)output+byte_offset+1, BUFF_SZ - len+1); 283 memmove((void *)output, (void *)(output + byte_offset), BUFF_SZ - byte_offset);
264 memset(output+byte_offset+1, 0, BUFF_SZ-byte_offset+1);
265 284
266 /*start reading from end of current line chunk on next recv*/ 285 /*start reading from end of current line chunk on next recv*/
267 byte_offset = strlen(output); 286 byte_offset = strlen(output);
287
288 /* NUL the rest of the buffer */
289 memset(output + byte_offset, 0, BUFF_SZ - byte_offset);
268 } 290 }
269 } else { 291 } else {
270 byte_offset += recv_ret; 292 byte_offset += (size_t)recv_ret;
271 } 293 }
272 } 294 }
273 295
274 if (recv_ret < 0) { 296 if (recv_ret < 0) {
275 printf("SSH CRITICAL - %s", strerror(errno)); 297 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL);
276 exit(STATE_CRITICAL); 298 xasprintf(&connection_sc.output, "%s - %s", "SSH CRITICAL - ", strerror(errno));
299 mp_add_subcheck_to_check(overall, connection_sc);
300 return OK;
277 } 301 }
278 302
279 if (version_control_string == NULL) { 303 if (version_control_string == NULL) {
280 printf("SSH CRITICAL - No version control string received"); 304 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL);
281 exit(STATE_CRITICAL); 305 xasprintf(&connection_sc.output, "%s", "SSH CRITICAL - No version control string received");
306 mp_add_subcheck_to_check(overall, connection_sc);
307 return OK;
282 } 308 }
309
310 connection_sc = mp_set_subcheck_state(connection_sc, STATE_OK);
311 xasprintf(&connection_sc.output, "%s", "Initial connection succeeded");
312 mp_add_subcheck_to_check(overall, connection_sc);
313
283 /* 314 /*
284 * "When the connection has been established, both sides MUST send an 315 * "When the connection has been established, both sides MUST send an
285 * identification string. This identification string MUST be 316 * identification string. This identification string MUST be
@@ -287,10 +318,12 @@ ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol
287 * SSH-protoversion-softwareversion SP comments CR LF" 318 * SSH-protoversion-softwareversion SP comments CR LF"
288 * - RFC 4253:4.2 319 * - RFC 4253:4.2
289 */ 320 */
290 strip (version_control_string); 321 strip(version_control_string);
291 if (verbose) 322 if (verbose) {
292 printf ("%s\n", version_control_string); 323 printf("%s\n", version_control_string);
293 ssh_proto = version_control_string + 4; 324 }
325
326 char *ssh_proto = version_control_string + 4;
294 327
295 /* 328 /*
296 * We assume the protoversion is of the form Major.Minor, although 329 * We assume the protoversion is of the form Major.Minor, although
@@ -308,7 +341,8 @@ ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol
308 * "1.x" (e.g., "1.5" or "1.3")." 341 * "1.x" (e.g., "1.5" or "1.3")."
309 * - RFC 4253:5 342 * - RFC 4253:5
310 */ 343 */
311 ssh_server = ssh_proto + strspn (ssh_proto, "0123456789.") + 1; /* (+1 for the '-' separating protoversion from softwareversion) */ 344 char *ssh_server = ssh_proto + strspn(ssh_proto, "0123456789.") +
345 1; /* (+1 for the '-' separating protoversion from softwareversion) */
312 346
313 /* If there's a space in the version string, whatever's after the space is a comment 347 /* If there's a space in the version string, whatever's after the space is a comment
314 * (which is NOT part of the server name/version)*/ 348 * (which is NOT part of the server name/version)*/
@@ -316,88 +350,105 @@ ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol
316 if (tmp) { 350 if (tmp) {
317 ssh_server[tmp - ssh_server] = '\0'; 351 ssh_server[tmp - ssh_server] = '\0';
318 } 352 }
353
354 mp_subcheck protocol_validity_sc = mp_subcheck_init();
319 if (strlen(ssh_proto) == 0 || strlen(ssh_server) == 0) { 355 if (strlen(ssh_proto) == 0 || strlen(ssh_server) == 0) {
320 printf(_("SSH CRITICAL - Invalid protocol version control string %s\n"), version_control_string); 356 protocol_validity_sc = mp_set_subcheck_state(protocol_validity_sc, STATE_CRITICAL);
321 exit (STATE_CRITICAL); 357 xasprintf(&protocol_validity_sc.output, "Invalid protocol version control string %s",
358 version_control_string);
359 mp_add_subcheck_to_check(overall, protocol_validity_sc);
360 return OK;
322 } 361 }
323 ssh_proto[strspn (ssh_proto, "0123456789. ")] = 0; 362
324 363 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); 364 xasprintf(&protocol_validity_sc.output, "Valid protocol version control string %s",
326 send (sd, buffer, strlen (buffer), MSG_DONTWAIT); 365 version_control_string);
327 if (verbose) 366 mp_add_subcheck_to_check(overall, protocol_validity_sc);
328 printf ("%s\n", buffer); 367
329 368 ssh_proto[strspn(ssh_proto, "0123456789. ")] = 0;
330 if (remote_version && strcmp(remote_version, ssh_server)) { 369
331 printf 370 static char *rev_no = VERSION;
332 (_("SSH CRITICAL - %s (protocol %s) version mismatch, expected '%s'\n"), 371 xasprintf(&buffer, "SSH-%s-check_ssh_%s\r\n", ssh_proto, rev_no);
333 ssh_server, ssh_proto, remote_version); 372 send(socket, buffer, strlen(buffer), MSG_DONTWAIT);
334 close(sd); 373 if (verbose) {
335 exit (STATE_CRITICAL); 374 printf("%s\n", buffer);
336 } 375 }
337 376
338 if (remote_protocol && strcmp(remote_protocol, ssh_proto)) { 377 if (desired_remote_version && strcmp(desired_remote_version, ssh_server)) {
339 printf 378 mp_subcheck remote_version_sc = mp_subcheck_init();
340 (_("SSH CRITICAL - %s (protocol %s) protocol version mismatch, expected '%s' | %s\n"), 379 remote_version_sc = mp_set_subcheck_state(remote_version_sc, STATE_CRITICAL);
341 ssh_server, ssh_proto, remote_protocol, fperfdata("time", elapsed_time, "s", 380 xasprintf(&remote_version_sc.output, _("%s (protocol %s) version mismatch, expected '%s'"),
342 false, 0, false, 0, true, 0, true, (int)socket_timeout)); 381 ssh_server, ssh_proto, desired_remote_version);
343 close(sd); 382 close(socket);
344 exit (STATE_CRITICAL); 383 mp_add_subcheck_to_check(overall, remote_version_sc);
384 return OK;
345 } 385 }
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 386
387 double elapsed_time = (double)deltime(tv) / 1.0e6;
388 mp_perfdata time_pd = perfdata_init();
389 time_pd.value = mp_create_pd_value(elapsed_time);
390 time_pd.label = "time";
391 time_pd.max_present = true;
392 time_pd.max = mp_create_pd_value(socket_timeout);
393
394 mp_subcheck protocol_version_sc = mp_subcheck_init();
395 mp_add_perfdata_to_subcheck(&protocol_version_sc, time_pd);
396
397 if (desired_remote_protocol && strcmp(desired_remote_protocol, ssh_proto)) {
398 protocol_version_sc = mp_set_subcheck_state(protocol_version_sc, STATE_CRITICAL);
399 xasprintf(&protocol_version_sc.output,
400 _("%s (protocol %s) protocol version mismatch, expected '%s'"), ssh_server,
401 ssh_proto, desired_remote_protocol);
402 } else {
403 protocol_version_sc = mp_set_subcheck_state(protocol_version_sc, STATE_OK);
404 xasprintf(&protocol_version_sc.output, "SSH server version: %s (protocol version: %s)",
405 ssh_server, ssh_proto);
406 }
356 407
408 mp_add_subcheck_to_check(overall, protocol_version_sc);
409 close(socket);
410 return OK;
411}
357 412
358void 413void print_help(void) {
359print_help (void)
360{
361 char *myport; 414 char *myport;
362 xasprintf (&myport, "%d", SSH_DFL_PORT); 415 xasprintf(&myport, "%d", default_ssh_port);
363 416
364 print_revision (progname, NP_VERSION); 417 print_revision(progname, NP_VERSION);
365 418
366 printf ("Copyright (c) 1999 Remi Paulmier <remi@sinfomic.fr>\n"); 419 printf("Copyright (c) 1999 Remi Paulmier <remi@sinfomic.fr>\n");
367 printf (COPYRIGHT, copyright, email); 420 printf(COPYRIGHT, copyright, email);
368 421
369 printf ("%s\n", _("Try to connect to an SSH server at specified server and port")); 422 printf("%s\n", _("Try to connect to an SSH server at specified server and port"));
370 423
371 printf ("\n\n"); 424 printf("\n\n");
372 425
373 print_usage (); 426 print_usage();
374 427
375 printf (UT_HELP_VRSN); 428 printf(UT_HELP_VRSN);
376 printf (UT_EXTRA_OPTS); 429 printf(UT_EXTRA_OPTS);
377 430
378 printf (UT_HOST_PORT, 'p', myport); 431 printf(UT_HOST_PORT, 'p', myport);
379 432
380 printf (UT_IPv46); 433 printf(UT_IPv46);
381 434
382 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 435 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
383 436
384 printf (" %s\n", "-r, --remote-version=STRING"); 437 printf(" %s\n", "-r, --remote-version=STRING");
385 printf (" %s\n", _("Alert if string doesn't match expected server version (ex: OpenSSH_3.9p1)")); 438 printf(" %s\n",
439 _("Alert if string doesn't match expected server version (ex: OpenSSH_3.9p1)"));
386 440
387 printf (" %s\n", "-P, --remote-protocol=STRING"); 441 printf(" %s\n", "-P, --remote-protocol=STRING");
388 printf (" %s\n", _("Alert if protocol doesn't match expected protocol version (ex: 2.0)")); 442 printf(" %s\n", _("Alert if protocol doesn't match expected protocol version (ex: 2.0)"));
443 printf(UT_OUTPUT_FORMAT);
389 444
390 printf (UT_VERBOSE); 445 printf(UT_VERBOSE);
391 446
392 printf (UT_SUPPORT); 447 printf(UT_SUPPORT);
393} 448}
394 449
395 450void print_usage(void) {
396 451 printf("%s\n", _("Usage:"));
397void 452 printf("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] --hostname <host>\n",
398print_usage (void) 453 progname);
399{
400 printf ("%s\n", _("Usage:"));
401 printf ("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] <host>\n", progname);
402} 454}
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..dbf53a00 100644
--- a/plugins/check_swap.c
+++ b/plugins/check_swap.c
@@ -1,607 +1,415 @@
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))) ||
343 dskused_mb = (float) ent[i].se_inuse / conv_factor; 176 config.warn.value >= data.metrics.free) {
344 dskfree_mb = ( dsktotal_mb - dskused_mb ); 177 sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
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 } 178 }
353
354 total_swap_mb += dsktotal_mb;
355 free_swap_mb += dskfree_mb;
356 used_swap_mb += dskused_mb;
357 } 179 }
358 180
359 /* and clean up after ourselves */ 181 if (verbose > 1) {
360 free(ent); 182 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 } 183 }
374 184
375 result = max_state (result, check_swap(free_swap_mb, total_swap_mb)); 185 if (config.crit_is_set) {
376 printf (_("SWAP %s - %d%% free (%dMB out of %dMB) %s|"), 186 if ((config.crit.is_percentage && (percent_used >= (100 - (double)config.crit.value))) ||
377 state_text (result), 187 config.crit.value >= data.metrics.free) {
378 (100 - percent_used), (int) free_swap_mb, (int) total_swap_mb, status); 188 sc1 = mp_set_subcheck_state(sc1, STATE_CRITICAL);
189 }
190 }
379 191
380 uint64_t warn_print = warn.value; 192 xasprintf(&sc1.output, _("%g%% free (%lluMiB out of %lluMiB)"), (100 - percent_used),
381 if (warn.is_percentage) warn_print = warn.value * (total_swap_mb *1024 *1024/100); 193 data.metrics.free >> 20, 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 194
385 puts (perfdata_uint64 ("swap", free_swap_mb *1024 *1024, "B", 195 overall.summary = "Swap";
386 true, warn_print, 196 mp_add_subcheck_to_check(&overall, sc1);
387 true, crit_print,
388 true, 0,
389 true, (long) total_swap_mb * 1024 * 1024));
390 197
391 return result; 198 mp_exit(overall);
392} 199}
393 200
201int check_swap(float free_swap_mb, float total_swap_mb, swap_config config) {
202 if (total_swap_mb == 0) {
203 return config.no_swap_state;
204 }
394 205
395int 206 uint64_t free_swap =
396check_swap(float free_swap_mb, float total_swap_mb) 207 (uint64_t)(free_swap_mb *
397{ 208 (1024 * 1024)); /* Convert back to bytes as warn and crit specified in bytes */
398
399 if (!total_swap_mb) return no_swap_state;
400 209
401 uint64_t free_swap = free_swap_mb * (1024 * 1024); /* Convert back to bytes as warn and crit specified in bytes */ 210 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; 211 return STATE_CRITICAL;
212 }
213 if (!config.warn.is_percentage && config.warn.value >= free_swap) {
214 return STATE_WARNING;
215 }
403 216
404 if (warn.value || crit.value) { /* Thresholds defined */ 217 uint64_t usage_percentage =
405 if (!crit.is_percentage && crit.value >= free_swap) return STATE_CRITICAL; 218 (uint64_t)((total_swap_mb - free_swap_mb) / total_swap_mb) * HUNDRED_PERCENT;
406 if (!warn.is_percentage && warn.value >= free_swap) return STATE_WARNING;
407 219
408 if (crit.is_percentage && 220 if (config.crit.is_percentage && config.crit.value != 0 &&
409 crit.value != 0 && 221 usage_percentage >= (HUNDRED_PERCENT - config.crit.value)) {
410 usage_percentage >= (100 - crit.value)) 222 return STATE_CRITICAL;
411 { 223 }
412 return STATE_CRITICAL;
413 }
414 224
415 if (warn.is_percentage && 225 if (config.warn.is_percentage && config.warn.value != 0 &&
416 warn.value != 0 && 226 usage_percentage >= (HUNDRED_PERCENT - config.warn.value)) {
417 usage_percentage >= (100 - warn.value)) 227 return STATE_WARNING;
418 { 228 }
419 return STATE_WARNING;
420 }
421 229
422 return STATE_OK; 230 return STATE_OK;
423 } else { /* Without thresholds */
424 return STATE_OK;
425 }
426} 231}
427 232
428 233#define output_format_index CHAR_MAX + 1
429 234
430/* process command-line arguments */ 235/* process command-line arguments */
431int 236swap_config_wrapper process_arguments(int argc, char **argv) {
432process_arguments (int argc, char **argv) 237 swap_config_wrapper conf_wrapper = {.errorcode = OK};
433{ 238 conf_wrapper.config = swap_config_init();
434 int c = 0; /* option character */ 239
435 240 static struct option longopts[] = {{"warning", required_argument, 0, 'w'},
436 int option = 0; 241 {"critical", required_argument, 0, 'c'},
437 static struct option longopts[] = { 242 {"allswaps", no_argument, 0, 'a'},
438 {"warning", required_argument, 0, 'w'}, 243 {"no-swap", required_argument, 0, 'n'},
439 {"critical", required_argument, 0, 'c'}, 244 {"verbose", no_argument, 0, 'v'},
440 {"allswaps", no_argument, 0, 'a'}, 245 {"version", no_argument, 0, 'V'},
441 {"no-swap", required_argument, 0, 'n'}, 246 {"help", no_argument, 0, 'h'},
442 {"verbose", no_argument, 0, 'v'}, 247 {"output-format", required_argument, 0, output_format_index},
443 {"version", no_argument, 0, 'V'}, 248 {0, 0, 0, 0}};
444 {"help", no_argument, 0, 'h'}, 249
445 {0, 0, 0, 0} 250 while (true) {
446 }; 251 int option = 0;
447 252 int option_char = getopt_long(argc, argv, "+?Vvhac:w:n:", longopts, &option);
448 while (1) { 253
449 c = getopt_long (argc, argv, "+?Vvhac:w:n:", longopts, &option); 254 if (option_char == -1 || option_char == EOF) {
450
451 if (c == -1 || c == EOF)
452 break; 255 break;
256 }
453 257
454 switch (c) { 258 switch (option_char) {
455 case 'w': /* warning size threshold */ 259 case 'w': /* warning size threshold */
456 { 260 {
457 /* 261 /*
458 * We expect either a positive integer value without a unit, which means 262 * 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 (%), 263 * 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 264 * percentage sign (%), which means the value must be with 0 and 100
461 */ 265 * and is relative to the total swap
462 size_t length; 266 */
463 length = strlen(optarg); 267 size_t length;
464 268 length = strlen(optarg);
465 if (optarg[length - 1] == '%') { 269 conf_wrapper.config.warn_is_set = true;
466 /* It's percentage */ 270
467 warn.is_percentage = true; 271 if (optarg[length - 1] == '%') {
468 optarg[length - 1] = '\0'; 272 /* It's percentage */
469 if (is_uint64(optarg, &warn.value)) { 273 conf_wrapper.config.warn.is_percentage = true;
470 if (warn.value > 100) { 274 optarg[length - 1] = '\0';
471 usage4 (_("Warning threshold percentage must be <= 100!")); 275 if (is_uint64(optarg, &conf_wrapper.config.warn.value)) {
472 } 276 if (conf_wrapper.config.warn.value > HUNDRED_PERCENT) {
473 } 277 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 } 278 }
483 } 279 }
280 break;
281 } /* It's Bytes */
282 conf_wrapper.config.warn.is_percentage = false;
283 if (is_uint64(optarg, &conf_wrapper.config.warn.value)) {
284 break;
484 } 285 }
286 usage4(_("Warning threshold be positive integer or "
287 "percentage!"));
288 }
485 case 'c': /* critical size threshold */ 289 case 'c': /* critical size threshold */
486 { 290 {
487 /* 291 /*
488 * We expect either a positive integer value without a unit, which means 292 * 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 (%), 293 * 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 294 * percentage sign (%), which means the value must be with 0 and 100
491 */ 295 * and is relative to the total swap
492 size_t length; 296 */
493 length = strlen(optarg); 297 size_t length;
494 298 length = strlen(optarg);
495 if (optarg[length - 1] == '%') { 299 conf_wrapper.config.crit_is_set = true;
496 /* It's percentage */ 300
497 crit.is_percentage = true; 301 if (optarg[length - 1] == '%') {
498 optarg[length - 1] = '\0'; 302 /* It's percentage */
499 if (is_uint64(optarg, &crit.value)) { 303 conf_wrapper.config.crit.is_percentage = true;
500 if (crit.value> 100) { 304 optarg[length - 1] = '\0';
501 usage4 (_("Critical threshold percentage must be <= 100!")); 305 if (is_uint64(optarg, &conf_wrapper.config.crit.value)) {
502 } 306 if (conf_wrapper.config.crit.value > HUNDRED_PERCENT) {
503 } 307 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 } 308 }
513 } 309 }
514 } 310 break;
515 case 'a': /* all swap */ 311 } /* It's Bytes */
516 allswaps = true; 312 conf_wrapper.config.crit.is_percentage = false;
313 if (is_uint64(optarg, &conf_wrapper.config.crit.value)) {
314 break;
315 }
316 usage4(_("Critical threshold be positive integer or "
317 "percentage!"));
318 }
319 case 'a': /* all swap */
320 conf_wrapper.config.allswaps = true;
517 break; 321 break;
518 case 'n': 322 case 'n':
519 if ((no_swap_state = mp_translate_state(optarg)) == ERROR) { 323 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).")); 324 usage4(_("no-swap result must be a valid state name (OK, "
325 "WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
521 } 326 }
522 break; 327 break;
523 case 'v': /* verbose */ 328 case 'v': /* verbose */
524 verbose++; 329 verbose++;
525 break; 330 break;
526 case 'V': /* version */ 331 case output_format_index: {
527 print_revision (progname, NP_VERSION); 332 parsed_output_format parser = mp_parse_output_format(optarg);
528 exit (STATE_UNKNOWN); 333 if (!parser.parsing_success) {
529 case 'h': /* help */ 334 // TODO List all available formats here, maybe add anothoer usage function
530 print_help (); 335 printf("Invalid output format: %s\n", optarg);
531 exit (STATE_UNKNOWN); 336 exit(STATE_UNKNOWN);
532 case '?': /* error */ 337 }
533 usage5 (); 338
339 conf_wrapper.config.output_format_is_set = true;
340 conf_wrapper.config.output_format = parser.output_format;
341 break;
342 }
343 case 'V': /* version */
344 print_revision(progname, NP_VERSION);
345 exit(STATE_UNKNOWN);
346 case 'h': /* help */
347 print_help(conf_wrapper.config);
348 exit(STATE_UNKNOWN);
349 case '?': /* error */
350 usage5();
534 } 351 }
535 } 352 }
536 353
537 c = optind; 354 if ((conf_wrapper.config.warn.is_percentage == conf_wrapper.config.crit.is_percentage) &&
538 if (c == argc) 355 (conf_wrapper.config.warn.value < conf_wrapper.config.crit.value)) {
539 return validate_arguments (); 356 /* This is NOT triggered if warn and crit are different units, e.g warn
540 357 * is percentage and crit is absolute. We cannot determine the condition
541 return validate_arguments (); 358 * 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 */ 359 */
554 usage4(_("Warning should be more than critical")); 360 usage4(_("Warning should be more than critical"));
555 } 361 }
556 return OK;
557}
558
559 362
560 363 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} 364}
599 365
366void print_help(swap_config config) {
367 print_revision(progname, NP_VERSION);
368
369 printf(_(COPYRIGHT), copyright, email);
370
371 printf("%s\n", _("Check swap space on local machine."));
372
373 printf("\n\n");
374
375 print_usage();
376
377 printf(UT_HELP_VRSN);
378 printf(UT_EXTRA_OPTS);
379
380 printf(" %s\n", "-w, --warning=INTEGER");
381 printf(" %s\n", _("Exit with WARNING status if less than INTEGER bytes "
382 "of swap space are free"));
383 printf(" %s\n", "-w, --warning=PERCENT%");
384 printf(" %s\n", _("Exit with WARNING status if less than PERCENT of "
385 "swap space is free"));
386 printf(" %s\n", "-c, --critical=INTEGER");
387 printf(" %s\n", _("Exit with CRITICAL status if less than INTEGER bytes "
388 "of swap space are free"));
389 printf(" %s\n", "-c, --critical=PERCENT%");
390 printf(" %s\n", _("Exit with CRITICAL status if less than PERCENT of "
391 "swap space is free"));
392 printf(" %s\n", "-a, --allswaps");
393 printf(" %s\n", _("Conduct comparisons for all swap partitions, one by one"));
394 printf(" %s\n", "-n, --no-swap=<ok|warning|critical|unknown>");
395 printf(" %s %s\n",
396 _("Resulting state when there is no swap regardless of thresholds. "
397 "Default:"),
398 state_text(config.no_swap_state));
399 printf(UT_OUTPUT_FORMAT);
400 printf(UT_VERBOSE);
401
402 printf("\n");
403 printf("%s\n", _("Notes:"));
404 printf(" %s\n", _("Both INTEGER and PERCENT thresholds can be specified, "
405 "they are all checked."));
406 printf(" %s\n", _("On AIX, if -a is specified, uses lsps -a, otherwise uses lsps -s."));
407
408 printf(UT_SUPPORT);
409}
600 410
601void 411void print_usage(void) {
602print_usage (void) 412 printf("%s\n", _("Usage:"));
603{ 413 printf(" %s [-av] -w <percent_free>%% -c <percent_free>%%\n", progname);
604 printf ("%s\n", _("Usage:")); 414 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} 415}
diff --git a/plugins/check_swap.d/check_swap.h b/plugins/check_swap.d/check_swap.h
new file mode 100644
index 00000000..8d3c7fcf
--- /dev/null
+++ b/plugins/check_swap.d/check_swap.h
@@ -0,0 +1,49 @@
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[],
47 const char swap_format[]);
48swap_result getSwapFromSwapctl_BSD(swap_config config);
49swap_result getSwapFromSwap_SRV4(swap_config config);
diff --git a/plugins/check_swap.d/swap.c b/plugins/check_swap.d/swap.c
new file mode 100644
index 00000000..58213a3c
--- /dev/null
+++ b/plugins/check_swap.d/swap.c
@@ -0,0 +1,471 @@
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(config);
56# else // CHECK_SWAP_SWAPCTL_SVR4
57# ifdef CHECK_SWAP_SWAPCTL_BSD
58 return getSwapFromSwapctl_BSD(config);
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,
99 &swap_free) == 3) {
100 found_total = true;
101 found_free = true;
102 // Set error
103 result.errorcode = STATE_OK;
104 // Break out of fgets here, since both scanf expressions might match (NetBSD for
105 // example)
106 break;
107 }
108
109 /*
110 * The following sscanf call looks for lines looking like:
111 * "SwapTotal: 123" and "SwapFree: 123" This format exists at least
112 * on Debian Linux with a 5.* kernel
113 */
114 unsigned long tmp_KB = 0;
115 int sscanf_result = sscanf(input_buffer,
116 "%*[S]%*[w]%*[a]%*[p]%[TotalFreCchd]%*[:] %lu "
117 "%*[k]%*[B]",
118 str, &tmp_KB);
119
120 if (sscanf_result == 2) {
121
122 if (verbose >= 3) {
123 printf("Got %s with %lu\n", str, tmp_KB);
124 }
125
126 /* I think this part is always in Kb, so convert to bytes */
127 if (strcmp("Total", str) == 0) {
128 swap_total = tmp_KB * 1000;
129 found_total = true;
130 } else if (strcmp("Free", str) == 0) {
131 swap_free += tmp_KB * 1000;
132 found_free = true;
133 } else if (strcmp("Cached", str) == 0) {
134 swap_free += tmp_KB * 1000;
135 }
136
137 result.errorcode = STATE_OK;
138 }
139 }
140
141 fclose(meminfo_file_ptr);
142
143 result.metrics.total = swap_total;
144 result.metrics.free = swap_free;
145 result.metrics.used = swap_total - swap_free;
146
147 if (!found_free || !found_total) {
148 result.errorcode = STATE_UNKNOWN;
149 }
150
151 return result;
152}
153
154swap_result getSwapFromSwapCommand(swap_config config, const char swap_command[],
155 const char swap_format[]) {
156 swap_result result = {0};
157
158 char *temp_buffer;
159
160 if (verbose >= 2) {
161 printf(_("Command: %s\n"), swap_command);
162 }
163 if (verbose >= 3) {
164 printf(_("Format: %s\n"), swap_format);
165 }
166
167 child_process = spopen(swap_command);
168 if (child_process == NULL) {
169 printf(_("Could not open pipe: %s\n"), swap_command);
170 swap_result tmp = {
171 .errorcode = STATE_UNKNOWN,
172 };
173 return tmp;
174 }
175
176 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
177 if (child_stderr == NULL) {
178 printf(_("Could not open stderr for %s\n"), swap_command);
179 }
180
181 char str[32] = {0};
182 char input_buffer[MAX_INPUT_BUFFER];
183
184 /* read 1st line */
185 fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process);
186 if (strcmp(swap_format, "") == 0) {
187 temp_buffer = strtok(input_buffer, " \n");
188 while (temp_buffer) {
189 if (strstr(temp_buffer, "blocks")) {
190 sprintf(str, "%s %s", str, "%lu");
191 } else if (strstr(temp_buffer, "dskfree")) {
192 sprintf(str, "%s %s", str, "%lu");
193 } else {
194 sprintf(str, "%s %s", str, "%*s");
195 }
196 temp_buffer = strtok(NULL, " \n");
197 }
198 }
199
200 double total_swap_mb = 0;
201 double free_swap_mb = 0;
202 double used_swap_mb = 0;
203 double dsktotal_mb = 0;
204 double dskused_mb = 0;
205 double dskfree_mb = 0;
206
207 /*
208 * If different swap command is used for summary switch, need to read format
209 * differently
210 */
211 if (config.on_aix && !config.allswaps) {
212 fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process); /* Ignore first line */
213 sscanf(input_buffer, swap_format, &total_swap_mb, &used_swap_mb);
214 free_swap_mb = total_swap_mb * (100 - used_swap_mb) / 100;
215 used_swap_mb = total_swap_mb - free_swap_mb;
216
217 if (verbose >= 3) {
218 printf(_("total=%.0f, used=%.0f, free=%.0f\n"), total_swap_mb, used_swap_mb,
219 free_swap_mb);
220 }
221 } else {
222 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
223 sscanf(input_buffer, swap_format, &dsktotal_mb, &dskfree_mb);
224
225 dsktotal_mb = dsktotal_mb / config.conversion_factor;
226 /* AIX lists percent used, so this converts to dskfree in MBs */
227
228 if (config.on_aix) {
229 dskfree_mb = dsktotal_mb * (100 - dskfree_mb) / 100;
230 } else {
231 dskfree_mb = dskfree_mb / config.conversion_factor;
232 }
233
234 if (verbose >= 3) {
235 printf(_("total=%.0f, free=%.0f\n"), dsktotal_mb, dskfree_mb);
236 }
237
238 dskused_mb = dsktotal_mb - dskfree_mb;
239 total_swap_mb += dsktotal_mb;
240 used_swap_mb += dskused_mb;
241 free_swap_mb += dskfree_mb;
242 }
243 }
244
245 result.metrics.free = free_swap_mb * 1024 * 1024;
246 result.metrics.used = used_swap_mb * 1024 * 1024;
247 result.metrics.total = free_swap_mb * 1024 * 1024;
248
249 /* If we get anything on STDERR, at least set warning */
250 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
251 result.statusCode = max_state(result.statusCode, STATE_WARNING);
252 // TODO Set error here
253 }
254
255 /* close stderr */
256 (void)fclose(child_stderr);
257
258 /* close the pipe */
259 if (spclose(child_process)) {
260 result.statusCode = max_state(result.statusCode, STATE_WARNING);
261 // TODO set error here
262 }
263
264 return result;
265}
266
267#ifndef CHECK_SWAP_SWAPCTL_BSD
268# define CHECK_SWAP_SWAPCTL_BSD
269
270// Stub functionality for BSD stuff, so the compiler always sees the following BSD code
271
272# define SWAP_NSWAP 0
273# define SWAP_STATS 1
274
275int bsd_swapctl(int cmd, const void *arg, int misc) {
276 (void)cmd;
277 (void)arg;
278 (void)misc;
279 return 512;
280}
281
282struct swapent {
283 dev_t se_dev; /* device id */
284 int se_flags; /* entry flags */
285 int se_nblks; /* total blocks */
286 int se_inuse; /* blocks in use */
287 int se_priority; /* priority */
288 char se_path[PATH_MAX]; /* path to entry */
289};
290
291#else
292
293// Includes for NetBSD
294# include <unistd.h>
295# include <sys/swap.h>
296
297# define bsd_swapctl swapctl
298
299#endif // CHECK_SWAP_SWAPCTL_BSD
300
301swap_result getSwapFromSwapctl_BSD(swap_config config) {
302 /* get the number of active swap devices */
303 int nswaps = bsd_swapctl(SWAP_NSWAP, NULL, 0);
304
305 /* initialize swap table + entries */
306 struct swapent *ent = (struct swapent *)malloc(sizeof(struct swapent) * (unsigned long)nswaps);
307
308 /* and now, tally 'em up */
309 int swapctl_res = bsd_swapctl(SWAP_STATS, ent, nswaps);
310 if (swapctl_res < 0) {
311 perror(_("swapctl failed: "));
312 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
313 }
314
315 double dsktotal_mb = 0.0;
316 double dskfree_mb = 0.0;
317 double dskused_mb = 0.0;
318 unsigned long long total_swap_mb = 0;
319 unsigned long long free_swap_mb = 0;
320 unsigned long long used_swap_mb = 0;
321
322 for (int i = 0; i < nswaps; i++) {
323 dsktotal_mb = (double)ent[i].se_nblks / (double)config.conversion_factor;
324 dskused_mb = (double)ent[i].se_inuse / (double)config.conversion_factor;
325 dskfree_mb = (dsktotal_mb - dskused_mb);
326
327 if (config.allswaps && dsktotal_mb > 0) {
328 double percent = 100 * (((double)dskused_mb) / ((double)dsktotal_mb));
329
330 if (verbose) {
331 printf("[%.0f (%g%%)]", dskfree_mb, 100 - percent);
332 }
333 }
334
335 total_swap_mb += (unsigned long long)dsktotal_mb;
336 free_swap_mb += (unsigned long long)dskfree_mb;
337 used_swap_mb += (unsigned long long)dskused_mb;
338 }
339
340 /* and clean up after ourselves */
341 free(ent);
342
343 swap_result result = {0};
344
345 result.statusCode = OK;
346 result.errorcode = OK;
347
348 result.metrics.total = total_swap_mb * 1024 * 1024;
349 result.metrics.free = free_swap_mb * 1024 * 1024;
350 result.metrics.used = used_swap_mb * 1024 * 1024;
351
352 return result;
353}
354
355#ifndef CHECK_SWAP_SWAPCTL_SVR4
356int srv4_swapctl(int cmd, void *arg) {
357 (void)cmd;
358 (void)arg;
359 return 512;
360}
361
362typedef struct srv4_swapent {
363 char *ste_path; /* name of the swap file */
364 off_t ste_start; /* starting block for swapping */
365 off_t ste_length; /* length of swap area */
366 long ste_pages; /* number of pages for swapping */
367 long ste_free; /* number of ste_pages free */
368 long ste_flags; /* ST_INDEL bit set if swap file */
369 /* is now being deleted */
370} swapent_t;
371
372typedef struct swaptbl {
373 int swt_n; /* number of swapents following */
374 struct srv4_swapent swt_ent[]; /* array of swt_n swapents */
375} swaptbl_t;
376
377# define SC_LIST 2
378# define SC_GETNSWP 3
379
380# ifndef MAXPATHLEN
381# define MAXPATHLEN 2048
382# endif
383
384#else
385# define srv4_swapctl swapctl
386#endif
387
388swap_result getSwapFromSwap_SRV4(swap_config config) {
389 int nswaps = 0;
390
391 /* get the number of active swap devices */
392 if ((nswaps = srv4_swapctl(SC_GETNSWP, NULL)) == -1) {
393 die(STATE_UNKNOWN, _("Error getting swap devices\n"));
394 }
395
396 if (nswaps == 0) {
397 die(STATE_OK, _("SWAP OK: No swap devices defined\n"));
398 }
399
400 if (verbose >= 3) {
401 printf("Found %d swap device(s)\n", nswaps);
402 }
403
404 /* initialize swap table + entries */
405 swaptbl_t *tbl =
406 (swaptbl_t *)malloc(sizeof(swaptbl_t) + (sizeof(swapent_t) * (unsigned long)nswaps));
407
408 if (tbl == NULL) {
409 die(STATE_UNKNOWN, _("malloc() failed!\n"));
410 }
411
412 memset(tbl, 0, sizeof(swaptbl_t) + (sizeof(swapent_t) * (unsigned long)nswaps));
413 tbl->swt_n = nswaps;
414
415 for (int i = 0; i < nswaps; i++) {
416 if ((tbl->swt_ent[i].ste_path = (char *)malloc(sizeof(char) * MAXPATHLEN)) == NULL) {
417 die(STATE_UNKNOWN, _("malloc() failed!\n"));
418 }
419 }
420
421 /* and now, tally 'em up */
422 int swapctl_res = srv4_swapctl(SC_LIST, tbl);
423 if (swapctl_res < 0) {
424 perror(_("swapctl failed: "));
425 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
426 }
427
428 double dsktotal_mb = 0.0;
429 double dskfree_mb = 0.0;
430 double dskused_mb = 0.0;
431 unsigned long long total_swap_mb = 0;
432 unsigned long long free_swap_mb = 0;
433 unsigned long long used_swap_mb = 0;
434
435 for (int i = 0; i < nswaps; i++) {
436 dsktotal_mb = (float)tbl->swt_ent[i].ste_pages / SWAP_CONVERSION;
437 dskfree_mb = (float)tbl->swt_ent[i].ste_free / SWAP_CONVERSION;
438 dskused_mb = (dsktotal_mb - dskfree_mb);
439
440 if (verbose >= 3) {
441 printf("dsktotal_mb=%.0f dskfree_mb=%.0f dskused_mb=%.0f\n", dsktotal_mb, dskfree_mb,
442 dskused_mb);
443 }
444
445 if (config.allswaps && dsktotal_mb > 0) {
446 double percent = 100 * (((double)dskused_mb) / ((double)dsktotal_mb));
447
448 if (verbose) {
449 printf("[%.0f (%g%%)]", dskfree_mb, 100 - percent);
450 }
451 }
452
453 total_swap_mb += (unsigned long long)dsktotal_mb;
454 free_swap_mb += (unsigned long long)dskfree_mb;
455 used_swap_mb += (unsigned long long)dskused_mb;
456 }
457
458 /* and clean up after ourselves */
459 for (int i = 0; i < nswaps; i++) {
460 free(tbl->swt_ent[i].ste_path);
461 }
462 free(tbl);
463
464 swap_result result = {0};
465 result.errorcode = OK;
466 result.metrics.total = total_swap_mb * 1024 * 1024;
467 result.metrics.free = free_swap_mb * 1024 * 1024;
468 result.metrics.used = used_swap_mb * 1024 * 1024;
469
470 return result;
471}
diff --git a/plugins/check_tcp.c b/plugins/check_tcp.c
index 01dd35eb..09806373 100644
--- a/plugins/check_tcp.c
+++ b/plugins/check_tcp.c
@@ -1,415 +1,496 @@
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*/,
99static size_t flags; 69 check_tcp_config /*config*/);
100 70void print_help(const char *service);
101int 71void print_usage(void);
102main (int argc, char **argv) 72
103{ 73int verbosity = 0;
104 int result = STATE_UNKNOWN; 74
105 char *status = NULL; 75static const int READ_TIMEOUT = 2;
106 struct timeval tv; 76
107 struct timeval timeout; 77const int MAXBUF = 1024;
108 int match = -1; 78
109 fd_set rfds; 79const int DEFAULT_FTP_PORT = 21;
110 80const int DEFAULT_POP_PORT = 110;
111 FD_ZERO(&rfds); 81const int DEFAULT_SPOP_PORT = 995;
112 82const int DEFAULT_SMTP_PORT = 25;
113 setlocale (LC_ALL, ""); 83const int DEFAULT_SSMTP_PORT = 465;
114 bindtextdomain (PACKAGE, LOCALEDIR); 84const int DEFAULT_IMAP_PORT = 143;
115 textdomain (PACKAGE); 85const int DEFAULT_SIMAP_PORT = 993;
86const int DEFAULT_XMPP_C2S_PORT = 5222;
87const int DEFAULT_NNTP_PORT = 119;
88const int DEFAULT_NNTPS_PORT = 563;
89const int DEFAULT_CLAMD_PORT = 3310;
90
91int main(int argc, char **argv) {
92 setlocale(LC_ALL, "");
93 bindtextdomain(PACKAGE, LOCALEDIR);
94 textdomain(PACKAGE);
116 95
117 /* determine program- and service-name quickly */ 96 /* determine program- and service-name quickly */
118 progname = strrchr(argv[0], '/'); 97 progname = strrchr(argv[0], '/');
119 if(progname != NULL) progname++; 98 if (progname != NULL) {
120 else progname = argv[0]; 99 progname++;
100 } else {
101 progname = argv[0];
102 }
103
104 // Initialize config here with values from above,
105 // might be changed by on disk config or cli commands
106 check_tcp_config config = check_tcp_config_init();
121 107
122 size_t prog_name_len = strlen(progname); 108 size_t prog_name_len = strlen(progname);
123 if(prog_name_len > 6 && !memcmp(progname, "check_", 6)) { 109 const size_t prefix_length = strlen("check_");
124 SERVICE = strdup(progname + 6); 110
125 for(size_t i = 0; i < prog_name_len - 6; i++) 111 if (prog_name_len <= prefix_length) {
126 SERVICE[i] = toupper(SERVICE[i]); 112 die(STATE_UNKNOWN, _("Weird progname"));
113 }
114
115 if (!memcmp(progname, "check_", prefix_length)) {
116 config.service = strdup(progname + prefix_length);
117 if (config.service == NULL) {
118 die(STATE_UNKNOWN, _("Allocation failed"));
119 }
120
121 for (size_t i = 0; i < prog_name_len - prefix_length; i++) {
122 config.service[i] = toupper(config.service[i]);
123 }
127 } 124 }
128 125
129 /* set up a reasonable buffer at first (will be realloc()'ed if 126 /* set up a reasonable buffer at first (will be realloc()'ed if
130 * user specifies other options) */ 127 * user specifies other options) */
131 server_expect = calloc(sizeof(char *), 2); 128 config.server_expect = calloc(2, sizeof(char *));
132 129
133 /* determine defaults for this service's protocol */ 130 if (config.server_expect == NULL) {
134 if (!strncmp(SERVICE, "UDP", 3)) { 131 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 } 132 }
152 else if (!strncmp(SERVICE, "IMAP", 4)) { 133
153 EXPECT = "* OK"; 134 /* determine defaults for this service's protocol */
154 QUIT = "a1 LOGOUT\r\n"; 135 if (!strncmp(config.service, "UDP", strlen("UDP"))) {
155 PORT = 143; 136 config.protocol = IPPROTO_UDP;
137 } else if (!strncmp(config.service, "FTP", strlen("FTP"))) {
138 config.server_expect[0] = "220";
139 config.quit = "QUIT\r\n";
140 config.server_port = DEFAULT_FTP_PORT;
141 } else if (!strncmp(config.service, "POP", strlen("POP")) ||
142 !strncmp(config.service, "POP3", strlen("POP3"))) {
143 config.server_expect[0] = "+OK";
144 config.quit = "QUIT\r\n";
145 config.server_port = DEFAULT_POP_PORT;
146 } else if (!strncmp(config.service, "SMTP", strlen("SMTP"))) {
147 config.server_expect[0] = "220";
148 config.quit = "QUIT\r\n";
149 config.server_port = DEFAULT_SMTP_PORT;
150 } else if (!strncmp(config.service, "IMAP", strlen("IMAP"))) {
151 config.server_expect[0] = "* OK";
152 config.quit = "a1 LOGOUT\r\n";
153 config.server_port = DEFAULT_IMAP_PORT;
156 } 154 }
157#ifdef HAVE_SSL 155#ifdef HAVE_SSL
158 else if (!strncmp(SERVICE, "SIMAP", 5)) { 156 else if (!strncmp(config.service, "SIMAP", strlen("SIMAP"))) {
159 EXPECT = "* OK"; 157 config.server_expect[0] = "* OK";
160 QUIT = "a1 LOGOUT\r\n"; 158 config.quit = "a1 LOGOUT\r\n";
161 flags |= FLAG_SSL; 159 config.use_tls = true;
162 PORT = 993; 160 config.server_port = DEFAULT_SIMAP_PORT;
163 } 161 } else if (!strncmp(config.service, "SPOP", strlen("SPOP"))) {
164 else if (!strncmp(SERVICE, "SPOP", 4)) { 162 config.server_expect[0] = "+OK";
165 EXPECT = "+OK"; 163 config.quit = "QUIT\r\n";
166 QUIT = "QUIT\r\n"; 164 config.use_tls = true;
167 flags |= FLAG_SSL; 165 config.server_port = DEFAULT_SPOP_PORT;
168 PORT = 995; 166 } else if (!strncmp(config.service, "SSMTP", strlen("SSMTP"))) {
169 } 167 config.server_expect[0] = "220";
170 else if (!strncmp(SERVICE, "SSMTP", 5)) { 168 config.quit = "QUIT\r\n";
171 EXPECT = "220"; 169 config.use_tls = true;
172 QUIT = "QUIT\r\n"; 170 config.server_port = DEFAULT_SSMTP_PORT;
173 flags |= FLAG_SSL; 171 } else if (!strncmp(config.service, "JABBER", strlen("JABBER"))) {
174 PORT = 465; 172 config.send = "<stream:stream to=\'host\' xmlns=\'jabber:client\' "
175 } 173 "xmlns:stream=\'http://etherx.jabber.org/streams\'>\n";
176 else if (!strncmp(SERVICE, "JABBER", 6)) { 174 config.server_expect[0] = "<?xml version=\'1.0\'";
177 SEND = "<stream:stream to=\'host\' xmlns=\'jabber:client\' xmlns:stream=\'http://etherx.jabber.org/streams\'>\n"; 175 config.quit = "</stream:stream>\n";
178 EXPECT = "<?xml version=\'1.0\'"; 176 config.hide_output = true;
179 QUIT = "</stream:stream>\n"; 177 config.server_port = DEFAULT_XMPP_C2S_PORT;
180 flags |= FLAG_HIDE_OUTPUT; 178 } else if (!strncmp(config.service, "NNTPS", strlen("NNTPS"))) {
181 PORT = 5222; 179 config.server_expect_count = 2;
182 } 180 config.server_expect[0] = "200";
183 else if (!strncmp (SERVICE, "NNTPS", 5)) { 181 config.server_expect[1] = "201";
184 server_expect_count = 2; 182 config.quit = "QUIT\r\n";
185 server_expect[0] = "200"; 183 config.use_tls = true;
186 server_expect[1] = "201"; 184 config.server_port = DEFAULT_NNTPS_PORT;
187 QUIT = "QUIT\r\n";
188 flags |= FLAG_SSL;
189 PORT = 563;
190 } 185 }
191#endif 186#endif
192 else if (!strncmp (SERVICE, "NNTP", 4)) { 187 else if (!strncmp(config.service, "NNTP", strlen("NNTP"))) {
193 server_expect_count = 2; 188 config.server_expect_count = 2;
194 server_expect = malloc(sizeof(char *) * server_expect_count); 189 char **tmp = realloc(config.server_expect, config.server_expect_count * sizeof(char *));
195 server_expect[0] = strdup("200"); 190 if (tmp == NULL) {
196 server_expect[1] = strdup("201"); 191 free(config.server_expect);
197 QUIT = "QUIT\r\n"; 192 die(STATE_UNKNOWN, _("Allocation failed"));
198 PORT = 119; 193 }
199 } 194 config.server_expect = tmp;
200 else if (!strncmp(SERVICE, "CLAMD", 5)) { 195
201 SEND = "PING"; 196 config.server_expect[0] = strdup("200");
202 EXPECT = "PONG"; 197 config.server_expect[1] = strdup("201");
203 QUIT = NULL; 198 config.quit = "QUIT\r\n";
204 PORT = 3310; 199 config.server_port = DEFAULT_NNTP_PORT;
200 } else if (!strncmp(config.service, "CLAMD", strlen("CLAMD"))) {
201 config.send = "PING";
202 config.server_expect[0] = "PONG";
203 config.quit = NULL;
204 config.server_port = DEFAULT_CLAMD_PORT;
205 } 205 }
206 /* fallthrough check, so it's supposed to use reverse matching */ 206 /* fallthrough check, so it's supposed to use reverse matching */
207 else if (strcmp (SERVICE, "TCP")) 207 else if (strcmp(config.service, "TCP")) {
208 usage (_("CRITICAL - Generic check_tcp called with unknown service\n")); 208 usage(_("CRITICAL - Generic check_tcp called with unknown service\n"));
209 209 }
210 server_address = "127.0.0.1";
211 server_port = PORT;
212 server_send = SEND;
213 server_quit = QUIT;
214 status = NULL;
215 210
216 /* Parse extra opts if any */ 211 /* Parse extra opts if any */
217 argv=np_extra_opts (&argc, argv, progname); 212 argv = np_extra_opts(&argc, argv, progname);
213
214 check_tcp_config_wrapper paw = process_arguments(argc, argv, config);
215 if (paw.errorcode == ERROR) {
216 usage4(_("Could not parse arguments"));
217 }
218 218
219 if (process_arguments (argc, argv) == ERROR) 219 config = paw.config;
220 usage4 (_("Could not parse arguments"));
221 220
222 if(flags & FLAG_VERBOSE) { 221 if (verbosity > 0) {
223 printf("Using service %s\n", SERVICE); 222 printf("Using service %s\n", config.service);
224 printf("Port: %d\n", server_port); 223 printf("Port: %d\n", config.server_port);
225 printf("flags: 0x%x\n", (int)flags);
226 } 224 }
227 225
228 if(EXPECT && !server_expect_count) 226 if ((config.server_expect_count == 0) && config.server_expect[0]) {
229 server_expect_count++; 227 config.server_expect_count++;
228 }
230 229
231 if(PROTOCOL==IPPROTO_UDP && !(server_expect_count && server_send)){ 230 if (config.protocol == IPPROTO_UDP && !(config.server_expect_count && config.send)) {
232 usage(_("With UDP checks, a send/expect string must be specified.")); 231 usage(_("With UDP checks, a send/expect string must be specified."));
233 } 232 }
234 233
234 // Initialize check stuff before setting timers
235 mp_check overall = mp_check_init();
236 if (config.output_format_set) {
237 mp_set_format(config.output_format);
238 }
239
235 /* set up the timer */ 240 /* set up the timer */
236 signal (SIGALRM, socket_timeout_alarm_handler); 241 signal(SIGALRM, socket_timeout_alarm_handler);
237 alarm (socket_timeout); 242 alarm(socket_timeout);
238 243
239 /* try to connect to the host at the given port number */ 244 /* try to connect to the host at the given port number */
240 gettimeofday (&tv, NULL); 245 struct timeval start_time;
241 246 gettimeofday(&start_time, NULL);
242 result = np_net_connect (server_address, server_port, &sd, PROTOCOL); 247
243 if (result == STATE_CRITICAL) return econn_refuse_state; 248 int socket_descriptor = 0;
249 mp_subcheck inital_connect_result = mp_subcheck_init();
250
251 // Try initial connection
252 if (np_net_connect(config.server_address, config.server_port, &socket_descriptor,
253 config.protocol) == STATE_CRITICAL) {
254 // Early exit here, we got connection refused
255 inital_connect_result =
256 mp_set_subcheck_state(inital_connect_result, config.econn_refuse_state);
257 xasprintf(&inital_connect_result.output, "Connection to %s on port %i was REFUSED",
258 config.server_address, config.server_port);
259 mp_add_subcheck_to_check(&overall, inital_connect_result);
260 mp_exit(overall);
261 } else {
262 inital_connect_result = mp_set_subcheck_state(inital_connect_result, STATE_OK);
263 xasprintf(&inital_connect_result.output, "Connection to %s on port %i was a SUCCESS",
264 config.server_address, config.server_port);
265 mp_add_subcheck_to_check(&overall, inital_connect_result);
266 }
244 267
245#ifdef HAVE_SSL 268#ifdef HAVE_SSL
246 if (flags & FLAG_SSL){ 269 if (config.use_tls) {
247 result = np_net_ssl_init_with_hostname(sd, (sni_specified ? sni : NULL)); 270 mp_subcheck tls_connection_result = mp_subcheck_init();
248 if (result == STATE_OK && check_cert) { 271 mp_state_enum result = np_net_ssl_init_with_hostname(
249 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit); 272 socket_descriptor, (config.sni_specified ? config.sni : NULL));
273 tls_connection_result = mp_set_subcheck_default_state(tls_connection_result, result);
274
275 if (result == STATE_OK) {
276 xasprintf(&tls_connection_result.output, "TLS connection succeeded");
277
278 if (config.check_cert) {
279 result =
280 np_net_ssl_check_cert(config.days_till_exp_warn, config.days_till_exp_crit);
281
282 mp_subcheck tls_certificate_lifetime_result = mp_subcheck_init();
283 tls_certificate_lifetime_result =
284 mp_set_subcheck_state(tls_certificate_lifetime_result, result);
285
286 if (result == STATE_OK) {
287 xasprintf(&tls_certificate_lifetime_result.output,
288 "Certificate lifetime is within thresholds");
289 } else if (result == STATE_WARNING) {
290 xasprintf(&tls_certificate_lifetime_result.output,
291 "Certificate lifetime is violating warning threshold (%i)",
292 config.days_till_exp_warn);
293 } else if (result == STATE_CRITICAL) {
294 xasprintf(&tls_certificate_lifetime_result.output,
295 "Certificate lifetime is violating critical threshold (%i)",
296 config.days_till_exp_crit);
297 } else {
298 xasprintf(&tls_certificate_lifetime_result.output,
299 "Certificate lifetime is somehow unknown");
300 }
301
302 mp_add_subcheck_to_subcheck(&tls_connection_result,
303 tls_certificate_lifetime_result);
304 }
305
306 mp_add_subcheck_to_check(&overall, tls_connection_result);
307 } else {
308 xasprintf(&tls_connection_result.output, "TLS connection failed");
309 mp_add_subcheck_to_check(&overall, tls_connection_result);
310
311 if (socket_descriptor) {
312 close(socket_descriptor);
313 }
314 np_net_ssl_cleanup();
315
316 mp_exit(overall);
250 } 317 }
251 } 318 }
252 if(result != STATE_OK){
253 if(sd) close(sd);
254 np_net_ssl_cleanup();
255 return result;
256 }
257#endif /* HAVE_SSL */ 319#endif /* HAVE_SSL */
258 320
259 if (server_send != NULL) { /* Something to send? */ 321 if (config.send != NULL) { /* Something to send? */
260 my_send(server_send, strlen(server_send)); 322 my_send(socket_descriptor, config.send, strlen(config.send), config.use_tls);
261 } 323 }
262 324
263 if (delay > 0) { 325 if (config.delay > 0) {
264 tv.tv_sec += delay; 326 start_time.tv_sec += config.delay;
265 sleep (delay); 327 sleep(config.delay);
266 } 328 }
267 329
268 if(flags & FLAG_VERBOSE) { 330 if (verbosity > 0) {
269 if (server_send) { 331 if (config.send) {
270 printf("Send string: %s\n", server_send); 332 printf("Send string: %s\n", config.send);
333 }
334 if (config.quit) {
335 printf("Quit string: %s\n", config.quit);
271 } 336 }
272 if (server_quit) { 337 printf("server_expect_count: %d\n", (int)config.server_expect_count);
273 printf("Quit string: %s\n", server_quit); 338 for (size_t i = 0; i < config.server_expect_count; i++) {
339 printf("\t%zd: %s\n", i, config.server_expect[i]);
274 } 340 }
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 } 341 }
279 342
280 /* if(len) later on, we know we have a non-NULL response */ 343 /* if(len) later on, we know we have a non-NULL response */
281 ssize_t len = 0; 344 ssize_t len = 0;
345 char *received_buffer = NULL;
346 enum np_match_result match = NP_MATCH_NONE;
347 mp_subcheck expected_data_result = mp_subcheck_init();
282 348
283 if (server_expect_count) { 349 if (config.server_expect_count) {
284 ssize_t received = 0; 350 ssize_t received = 0;
351 char buffer[MAXBUF];
285 352
286 /* watch for the expect string */ 353 /* watch for the expect string */
287 while ((received = my_recv(buffer, sizeof(buffer))) > 0) { 354 while ((received = my_recv(socket_descriptor, buffer, sizeof(buffer), config.use_tls)) >
288 status = realloc(status, len + received + 1); 355 0) {
289 memcpy(&status[len], buffer, received); 356 received_buffer = realloc(received_buffer, len + received + 1);
357
358 if (received_buffer == NULL) {
359 die(STATE_UNKNOWN, _("Allocation failed"));
360 }
361
362 memcpy(&received_buffer[len], buffer, received);
290 len += received; 363 len += received;
291 status[len] = '\0'; 364 received_buffer[len] = '\0';
292 365
293 /* stop reading if user-forced */ 366 /* stop reading if user-forced */
294 if (maxbytes && len >= maxbytes) 367 if (config.maxbytes && len >= config.maxbytes) {
295 break; 368 break;
369 }
296 370
297 if ((match = np_expect_match(status, 371 if ((match = np_expect_match(received_buffer, config.server_expect,
298 server_expect, 372 config.server_expect_count, config.match_flags)) !=
299 server_expect_count, 373 NP_MATCH_RETRY) {
300 match_flags)) != NP_MATCH_RETRY)
301 break; 374 break;
375 }
376
377 fd_set rfds;
378 FD_ZERO(&rfds);
379 FD_SET(socket_descriptor, &rfds);
302 380
303 /* some protocols wait for further input, so make sure we don't wait forever */ 381 /* some protocols wait for further input, so make sure we don't wait forever */
304 FD_SET(sd, &rfds); 382 struct timeval timeout;
305 timeout.tv_sec = READ_TIMEOUT; 383 timeout.tv_sec = READ_TIMEOUT;
306 timeout.tv_usec = 0; 384 timeout.tv_usec = 0;
307 if(select(sd + 1, &rfds, NULL, NULL, &timeout) <= 0) 385
386 if (select(socket_descriptor + 1, &rfds, NULL, NULL, &timeout) <= 0) {
308 break; 387 break;
388 }
309 } 389 }
310 390
311 if (match == NP_MATCH_RETRY) 391 if (match == NP_MATCH_RETRY) {
312 match = NP_MATCH_FAILURE; 392 match = NP_MATCH_FAILURE;
393 }
313 394
314 /* no data when expected, so return critical */ 395 /* no data when expected, so return critical */
315 if (len == 0) 396 if (len == 0) {
316 die (STATE_CRITICAL, _("No data received from host\n")); 397 xasprintf(&expected_data_result.output, "Received no data when some was expected");
398 expected_data_result = mp_set_subcheck_state(expected_data_result, STATE_CRITICAL);
399 mp_add_subcheck_to_check(&overall, expected_data_result);
400 mp_exit(overall);
401 }
317 402
318 /* print raw output if we're debugging */ 403 /* print raw output if we're debugging */
319 if(flags & FLAG_VERBOSE) 404 if (verbosity > 0) {
320 printf("received %d bytes from host\n#-raw-recv-------#\n%s\n#-raw-recv-------#\n", 405 printf("received %d bytes from host\n#-raw-recv-------#\n%s\n#-raw-recv-------#\n",
321 (int)len + 1, status); 406 (int)len + 1, received_buffer);
407 }
322 /* strip whitespace from end of output */ 408 /* strip whitespace from end of output */
323 while(--len > 0 && isspace(status[len])) 409 while (--len > 0 && isspace(received_buffer[len])) {
324 status[len] = '\0'; 410 received_buffer[len] = '\0';
411 }
325 } 412 }
326 413
327 if (server_quit != NULL) { 414 if (config.quit != NULL) {
328 my_send(server_quit, strlen(server_quit)); 415 my_send(socket_descriptor, config.quit, strlen(config.quit), config.use_tls);
416 }
417
418 if (socket_descriptor) {
419 close(socket_descriptor);
329 } 420 }
330 if (sd) close (sd);
331#ifdef HAVE_SSL 421#ifdef HAVE_SSL
332 np_net_ssl_cleanup(); 422 np_net_ssl_cleanup();
333#endif 423#endif
334 424
335 microsec = deltime (tv); 425 long microsec = deltime(start_time);
336 elapsed_time = (double)microsec / 1.0e6; 426 double elapsed_time = (double)microsec / 1.0e6;
427
428 mp_subcheck elapsed_time_result = mp_subcheck_init();
429
430 mp_perfdata time_pd = perfdata_init();
431 time_pd = mp_set_pd_value(time_pd, elapsed_time);
432 time_pd.label = "time";
433 time_pd.uom = "s";
434
435 if (config.critical_time_set && elapsed_time > config.critical_time) {
436 xasprintf(&elapsed_time_result.output,
437 "Connection time %fs exceeded critical threshold (%f)", elapsed_time,
438 config.critical_time);
439
440 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_CRITICAL);
441 time_pd.crit_present = true;
442 mp_range crit_val = mp_range_init();
443
444 crit_val.end = mp_create_pd_value(config.critical_time);
445 crit_val.end_infinity = false;
446
447 time_pd.crit = crit_val;
448 } else if (config.warning_time_set && elapsed_time > config.warning_time) {
449 xasprintf(&elapsed_time_result.output,
450 "Connection time %fs exceeded warning threshold (%f)", elapsed_time,
451 config.critical_time);
452
453 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_WARNING);
454 time_pd.warn_present = true;
455 mp_range warn_val = mp_range_init();
456 warn_val.end = mp_create_pd_value(config.critical_time);
457 warn_val.end_infinity = false;
458
459 time_pd.warn = warn_val;
460 } else {
461 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_OK);
462 xasprintf(&elapsed_time_result.output, "Connection time %fs is within thresholds",
463 elapsed_time);
464 }
337 465
338 if (flags & FLAG_TIME_CRIT && elapsed_time > critical_time) 466 mp_add_perfdata_to_subcheck(&elapsed_time_result, time_pd);
339 result = STATE_CRITICAL; 467 mp_add_subcheck_to_check(&overall, elapsed_time_result);
340 else if (flags & FLAG_TIME_WARN && elapsed_time > warning_time)
341 result = STATE_WARNING;
342 468
343 /* did we get the response we hoped? */ 469 /* did we get the response we hoped? */
344 if(match == NP_MATCH_FAILURE && result != STATE_CRITICAL) 470 if (match == NP_MATCH_FAILURE) {
345 result = expect_mismatch_state; 471 expected_data_result =
472 mp_set_subcheck_state(expected_data_result, config.expect_mismatch_state);
473 xasprintf(&expected_data_result.output, "Answer failed to match expectation");
474 mp_add_subcheck_to_check(&overall, expected_data_result);
475 } else if (match == NP_MATCH_SUCCESS) {
476 expected_data_result = mp_set_subcheck_state(expected_data_result, STATE_OK);
477 xasprintf(&expected_data_result.output, "The answer of the server matched the expectation");
478 mp_add_subcheck_to_check(&overall, expected_data_result);
479 }
346 480
347 /* reset the alarm */ 481 /* reset the alarm */
348 alarm (0); 482 alarm(0);
349
350 /* this is a bit stupid, because we don't want to print the
351 * response time (which can look ok to the user) if we didn't get
352 * the response we were looking for. if-else */
353 printf("%s %s - ", SERVICE, state_text(result));
354
355 if(match == NP_MATCH_FAILURE && len && !(flags & FLAG_HIDE_OUTPUT))
356 printf("Unexpected response from host/socket: %s", status);
357 else {
358 if(match == NP_MATCH_FAILURE)
359 printf("Unexpected response from host/socket on ");
360 else
361 printf("%.3f second response time on ", elapsed_time);
362 if(server_address[0] != '/') {
363 if (host_specified)
364 printf("%s port %d",
365 server_address, server_port);
366 else
367 printf("port %d", server_port);
368 }
369 else
370 printf("socket %s", server_address);
371 }
372 483
373 if (match != NP_MATCH_FAILURE && !(flags & FLAG_HIDE_OUTPUT) && len) 484 mp_exit(overall);
374 printf (" [%s]", status);
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} 485}
399 486
400
401
402/* process command-line arguments */ 487/* process command-line arguments */
403static int process_arguments (int argc, char **argv) { 488static check_tcp_config_wrapper process_arguments(int argc, char **argv, check_tcp_config config) {
404 int c;
405 bool escape = false;
406 char *temp;
407
408 enum { 489 enum {
409 SNI_OPTION = CHAR_MAX + 1 490 SNI_OPTION = CHAR_MAX + 1,
491 output_format_index,
410 }; 492 };
411 493
412 int option = 0;
413 static struct option longopts[] = { 494 static struct option longopts[] = {
414 {"hostname", required_argument, 0, 'H'}, 495 {"hostname", required_argument, 0, 'H'},
415 {"critical", required_argument, 0, 'c'}, 496 {"critical", required_argument, 0, 'c'},
@@ -437,278 +518,311 @@ static int process_arguments (int argc, char **argv) {
437 {"ssl", no_argument, 0, 'S'}, 518 {"ssl", no_argument, 0, 'S'},
438 {"sni", required_argument, 0, SNI_OPTION}, 519 {"sni", required_argument, 0, SNI_OPTION},
439 {"certificate", required_argument, 0, 'D'}, 520 {"certificate", required_argument, 0, 'D'},
440 {0, 0, 0, 0} 521 {"output-format", required_argument, 0, output_format_index},
441 }; 522 {0, 0, 0, 0}};
442 523
443 if (argc < 2) 524 if (argc < 2) {
444 usage4 (_("No arguments found")); 525 usage4(_("No arguments found"));
526 }
445 527
446 /* backwards compatibility */ 528 /* backwards compatibility */
447 for (c = 1; c < argc; c++) { 529 for (int i = 1; i < argc; i++) {
448 if (strcmp ("-to", argv[c]) == 0) 530 if (strcmp("-to", argv[i]) == 0) {
449 strcpy (argv[c], "-t"); 531 strcpy(argv[i], "-t");
450 else if (strcmp ("-wt", argv[c]) == 0) 532 } else if (strcmp("-wt", argv[i]) == 0) {
451 strcpy (argv[c], "-w"); 533 strcpy(argv[i], "-w");
452 else if (strcmp ("-ct", argv[c]) == 0) 534 } else if (strcmp("-ct", argv[i]) == 0) {
453 strcpy (argv[c], "-c"); 535 strcpy(argv[i], "-c");
536 }
454 } 537 }
455 538
456 if (!is_option (argv[1])) { 539 if (!is_option(argv[1])) {
457 server_address = argv[1]; 540 config.server_address = argv[1];
458 argv[1] = argv[0]; 541 argv[1] = argv[0];
459 argv = &argv[1]; 542 argv = &argv[1];
460 argc--; 543 argc--;
461 } 544 }
462 545
463 while (1) { 546 bool escape = false;
464 c = getopt_long (argc, argv, "+hVv46EAH:s:e:q:m:c:w:t:p:C:W:d:Sr:jD:M:", 547
465 longopts, &option); 548 while (true) {
549 int option = 0;
550 int option_index =
551 getopt_long(argc, argv, "+hVv46EAH:s:e:q:m:c:w:t:p:C:W:d:Sr:jD:M:", longopts, &option);
466 552
467 if (c == -1 || c == EOF || c == 1) 553 if (option_index == -1 || option_index == EOF || option_index == 1) {
468 break; 554 break;
555 }
469 556
470 switch (c) { 557 switch (option_index) {
471 case '?': /* print short usage statement if args not parsable */ 558 case '?': /* print short usage statement if args not parsable */
472 usage5 (); 559 usage5();
473 case 'h': /* help */ 560 case 'h': /* help */
474 print_help (); 561 print_help(config.service);
475 exit (STATE_UNKNOWN); 562 exit(STATE_UNKNOWN);
476 case 'V': /* version */ 563 case 'V': /* version */
477 print_revision (progname, NP_VERSION); 564 print_revision(progname, NP_VERSION);
478 exit (STATE_UNKNOWN); 565 exit(STATE_UNKNOWN);
479 case 'v': /* verbose mode */ 566 case 'v': /* verbose mode */
480 flags |= FLAG_VERBOSE; 567 verbosity++;
481 match_flags |= NP_MATCH_VERBOSE; 568 config.match_flags |= NP_MATCH_VERBOSE;
482 break; 569 break;
483 case '4': 570 case '4': // Apparently unused TODO
484 address_family = AF_INET; 571 address_family = AF_INET;
485 break; 572 break;
486 case '6': 573 case '6': // Apparently unused TODO
487#ifdef USE_IPV6 574#ifdef USE_IPV6
488 address_family = AF_INET6; 575 address_family = AF_INET6;
489#else 576#else
490 usage4 (_("IPv6 support not available")); 577 usage4(_("IPv6 support not available"));
491#endif 578#endif
492 break; 579 break;
493 case 'H': /* hostname */ 580 case 'H': /* hostname */
494 host_specified = true; 581 config.host_specified = true;
495 server_address = optarg; 582 config.server_address = optarg;
496 break;
497 case 'c': /* critical */
498 critical_time = strtod (optarg, NULL);
499 flags |= FLAG_TIME_CRIT;
500 break; 583 break;
501 case 'j': /* hide output */ 584 case 'c': /* critical */
502 flags |= FLAG_HIDE_OUTPUT; 585 config.critical_time = strtod(optarg, NULL);
586 config.critical_time_set = true;
503 break; 587 break;
504 case 'w': /* warning */ 588 case 'j': /* hide output */
505 warning_time = strtod (optarg, NULL); 589 config.hide_output = true;
506 flags |= FLAG_TIME_WARN;
507 break; 590 break;
508 case 'C': 591 case 'w': /* warning */
509 crit_codes = realloc (crit_codes, ++crit_codes_count); 592 config.warning_time = strtod(optarg, NULL);
510 crit_codes[crit_codes_count - 1] = optarg; 593 config.warning_time_set = true;
511 break; 594 break;
512 case 'W': 595 case 't': /* timeout */
513 warn_codes = realloc (warn_codes, ++warn_codes_count); 596 if (!is_intpos(optarg)) {
514 warn_codes[warn_codes_count - 1] = optarg; 597 usage4(_("Timeout interval must be a positive integer"));
515 break; 598 } else {
516 case 't': /* timeout */ 599 socket_timeout = atoi(optarg);
517 if (!is_intpos (optarg)) 600 }
518 usage4 (_("Timeout interval must be a positive integer"));
519 else
520 socket_timeout = atoi (optarg);
521 break; 601 break;
522 case 'p': /* port */ 602 case 'p': /* port */
523 if (!is_intpos (optarg)) 603 if (!is_intpos(optarg)) {
524 usage4 (_("Port must be a positive integer")); 604 usage4(_("Port must be a positive integer"));
525 else 605 } else {
526 server_port = atoi (optarg); 606 config.server_port = atoi(optarg);
607 }
527 break; 608 break;
528 case 'E': 609 case 'E':
529 escape = true; 610 escape = true;
530 break; 611 break;
531 case 's': 612 case 's':
532 if (escape) 613 if (escape) {
533 server_send = np_escaped_string(optarg); 614 config.send = np_escaped_string(optarg);
534 else 615 } else {
535 xasprintf(&server_send, "%s", optarg); 616 xasprintf(&config.send, "%s", optarg);
617 }
536 break; 618 break;
537 case 'e': /* expect string (may be repeated) */ 619 case 'e': /* expect string (may be repeated) */
538 match_flags &= ~NP_MATCH_EXACT; 620 config.match_flags &= ~NP_MATCH_EXACT;
539 if (server_expect_count == 0) 621 if (config.server_expect_count == 0) {
540 server_expect = malloc (sizeof (char *) * (++server_expect_count)); 622 config.server_expect = malloc(sizeof(char *) * (++config.server_expect_count));
541 else 623 } else {
542 server_expect = realloc (server_expect, sizeof (char *) * (++server_expect_count)); 624 config.server_expect =
543 server_expect[server_expect_count - 1] = optarg; 625 realloc(config.server_expect, sizeof(char *) * (++config.server_expect_count));
626 }
627
628 if (config.server_expect == NULL) {
629 die(STATE_UNKNOWN, _("Allocation failed"));
630 }
631 config.server_expect[config.server_expect_count - 1] = optarg;
544 break; 632 break;
545 case 'm': 633 case 'm':
546 if (!is_intpos (optarg)) 634 if (!is_intpos(optarg)) {
547 usage4 (_("Maxbytes must be a positive integer")); 635 usage4(_("Maxbytes must be a positive integer"));
548 else 636 } else {
549 maxbytes = strtol (optarg, NULL, 0); 637 config.maxbytes = strtol(optarg, NULL, 0);
638 }
550 break; 639 break;
551 case 'q': 640 case 'q':
552 if (escape) 641 if (escape) {
553 server_quit = np_escaped_string(optarg); 642 config.quit = np_escaped_string(optarg);
554 else 643 } else {
555 xasprintf(&server_quit, "%s\r\n", optarg); 644 xasprintf(&config.quit, "%s\r\n", optarg);
645 }
556 break; 646 break;
557 case 'r': 647 case 'r':
558 if (!strncmp(optarg,"ok",2)) 648 if (!strncmp(optarg, "ok", 2)) {
559 econn_refuse_state = STATE_OK; 649 config.econn_refuse_state = STATE_OK;
560 else if (!strncmp(optarg,"warn",4)) 650 } else if (!strncmp(optarg, "warn", 4)) {
561 econn_refuse_state = STATE_WARNING; 651 config.econn_refuse_state = STATE_WARNING;
562 else if (!strncmp(optarg,"crit",4)) 652 } else if (!strncmp(optarg, "crit", 4)) {
563 econn_refuse_state = STATE_CRITICAL; 653 config.econn_refuse_state = STATE_CRITICAL;
564 else 654 } else {
565 usage4 (_("Refuse must be one of ok, warn, crit")); 655 usage4(_("Refuse must be one of ok, warn, crit"));
656 }
566 break; 657 break;
567 case 'M': 658 case 'M':
568 if (!strncmp(optarg,"ok",2)) 659 if (!strncmp(optarg, "ok", 2)) {
569 expect_mismatch_state = STATE_OK; 660 config.expect_mismatch_state = STATE_OK;
570 else if (!strncmp(optarg,"warn",4)) 661 } else if (!strncmp(optarg, "warn", 4)) {
571 expect_mismatch_state = STATE_WARNING; 662 config.expect_mismatch_state = STATE_WARNING;
572 else if (!strncmp(optarg,"crit",4)) 663 } else if (!strncmp(optarg, "crit", 4)) {
573 expect_mismatch_state = STATE_CRITICAL; 664 config.expect_mismatch_state = STATE_CRITICAL;
574 else 665 } else {
575 usage4 (_("Mismatch must be one of ok, warn, crit")); 666 usage4(_("Mismatch must be one of ok, warn, crit"));
667 }
576 break; 668 break;
577 case 'd': 669 case 'd':
578 if (is_intpos (optarg)) 670 if (is_intpos(optarg)) {
579 delay = atoi (optarg); 671 config.delay = atoi(optarg);
580 else 672 } else {
581 usage4 (_("Delay must be a positive integer")); 673 usage4(_("Delay must be a positive integer"));
674 }
582 break; 675 break;
583 case 'D': /* Check SSL cert validity - days 'til certificate expiration */ 676 case 'D': /* Check SSL cert validity - days 'til certificate expiration */
584#ifdef HAVE_SSL 677#ifdef HAVE_SSL
585# ifdef USE_OPENSSL /* XXX */ 678# ifdef USE_OPENSSL /* XXX */
586 if ((temp=strchr(optarg,','))!=NULL) { 679 {
587 *temp='\0'; 680 char *temp;
588 if (!is_intnonneg (optarg)) 681 if ((temp = strchr(optarg, ',')) != NULL) {
589 usage2 (_("Invalid certificate expiration period"), optarg); 682 *temp = '\0';
590 days_till_exp_warn = atoi (optarg); 683 if (!is_intnonneg(optarg)) {
591 *temp=','; 684 usage2(_("Invalid certificate expiration period"), optarg);
592 temp++; 685 }
593 if (!is_intnonneg (temp)) 686 config.days_till_exp_warn = atoi(optarg);
594 usage2 (_("Invalid certificate expiration period"), temp); 687 *temp = ',';
595 days_till_exp_crit = atoi (temp); 688 temp++;
689 if (!is_intnonneg(temp)) {
690 usage2(_("Invalid certificate expiration period"), temp);
691 }
692 config.days_till_exp_crit = atoi(temp);
693 } else {
694 config.days_till_exp_crit = 0;
695 if (!is_intnonneg(optarg)) {
696 usage2(_("Invalid certificate expiration period"), optarg);
697 }
698 config.days_till_exp_warn = atoi(optarg);
596 } 699 }
597 else { 700 config.check_cert = true;
598 days_till_exp_crit=0; 701 config.use_tls = true;
599 if (!is_intnonneg (optarg)) 702 } break;
600 usage2 (_("Invalid certificate expiration period"), optarg); 703# endif /* USE_OPENSSL */
601 days_till_exp_warn = atoi (optarg);
602 }
603 check_cert = true;
604 flags |= FLAG_SSL;
605 break;
606# endif /* USE_OPENSSL */
607#endif 704#endif
608 /* fallthrough if we don't have ssl */ 705 /* fallthrough if we don't have ssl */
609 case 'S': 706 case 'S':
610#ifdef HAVE_SSL 707#ifdef HAVE_SSL
611 flags |= FLAG_SSL; 708 config.use_tls = true;
612#else 709#else
613 die (STATE_UNKNOWN, _("Invalid option - SSL is not available")); 710 die(STATE_UNKNOWN, _("Invalid option - SSL is not available"));
614#endif 711#endif
615 break; 712 break;
616 case SNI_OPTION: 713 case SNI_OPTION:
617#ifdef HAVE_SSL 714#ifdef HAVE_SSL
618 flags |= FLAG_SSL; 715 config.use_tls = true;
619 sni_specified = true; 716 config.sni_specified = true;
620 sni = optarg; 717 config.sni = optarg;
621#else 718#else
622 die (STATE_UNKNOWN, _("Invalid option - SSL is not available")); 719 die(STATE_UNKNOWN, _("Invalid option - SSL is not available"));
623#endif 720#endif
624 break; 721 break;
625 case 'A': 722 case 'A':
626 match_flags |= NP_MATCH_ALL; 723 config.match_flags |= NP_MATCH_ALL;
724 break;
725 case output_format_index: {
726 parsed_output_format parser = mp_parse_output_format(optarg);
727 if (!parser.parsing_success) {
728 // TODO List all available formats here, maybe add anothoer usage function
729 printf("Invalid output format: %s\n", optarg);
730 exit(STATE_UNKNOWN);
731 }
732
733 config.output_format_set = true;
734 config.output_format = parser.output_format;
627 break; 735 break;
628 } 736 }
737 }
629 } 738 }
630 739
631 c = optind; 740 int index = optind;
632 if(!host_specified && c < argc) 741 if (!config.host_specified && index < argc) {
633 server_address = strdup (argv[c++]); 742 config.server_address = strdup(argv[index++]);
743 }
634 744
635 if (server_address == NULL) 745 if (config.server_address == NULL) {
636 usage4 (_("You must provide a server address")); 746 usage4(_("You must provide a server address"));
637 else if (server_address[0] != '/' && !is_host(server_address)) 747 } 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); 748 die(STATE_CRITICAL, "%s %s - %s: %s\n", config.service, state_text(STATE_CRITICAL),
749 _("Invalid hostname, address or socket"), config.server_address);
750 }
639 751
640 return OK; 752 check_tcp_config_wrapper result = {
753 .config = config,
754 .errorcode = OK,
755 };
756 return result;
641} 757}
642 758
643 759void print_help(const char *service) {
644void 760 print_revision(progname, NP_VERSION);
645print_help (void) 761
646{ 762 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
647 print_revision (progname, NP_VERSION); 763 printf(COPYRIGHT, copyright, email);
648 764
649 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 765 printf(_("This plugin tests %s connections with the specified host (or unix socket).\n\n"),
650 printf (COPYRIGHT, copyright, email); 766 service);
651 767
652 printf (_("This plugin tests %s connections with the specified host (or unix socket).\n\n"), 768 print_usage();
653 SERVICE); 769
654 770 printf(UT_HELP_VRSN);
655 print_usage (); 771 printf(UT_EXTRA_OPTS);
656 772
657 printf (UT_HELP_VRSN); 773 printf(UT_HOST_PORT, 'p', "none");
658 printf (UT_EXTRA_OPTS); 774
659 775 printf(UT_IPv46);
660 printf (UT_HOST_PORT, 'p', "none"); 776
661 777 printf(" %s\n", "-E, --escape");
662 printf (UT_IPv46); 778 printf(" %s\n", _("Can use \\n, \\r, \\t or \\\\ in send or quit string. Must come before "
663 779 "send or quit option"));
664 printf (" %s\n", "-E, --escape"); 780 printf(" %s\n", _("Default: nothing added to send, \\r\\n added to end of quit"));
665 printf (" %s\n", _("Can use \\n, \\r, \\t or \\\\ in send or quit string. Must come before send or quit option")); 781 printf(" %s\n", "-s, --send=STRING");
666 printf (" %s\n", _("Default: nothing added to send, \\r\\n added to end of quit")); 782 printf(" %s\n", _("String to send to the server"));
667 printf (" %s\n", "-s, --send=STRING"); 783 printf(" %s\n", "-e, --expect=STRING");
668 printf (" %s\n", _("String to send to the server")); 784 printf(" %s %s\n", _("String to expect in server response"), _("(may be repeated)"));
669 printf (" %s\n", "-e, --expect=STRING"); 785 printf(" %s\n", "-A, --all");
670 printf (" %s %s\n", _("String to expect in server response"), _("(may be repeated)")); 786 printf(" %s\n", _("All expect strings need to occur in server response. Default is any"));
671 printf (" %s\n", "-A, --all"); 787 printf(" %s\n", "-q, --quit=STRING");
672 printf (" %s\n", _("All expect strings need to occur in server response. Default is any")); 788 printf(" %s\n", _("String to send server to initiate a clean close of the connection"));
673 printf (" %s\n", "-q, --quit=STRING"); 789 printf(" %s\n", "-r, --refuse=ok|warn|crit");
674 printf (" %s\n", _("String to send server to initiate a clean close of the connection")); 790 printf(" %s\n", _("Accept TCP refusals with states ok, warn, crit (default: crit)"));
675 printf (" %s\n", "-r, --refuse=ok|warn|crit"); 791 printf(" %s\n", "-M, --mismatch=ok|warn|crit");
676 printf (" %s\n", _("Accept TCP refusals with states ok, warn, crit (default: crit)")); 792 printf(" %s\n",
677 printf (" %s\n", "-M, --mismatch=ok|warn|crit"); 793 _("Accept expected string mismatches with states ok, warn, crit (default: warn)"));
678 printf (" %s\n", _("Accept expected string mismatches with states ok, warn, crit (default: warn)")); 794 printf(" %s\n", "-j, --jail");
679 printf (" %s\n", "-j, --jail"); 795 printf(" %s\n", _("Hide output from TCP socket"));
680 printf (" %s\n", _("Hide output from TCP socket")); 796 printf(" %s\n", "-m, --maxbytes=INTEGER");
681 printf (" %s\n", "-m, --maxbytes=INTEGER"); 797 printf(" %s\n", _("Close connection once more than this number of bytes are received"));
682 printf (" %s\n", _("Close connection once more than this number of bytes are received")); 798 printf(" %s\n", "-d, --delay=INTEGER");
683 printf (" %s\n", "-d, --delay=INTEGER"); 799 printf(" %s\n", _("Seconds to wait between sending string and polling for response"));
684 printf (" %s\n", _("Seconds to wait between sending string and polling for response"));
685 800
686#ifdef HAVE_SSL 801#ifdef HAVE_SSL
687 printf (" %s\n", "-D, --certificate=INTEGER[,INTEGER]"); 802 printf(" %s\n", "-D, --certificate=INTEGER[,INTEGER]");
688 printf (" %s\n", _("Minimum number of days a certificate has to be valid.")); 803 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).")); 804 printf(" %s\n", _("1st is #days for warning, 2nd is critical (if not specified - 0)."));
690 printf (" %s\n", "-S, --ssl"); 805 printf(" %s\n", "-S, --ssl");
691 printf (" %s\n", _("Use SSL for the connection.")); 806 printf(" %s\n", _("Use SSL for the connection."));
692 printf (" %s\n", "--sni=STRING"); 807 printf(" %s\n", "--sni=STRING");
693 printf (" %s\n", _("SSL server_name")); 808 printf(" %s\n", _("SSL server_name"));
694#endif 809#endif
695 810
696 printf (UT_WARN_CRIT); 811 printf(UT_WARN_CRIT);
697 812
698 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 813 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
699 814
700 printf (UT_VERBOSE); 815 printf(UT_OUTPUT_FORMAT);
816 printf(UT_VERBOSE);
701 817
702 printf (UT_SUPPORT); 818 printf(UT_SUPPORT);
703} 819}
704 820
705 821void print_usage(void) {
706void 822 printf("%s\n", _("Usage:"));
707print_usage (void) 823 printf("%s -H host -p port [-w <warning time>] [-c <critical time>] [-s <send string>]\n",
708{ 824 progname);
709 printf ("%s\n", _("Usage:")); 825 printf("[-e <expect string>] [-q <quit string>][-m <maximum bytes>] [-d <delay>]\n");
710 printf ("%s -H host -p port [-w <warning time>] [-c <critical time>] [-s <send string>]\n",progname); 826 printf("[-t <timeout seconds>] [-r <refuse state>] [-M <mismatch state>] [-v] [-4|-6] [-j]\n");
711 printf ("[-e <expect string>] [-q <quit string>][-m <maximum bytes>] [-d <delay>]\n"); 827 printf("[-D <warn days cert expire>[,<crit days cert expire>]] [-S <use SSL>] [-E]\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} 828}
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..fc9ba3f9 100644
--- a/plugins/check_time.c
+++ b/plugins/check_time.c
@@ -1,374 +1,355 @@
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"),
103 server_address, server_port); 91 config.server_address, config.server_port);
104 } 92 }
105 93
106 if (use_udp) { 94 if (config.use_udp) {
107 if (send (sd, "", 0, 0) < 0) { 95 if (send(socket, "", 0, 0) < 0) {
108 if (check_critical_time) 96 if (config.check_critical_time) {
109 result = STATE_CRITICAL; 97 result = STATE_CRITICAL;
110 else if (check_warning_time) 98 } else if (config.check_warning_time) {
111 result = STATE_WARNING; 99 result = STATE_WARNING;
112 else 100 } else {
113 result = STATE_UNKNOWN; 101 result = STATE_UNKNOWN;
114 die (result, 102 }
115 _("TIME UNKNOWN - could not send UDP request to server %s, port %d\n"), 103 die(result, _("TIME UNKNOWN - could not send UDP request to server %s, port %d\n"),
116 server_address, server_port); 104 config.server_address, config.server_port);
117 } 105 }
118 } 106 }
119 107
120 /* watch for the connection string */ 108 /* watch for the connection string */
121 result = recv (sd, (void *)&raw_server_time, sizeof (raw_server_time), 0); 109 uint32_t raw_server_time;
110 result = recv(socket, (void *)&raw_server_time, sizeof(raw_server_time), 0);
122 111
123 /* close the connection */ 112 /* close the connection */
124 close (sd); 113 close(socket);
125 114
126 /* reset the alarm */ 115 /* reset the alarm */
127 time (&end_time); 116 time(&end_time);
128 alarm (0); 117 alarm(0);
129 118
130 /* return a WARNING status if we couldn't read any data */ 119 /* return a WARNING status if we couldn't read any data */
131 if (result <= 0) { 120 if (result <= 0) {
132 if (check_critical_time) 121 if (config.check_critical_time) {
133 result = STATE_CRITICAL; 122 result = STATE_CRITICAL;
134 else if (check_warning_time) 123 } else if (config.check_warning_time) {
135 result = STATE_WARNING; 124 result = STATE_WARNING;
136 else 125 } else {
137 result = STATE_UNKNOWN; 126 result = STATE_UNKNOWN;
138 die (result, 127 }
139 _("TIME UNKNOWN - no data received from server %s, port %d\n"), 128 die(result, _("TIME UNKNOWN - no data received from server %s, port %d\n"),
140 server_address, server_port); 129 config.server_address, config.server_port);
141 } 130 }
142 131
143 result = STATE_OK; 132 result = STATE_OK;
144 133
145 conntime = (end_time - start_time); 134 time_t conntime = (end_time - start_time);
146 if (check_critical_time&& conntime > critical_time) 135 if (config.check_critical_time && conntime > config.critical_time) {
147 result = STATE_CRITICAL; 136 result = STATE_CRITICAL;
148 else if (check_warning_time && conntime > warning_time) 137 } else if (config.check_warning_time && conntime > config.warning_time) {
149 result = STATE_WARNING; 138 result = STATE_WARNING;
139 }
150 140
151 if (result != STATE_OK) 141 if (result != STATE_OK) {
152 die (result, _("TIME %s - %d second response time|%s\n"), 142 die(result, _("TIME %s - %d second response time|%s\n"), state_text(result), (int)conntime,
153 state_text (result), (int)conntime, 143 perfdata("time", (long)conntime, "s", config.check_warning_time,
154 perfdata ("time", (long)conntime, "s", 144 (long)config.warning_time, config.check_critical_time,
155 check_warning_time, (long)warning_time, 145 (long)config.critical_time, true, 0, false, 0));
156 check_critical_time, (long)critical_time, 146 }
157 true, 0, false, 0));
158 147
159 server_time = ntohl (raw_server_time) - UNIX_EPOCH; 148 unsigned long server_time;
160 if (server_time > (unsigned long)end_time) 149 unsigned long diff_time;
150 server_time = ntohl(raw_server_time) - UNIX_EPOCH;
151 if (server_time > (unsigned long)end_time) {
161 diff_time = server_time - (unsigned long)end_time; 152 diff_time = server_time - (unsigned long)end_time;
162 else 153 } else {
163 diff_time = (unsigned long)end_time - server_time; 154 diff_time = (unsigned long)end_time - server_time;
155 }
164 156
165 if (check_critical_diff&& diff_time > critical_diff) 157 if (config.check_critical_diff && diff_time > config.critical_diff) {
166 result = STATE_CRITICAL; 158 result = STATE_CRITICAL;
167 else if (check_warning_diff&& diff_time > warning_diff) 159 } else if (config.check_warning_diff && diff_time > config.warning_diff) {
168 result = STATE_WARNING; 160 result = STATE_WARNING;
161 }
169 162
170 printf (_("TIME %s - %lu second time difference|%s %s\n"), 163 printf(_("TIME %s - %lu second time difference|%s %s\n"), state_text(result), diff_time,
171 state_text (result), diff_time, 164 perfdata("time", (long)conntime, "s", config.check_warning_time,
172 perfdata ("time", (long)conntime, "s", 165 (long)config.warning_time, config.check_critical_time,
173 check_warning_time, (long)warning_time, 166 (long)config.critical_time, true, 0, false, 0),
174 check_critical_time, (long)critical_time, 167 perfdata("offset", diff_time, "s", config.check_warning_diff, config.warning_diff,
175 true, 0, false, 0), 168 config.check_critical_diff, config.critical_diff, 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; 169 return result;
181} 170}
182 171
183
184
185/* process command-line arguments */ 172/* process command-line arguments */
186int 173check_time_config_wrapper process_arguments(int argc, char **argv) {
187process_arguments (int argc, char **argv) 174 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
188{ 175 {"warning-variance", required_argument, 0, 'w'},
189 int c; 176 {"critical-variance", required_argument, 0, 'c'},
190 177 {"warning-connect", required_argument, 0, 'W'},
191 int option = 0; 178 {"critical-connect", required_argument, 0, 'C'},
192 static struct option longopts[] = { 179 {"port", required_argument, 0, 'p'},
193 {"hostname", required_argument, 0, 'H'}, 180 {"udp", no_argument, 0, 'u'},
194 {"warning-variance", required_argument, 0, 'w'}, 181 {"timeout", required_argument, 0, 't'},
195 {"critical-variance", required_argument, 0, 'c'}, 182 {"version", no_argument, 0, 'V'},
196 {"warning-connect", required_argument, 0, 'W'}, 183 {"help", no_argument, 0, 'h'},
197 {"critical-connect", required_argument, 0, 'C'}, 184 {0, 0, 0, 0}};
198 {"port", required_argument, 0, 'p'}, 185
199 {"udp", no_argument, 0, 'u'}, 186 if (argc < 2) {
200 {"timeout", required_argument, 0, 't'}, 187 usage("\n");
201 {"version", no_argument, 0, 'V'}, 188 }
202 {"help", no_argument, 0, 'h'},
203 {0, 0, 0, 0}
204 };
205 189
206 if (argc < 2) 190 for (int i = 1; i < argc; i++) {
207 usage ("\n"); 191 if (strcmp("-to", argv[i]) == 0) {
208 192 strcpy(argv[i], "-t");
209 for (c = 1; c < argc; c++) { 193 } else if (strcmp("-wd", argv[i]) == 0) {
210 if (strcmp ("-to", argv[c]) == 0) 194 strcpy(argv[i], "-w");
211 strcpy (argv[c], "-t"); 195 } else if (strcmp("-cd", argv[i]) == 0) {
212 else if (strcmp ("-wd", argv[c]) == 0) 196 strcpy(argv[i], "-c");
213 strcpy (argv[c], "-w"); 197 } else if (strcmp("-wt", argv[i]) == 0) {
214 else if (strcmp ("-cd", argv[c]) == 0) 198 strcpy(argv[i], "-W");
215 strcpy (argv[c], "-c"); 199 } else if (strcmp("-ct", argv[i]) == 0) {
216 else if (strcmp ("-wt", argv[c]) == 0) 200 strcpy(argv[i], "-C");
217 strcpy (argv[c], "-W"); 201 }
218 else if (strcmp ("-ct", argv[c]) == 0)
219 strcpy (argv[c], "-C");
220 } 202 }
221 203
204 check_time_config_wrapper result = {
205 .errorcode = OK,
206 .config = check_time_config_init(),
207 };
208
209 int option_char;
222 while (true) { 210 while (true) {
223 c = getopt_long (argc, argv, "hVH:w:c:W:C:p:t:u", longopts, 211 int option = 0;
224 &option); 212 option_char = getopt_long(argc, argv, "hVH:w:c:W:C:p:t:u", longopts, &option);
225 213
226 if (c == -1 || c == EOF) 214 if (option_char == -1 || option_char == EOF) {
227 break; 215 break;
216 }
228 217
229 switch (c) { 218 switch (option_char) {
230 case '?': /* print short usage statement if args not parsable */ 219 case '?': /* print short usage statement if args not parsable */
231 usage5 (); 220 usage5();
232 case 'h': /* help */ 221 case 'h': /* help */
233 print_help (); 222 print_help();
234 exit (STATE_UNKNOWN); 223 exit(STATE_UNKNOWN);
235 case 'V': /* version */ 224 case 'V': /* version */
236 print_revision (progname, NP_VERSION); 225 print_revision(progname, NP_VERSION);
237 exit (STATE_UNKNOWN); 226 exit(STATE_UNKNOWN);
238 case 'H': /* hostname */ 227 case 'H': /* hostname */
239 if (!is_host (optarg)) 228 if (!is_host(optarg)) {
240 usage2 (_("Invalid hostname/address"), optarg); 229 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 } 230 }
248 else if (strspn (optarg, "0123456789:,") > 0) { 231 result.config.server_address = optarg;
249 if (sscanf (optarg, "%lu%*[:,]%d", &warning_diff, &warning_time) == 2) { 232 break;
250 check_warning_diff = true; 233 case 'w': /* warning-variance */
251 check_warning_time = true; 234 if (is_intnonneg(optarg)) {
252 } 235 result.config.warning_diff = strtoul(optarg, NULL, 10);
253 else { 236 result.config.check_warning_diff = true;
254 usage4 (_("Warning thresholds must be a positive integer")); 237 } else if (strspn(optarg, "0123456789:,") > 0) {
238 if (sscanf(optarg, "%lu%*[:,]%d", &result.config.warning_diff,
239 &result.config.warning_time) == 2) {
240 result.config.check_warning_diff = true;
241 result.config.check_warning_time = true;
242 } else {
243 usage4(_("Warning thresholds must be a positive integer"));
255 } 244 }
256 } 245 } else {
257 else { 246 usage4(_("Warning threshold must be a positive integer"));
258 usage4 (_("Warning threshold must be a positive integer"));
259 } 247 }
260 break; 248 break;
261 case 'c': /* critical-variance */ 249 case 'c': /* critical-variance */
262 if (is_intnonneg (optarg)) { 250 if (is_intnonneg(optarg)) {
263 critical_diff = strtoul (optarg, NULL, 10); 251 result.config.critical_diff = strtoul(optarg, NULL, 10);
264 check_critical_diff = true; 252 result.config.check_critical_diff = true;
265 } 253 } else if (strspn(optarg, "0123456789:,") > 0) {
266 else if (strspn (optarg, "0123456789:,") > 0) { 254 if (sscanf(optarg, "%lu%*[:,]%d", &result.config.critical_diff,
267 if (sscanf (optarg, "%lu%*[:,]%d", &critical_diff, &critical_time) == 255 &result.config.critical_time) == 2) {
268 2) { 256 result.config.check_critical_diff = true;
269 check_critical_diff = true; 257 result.config.check_critical_time = true;
270 check_critical_time = true; 258 } else {
271 } 259 usage4(_("Critical thresholds must be a positive integer"));
272 else {
273 usage4 (_("Critical thresholds must be a positive integer"));
274 } 260 }
275 } 261 } else {
276 else { 262 usage4(_("Critical threshold must be a positive integer"));
277 usage4 (_("Critical threshold must be a positive integer"));
278 } 263 }
279 break; 264 break;
280 case 'W': /* warning-connect */ 265 case 'W': /* warning-connect */
281 if (!is_intnonneg (optarg)) 266 if (!is_intnonneg(optarg)) {
282 usage4 (_("Warning threshold must be a positive integer")); 267 usage4(_("Warning threshold must be a positive integer"));
283 else 268 } else {
284 warning_time = atoi (optarg); 269 result.config.warning_time = atoi(optarg);
285 check_warning_time = true; 270 }
271 result.config.check_warning_time = true;
286 break; 272 break;
287 case 'C': /* critical-connect */ 273 case 'C': /* critical-connect */
288 if (!is_intnonneg (optarg)) 274 if (!is_intnonneg(optarg)) {
289 usage4 (_("Critical threshold must be a positive integer")); 275 usage4(_("Critical threshold must be a positive integer"));
290 else 276 } else {
291 critical_time = atoi (optarg); 277 result.config.critical_time = atoi(optarg);
292 check_critical_time = true; 278 }
279 result.config.check_critical_time = true;
293 break; 280 break;
294 case 'p': /* port */ 281 case 'p': /* port */
295 if (!is_intnonneg (optarg)) 282 if (!is_intnonneg(optarg)) {
296 usage4 (_("Port must be a positive integer")); 283 usage4(_("Port must be a positive integer"));
297 else 284 } else {
298 server_port = atoi (optarg); 285 result.config.server_port = atoi(optarg);
286 }
299 break; 287 break;
300 case 't': /* timeout */ 288 case 't': /* timeout */
301 if (!is_intnonneg (optarg)) 289 if (!is_intnonneg(optarg)) {
302 usage2 (_("Timeout interval must be a positive integer"), optarg); 290 usage2(_("Timeout interval must be a positive integer"), optarg);
303 else 291 } else {
304 socket_timeout = atoi (optarg); 292 socket_timeout = atoi(optarg);
293 }
305 break; 294 break;
306 case 'u': /* udp */ 295 case 'u': /* udp */
307 use_udp = true; 296 result.config.use_udp = true;
308 } 297 }
309 } 298 }
310 299
311 c = optind; 300 option_char = optind;
312 if (server_address == NULL) { 301 if (result.config.server_address == NULL) {
313 if (argc > c) { 302 if (argc > option_char) {
314 if (!is_host (argv[c])) 303 if (!is_host(argv[option_char])) {
315 usage2 (_("Invalid hostname/address"), optarg); 304 usage2(_("Invalid hostname/address"), optarg);
316 server_address = argv[c]; 305 }
317 } 306 result.config.server_address = argv[option_char];
318 else { 307 } else {
319 usage4 (_("Hostname was not supplied")); 308 usage4(_("Hostname was not supplied"));
320 } 309 }
321 } 310 }
322 311
323 return OK; 312 return result;
324} 313}
325 314
326 315void print_help(void) {
327
328void
329print_help (void)
330{
331 char *myport; 316 char *myport;
332 xasprintf (&myport, "%d", TIME_PORT); 317 xasprintf(&myport, "%d", TIME_PORT);
333 318
334 print_revision (progname, NP_VERSION); 319 print_revision(progname, NP_VERSION);
335 320
336 printf ("Copyright (c) 1999 Ethan Galstad\n"); 321 printf("Copyright (c) 1999 Ethan Galstad\n");
337 printf (COPYRIGHT, copyright, email); 322 printf(COPYRIGHT, copyright, email);
338 323
339 printf ("%s\n", _("This plugin will check the time on the specified host.")); 324 printf("%s\n", _("This plugin will check the time on the specified host."));
340 325
341 printf ("\n\n"); 326 printf("\n\n");
342 327
343 print_usage (); 328 print_usage();
344 329
345 printf (UT_HELP_VRSN); 330 printf(UT_HELP_VRSN);
346 printf (UT_EXTRA_OPTS); 331 printf(UT_EXTRA_OPTS);
347 332
348 printf (UT_HOST_PORT, 'p', myport); 333 printf(UT_HOST_PORT, 'p', myport);
349 334
350 printf (" %s\n", "-u, --udp"); 335 printf(" %s\n", "-u, --udp");
351 printf (" %s\n", _("Use UDP to connect, not TCP")); 336 printf(" %s\n", _("Use UDP to connect, not TCP"));
352 printf (" %s\n", "-w, --warning-variance=INTEGER"); 337 printf(" %s\n", "-w, --warning-variance=INTEGER");
353 printf (" %s\n", _("Time difference (sec.) necessary to result in a warning status")); 338 printf(" %s\n", _("Time difference (sec.) necessary to result in a warning status"));
354 printf (" %s\n", "-c, --critical-variance=INTEGER"); 339 printf(" %s\n", "-c, --critical-variance=INTEGER");
355 printf (" %s\n", _("Time difference (sec.) necessary to result in a critical status")); 340 printf(" %s\n", _("Time difference (sec.) necessary to result in a critical status"));
356 printf (" %s\n", "-W, --warning-connect=INTEGER"); 341 printf(" %s\n", "-W, --warning-connect=INTEGER");
357 printf (" %s\n", _("Response time (sec.) necessary to result in warning status")); 342 printf(" %s\n", _("Response time (sec.) necessary to result in warning status"));
358 printf (" %s\n", "-C, --critical-connect=INTEGER"); 343 printf(" %s\n", "-C, --critical-connect=INTEGER");
359 printf (" %s\n", _("Response time (sec.) necessary to result in critical status")); 344 printf(" %s\n", _("Response time (sec.) necessary to result in critical status"));
360 345
361 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 346 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
362 347
363 printf (UT_SUPPORT); 348 printf(UT_SUPPORT);
364} 349}
365 350
366 351void print_usage(void) {
367 352 printf("%s\n", _("Usage:"));
368void 353 printf("%s -H <host_address> [-p port] [-u] [-w variance] [-c variance]\n", progname);
369print_usage (void) 354 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} 355}
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..54decce3 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,76 @@ 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)) ==
155 (UPSSTATUS_OB | UPSSTATUS_LB)) { 110 (UPSSTATUS_OB | UPSSTATUS_LB)) {
156 xasprintf(&ups_status, _("On Battery, Low Battery")); 111 xasprintf(&ups_status, _("On Battery, Low Battery"));
157 result = STATE_CRITICAL; 112 result = STATE_CRITICAL;
158 } else { 113 } else {
159 if (config.status & UPSSTATUS_OL) { 114 if (ups_status_flags & UPSSTATUS_OL) {
160 xasprintf(&ups_status, "%s%s", ups_status, _("Online")); 115 xasprintf(&ups_status, "%s%s", ups_status, _("Online"));
161 } 116 }
162 if (config.status & UPSSTATUS_OB) { 117 if (ups_status_flags & UPSSTATUS_OB) {
163 xasprintf(&ups_status, "%s%s", ups_status, _("On Battery")); 118 xasprintf(&ups_status, "%s%s", ups_status, _("On Battery"));
164 result = max_state(result, STATE_WARNING); 119 result = max_state(result, STATE_WARNING);
165 } 120 }
166 if (config.status & UPSSTATUS_LB) { 121 if (ups_status_flags & UPSSTATUS_LB) {
167 xasprintf(&ups_status, "%s%s", ups_status, _(", Low Battery")); 122 xasprintf(&ups_status, "%s%s", ups_status, _(", Low Battery"));
168 result = max_state(result, STATE_WARNING); 123 result = max_state(result, STATE_WARNING);
169 } 124 }
170 if (config.status & UPSSTATUS_CAL) { 125 if (ups_status_flags & UPSSTATUS_CAL) {
171 xasprintf(&ups_status, "%s%s", ups_status, _(", Calibrating")); 126 xasprintf(&ups_status, "%s%s", ups_status, _(", Calibrating"));
172 } 127 }
173 if (config.status & UPSSTATUS_RB) { 128 if (ups_status_flags & UPSSTATUS_RB) {
174 xasprintf(&ups_status, "%s%s", ups_status, 129 xasprintf(&ups_status, "%s%s", ups_status, _(", Replace Battery"));
175 _(", Replace Battery"));
176 result = max_state(result, STATE_WARNING); 130 result = max_state(result, STATE_WARNING);
177 } 131 }
178 if (config.status & UPSSTATUS_BYPASS) { 132 if (ups_status_flags & UPSSTATUS_BYPASS) {
179 xasprintf(&ups_status, "%s%s", ups_status, _(", On Bypass")); 133 xasprintf(&ups_status, "%s%s", ups_status, _(", On Bypass"));
180 // Bypassing the battery is likely a bad thing 134 // Bypassing the battery is likely a bad thing
181 result = STATE_CRITICAL; 135 result = STATE_CRITICAL;
182 } 136 }
183 if (config.status & UPSSTATUS_OVER) { 137 if (ups_status_flags & UPSSTATUS_OVER) {
184 xasprintf(&ups_status, "%s%s", ups_status, _(", Overload")); 138 xasprintf(&ups_status, "%s%s", ups_status, _(", Overload"));
185 result = max_state(result, STATE_WARNING); 139 result = max_state(result, STATE_WARNING);
186 } 140 }
187 if (config.status & UPSSTATUS_TRIM) { 141 if (ups_status_flags & UPSSTATUS_TRIM) {
188 xasprintf(&ups_status, "%s%s", ups_status, _(", Trimming")); 142 xasprintf(&ups_status, "%s%s", ups_status, _(", Trimming"));
189 } 143 }
190 if (config.status & UPSSTATUS_BOOST) { 144 if (ups_status_flags & UPSSTATUS_BOOST) {
191 xasprintf(&ups_status, "%s%s", ups_status, _(", Boosting")); 145 xasprintf(&ups_status, "%s%s", ups_status, _(", Boosting"));
192 } 146 }
193 if (config.status & UPSSTATUS_CHRG) { 147 if (ups_status_flags & UPSSTATUS_CHRG) {
194 xasprintf(&ups_status, "%s%s", ups_status, _(", Charging")); 148 xasprintf(&ups_status, "%s%s", ups_status, _(", Charging"));
195 } 149 }
196 if (config.status & UPSSTATUS_DISCHRG) { 150 if (ups_status_flags & UPSSTATUS_DISCHRG) {
197 xasprintf(&ups_status, "%s%s", ups_status, _(", Discharging")); 151 xasprintf(&ups_status, "%s%s", ups_status, _(", Discharging"));
198 result = max_state(result, STATE_WARNING); 152 result = max_state(result, STATE_WARNING);
199 } 153 }
200 if (config.status & UPSSTATUS_ALARM) { 154 if (ups_status_flags & UPSSTATUS_ALARM) {
201 xasprintf(&ups_status, "%s%s", ups_status, _(", ALARM")); 155 xasprintf(&ups_status, "%s%s", ups_status, _(", ALARM"));
202 result = STATE_CRITICAL; 156 result = STATE_CRITICAL;
203 } 157 }
204 if (config.status & UPSSTATUS_UNKNOWN) { 158 if (ups_status_flags & UPSSTATUS_UNKNOWN) {
205 xasprintf(&ups_status, "%s%s", ups_status, _(", Unknown")); 159 xasprintf(&ups_status, "%s%s", ups_status, _(", Unknown"));
206 } 160 }
207 } 161 }
@@ -210,7 +164,7 @@ int main(int argc, char **argv) {
210 164
211 int res; 165 int res;
212 char temp_buffer[MAX_INPUT_BUFFER]; 166 char temp_buffer[MAX_INPUT_BUFFER];
213 167 char *performance_data = strdup("");
214 /* get the ups utility voltage if possible */ 168 /* get the ups utility voltage if possible */
215 res = get_ups_variable("input.voltage", temp_buffer, config); 169 res = get_ups_variable("input.voltage", temp_buffer, config);
216 if (res == NOSUCHVAR) { 170 if (res == NOSUCHVAR) {
@@ -233,24 +187,20 @@ int main(int argc, char **argv) {
233 } 187 }
234 188
235 if (config.check_variable == UPS_UTILITY) { 189 if (config.check_variable == UPS_UTILITY) {
236 if (config.check_crit && 190 if (config.check_crit && ups_utility_deviation >= config.critical_value) {
237 ups_utility_deviation >= config.critical_value) {
238 result = STATE_CRITICAL; 191 result = STATE_CRITICAL;
239 } else if (config.check_warn && 192 } 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); 193 result = max_state(result, STATE_WARNING);
242 } 194 }
243 xasprintf(&data, "%s", 195 xasprintf(&performance_data, "%s",
244 perfdata("voltage", (long)(1000 * ups_utility_voltage), 196 perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV",
245 "mV", config.check_warn, 197 config.check_warn, (long)(1000 * config.warning_value),
246 (long)(1000 * config.warning_value), 198 config.check_crit, (long)(1000 * config.critical_value), true, 0,
247 config.check_crit,
248 (long)(1000 * config.critical_value), true, 0,
249 false, 0)); 199 false, 0));
250 } else { 200 } else {
251 xasprintf(&data, "%s", 201 xasprintf(&performance_data, "%s",
252 perfdata("voltage", (long)(1000 * ups_utility_voltage), 202 perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", false, 0, false,
253 "mV", false, 0, false, 0, true, 0, false, 0)); 203 0, true, 0, false, 0));
254 } 204 }
255 } 205 }
256 206
@@ -268,22 +218,19 @@ int main(int argc, char **argv) {
268 xasprintf(&message, "%sBatt=%3.1f%% ", message, ups_battery_percent); 218 xasprintf(&message, "%sBatt=%3.1f%% ", message, ups_battery_percent);
269 219
270 if (config.check_variable == UPS_BATTPCT) { 220 if (config.check_variable == UPS_BATTPCT) {
271 if (config.check_crit && 221 if (config.check_crit && ups_battery_percent <= config.critical_value) {
272 ups_battery_percent <= config.critical_value) {
273 result = STATE_CRITICAL; 222 result = STATE_CRITICAL;
274 } else if (config.check_warn && 223 } 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); 224 result = max_state(result, STATE_WARNING);
277 } 225 }
278 xasprintf(&data, "%s %s", data, 226 xasprintf(&performance_data, "%s %s", performance_data,
279 perfdata("battery", (long)ups_battery_percent, "%", 227 perfdata("battery", (long)ups_battery_percent, "%", config.check_warn,
280 config.check_warn, (long)(config.warning_value), 228 (long)(config.warning_value), config.check_crit,
281 config.check_crit, (long)(config.critical_value), 229 (long)(config.critical_value), true, 0, true, 100));
282 true, 0, true, 100));
283 } else { 230 } else {
284 xasprintf(&data, "%s %s", data, 231 xasprintf(&performance_data, "%s %s", performance_data,
285 perfdata("battery", (long)ups_battery_percent, "%", false, 232 perfdata("battery", (long)ups_battery_percent, "%", false, 0, false, 0, true,
286 0, false, 0, true, 0, true, 100)); 233 0, true, 100));
287 } 234 }
288 } 235 }
289 236
@@ -301,22 +248,19 @@ int main(int argc, char **argv) {
301 xasprintf(&message, "%sLoad=%3.1f%% ", message, ups_load_percent); 248 xasprintf(&message, "%sLoad=%3.1f%% ", message, ups_load_percent);
302 249
303 if (config.check_variable == UPS_LOADPCT) { 250 if (config.check_variable == UPS_LOADPCT) {
304 if (config.check_crit && 251 if (config.check_crit && ups_load_percent >= config.critical_value) {
305 ups_load_percent >= config.critical_value) {
306 result = STATE_CRITICAL; 252 result = STATE_CRITICAL;
307 } else if (config.check_warn && 253 } 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); 254 result = max_state(result, STATE_WARNING);
310 } 255 }
311 xasprintf(&data, "%s %s", data, 256 xasprintf(&performance_data, "%s %s", performance_data,
312 perfdata("load", (long)ups_load_percent, "%", 257 perfdata("load", (long)ups_load_percent, "%", config.check_warn,
313 config.check_warn, (long)(config.warning_value), 258 (long)(config.warning_value), config.check_crit,
314 config.check_crit, (long)(config.critical_value), 259 (long)(config.critical_value), true, 0, true, 100));
315 true, 0, true, 100));
316 } else { 260 } else {
317 xasprintf(&data, "%s %s", data, 261 xasprintf(&performance_data, "%s %s", performance_data,
318 perfdata("load", (long)ups_load_percent, "%", false, 0, 262 perfdata("load", (long)ups_load_percent, "%", false, 0, false, 0, true, 0,
319 false, 0, true, 0, true, 100)); 263 true, 100));
320 } 264 }
321 } 265 }
322 266
@@ -345,19 +289,17 @@ int main(int argc, char **argv) {
345 if (config.check_variable == UPS_TEMP) { 289 if (config.check_variable == UPS_TEMP) {
346 if (config.check_crit && ups_temperature >= config.critical_value) { 290 if (config.check_crit && ups_temperature >= config.critical_value) {
347 result = STATE_CRITICAL; 291 result = STATE_CRITICAL;
348 } else if (config.check_warn && 292 } else if (config.check_warn && ups_temperature >= config.warning_value) {
349 ups_temperature >= config.warning_value) {
350 result = max_state(result, STATE_WARNING); 293 result = max_state(result, STATE_WARNING);
351 } 294 }
352 xasprintf(&data, "%s %s", data, 295 xasprintf(&performance_data, "%s %s", performance_data,
353 perfdata("temp", (long)ups_temperature, tunits, 296 perfdata("temp", (long)ups_temperature, tunits, config.check_warn,
354 config.check_warn, (long)(config.warning_value), 297 (long)(config.warning_value), config.check_crit,
355 config.check_crit, (long)(config.critical_value), 298 (long)(config.critical_value), true, 0, false, 0));
356 true, 0, false, 0));
357 } else { 299 } else {
358 xasprintf(&data, "%s %s", data, 300 xasprintf(&performance_data, "%s %s", performance_data,
359 perfdata("temp", (long)ups_temperature, tunits, false, 0, 301 perfdata("temp", (long)ups_temperature, tunits, false, 0, false, 0, true, 0,
360 false, 0, true, 0, false, 0)); 302 false, 0));
361 } 303 }
362 } 304 }
363 305
@@ -376,19 +318,17 @@ int main(int argc, char **argv) {
376 if (config.check_variable == UPS_REALPOWER) { 318 if (config.check_variable == UPS_REALPOWER) {
377 if (config.check_crit && ups_realpower >= config.critical_value) { 319 if (config.check_crit && ups_realpower >= config.critical_value) {
378 result = STATE_CRITICAL; 320 result = STATE_CRITICAL;
379 } else if (config.check_warn && 321 } else if (config.check_warn && ups_realpower >= config.warning_value) {
380 ups_realpower >= config.warning_value) {
381 result = max_state(result, STATE_WARNING); 322 result = max_state(result, STATE_WARNING);
382 } 323 }
383 xasprintf(&data, "%s %s", data, 324 xasprintf(&performance_data, "%s %s", performance_data,
384 perfdata("realpower", (long)ups_realpower, "W", 325 perfdata("realpower", (long)ups_realpower, "W", config.check_warn,
385 config.check_warn, (long)(config.warning_value), 326 (long)(config.warning_value), config.check_crit,
386 config.check_crit, (long)(config.critical_value), 327 (long)(config.critical_value), true, 0, false, 0));
387 true, 0, false, 0));
388 } else { 328 } else {
389 xasprintf(&data, "%s %s", data, 329 xasprintf(&performance_data, "%s %s", performance_data,
390 perfdata("realpower", (long)ups_realpower, "W", false, 0, 330 perfdata("realpower", (long)ups_realpower, "W", false, 0, false, 0, true, 0,
391 false, 0, true, 0, false, 0)); 331 false, 0));
392 } 332 }
393 } 333 }
394 334
@@ -402,73 +342,79 @@ int main(int argc, char **argv) {
402 /* reset timeout */ 342 /* reset timeout */
403 alarm(0); 343 alarm(0);
404 344
405 printf("UPS %s - %s|%s\n", state_text(result), message, data); 345 printf("UPS %s - %s|%s\n", state_text(result), message, performance_data);
406 return result; 346 exit(result);
407} 347}
408 348
409/* determines what options are supported by the UPS */ 349/* determines what options are supported by the UPS */
410int determine_status(ups_config *config, int *supported_options) { 350determine_status_result determine_status(const check_ups_config config) {
411 char recv_buffer[MAX_INPUT_BUFFER]; 351
352 determine_status_result result = {
353 .errorcode = OK,
354 .ups_status = UPSSTATUS_NONE,
355 .supported_options = 0,
356 };
412 357
413 int res = get_ups_variable("ups.status", recv_buffer, *config); 358 char recv_buffer[MAX_INPUT_BUFFER];
359 int res = get_ups_variable("ups.status", recv_buffer, config);
414 if (res == NOSUCHVAR) { 360 if (res == NOSUCHVAR) {
415 return OK; 361 return result;
416 } 362 }
417 363
418 if (res != STATE_OK) { 364 if (res != STATE_OK) {
419 printf("%s\n", _("Invalid response received from host")); 365 printf("%s\n", _("Invalid response received from host"));
420 return ERROR; 366 result.errorcode = ERROR;
367 return result;
421 } 368 }
422 369
423 *supported_options |= UPS_STATUS; 370 result.supported_options |= UPS_STATUS;
424 371
425 char temp_buffer[MAX_INPUT_BUFFER]; 372 char temp_buffer[MAX_INPUT_BUFFER];
426 373
427 strcpy(temp_buffer, recv_buffer); 374 strcpy(temp_buffer, recv_buffer);
428 for (char *ptr = (char *)strtok(temp_buffer, " "); ptr != NULL; 375 for (char *ptr = strtok(temp_buffer, " "); ptr != NULL; ptr = strtok(NULL, " ")) {
429 ptr = (char *)strtok(NULL, " ")) {
430 if (!strcmp(ptr, "OFF")) { 376 if (!strcmp(ptr, "OFF")) {
431 config->status |= UPSSTATUS_OFF; 377 result.ups_status |= UPSSTATUS_OFF;
432 } else if (!strcmp(ptr, "OL")) { 378 } else if (!strcmp(ptr, "OL")) {
433 config->status |= UPSSTATUS_OL; 379 result.ups_status |= UPSSTATUS_OL;
434 } else if (!strcmp(ptr, "OB")) { 380 } else if (!strcmp(ptr, "OB")) {
435 config->status |= UPSSTATUS_OB; 381 result.ups_status |= UPSSTATUS_OB;
436 } else if (!strcmp(ptr, "LB")) { 382 } else if (!strcmp(ptr, "LB")) {
437 config->status |= UPSSTATUS_LB; 383 result.ups_status |= UPSSTATUS_LB;
438 } else if (!strcmp(ptr, "CAL")) { 384 } else if (!strcmp(ptr, "CAL")) {
439 config->status |= UPSSTATUS_CAL; 385 result.ups_status |= UPSSTATUS_CAL;
440 } else if (!strcmp(ptr, "RB")) { 386 } else if (!strcmp(ptr, "RB")) {
441 config->status |= UPSSTATUS_RB; 387 result.ups_status |= UPSSTATUS_RB;
442 } else if (!strcmp(ptr, "BYPASS")) { 388 } else if (!strcmp(ptr, "BYPASS")) {
443 config->status |= UPSSTATUS_BYPASS; 389 result.ups_status |= UPSSTATUS_BYPASS;
444 } else if (!strcmp(ptr, "OVER")) { 390 } else if (!strcmp(ptr, "OVER")) {
445 config->status |= UPSSTATUS_OVER; 391 result.ups_status |= UPSSTATUS_OVER;
446 } else if (!strcmp(ptr, "TRIM")) { 392 } else if (!strcmp(ptr, "TRIM")) {
447 config->status |= UPSSTATUS_TRIM; 393 result.ups_status |= UPSSTATUS_TRIM;
448 } else if (!strcmp(ptr, "BOOST")) { 394 } else if (!strcmp(ptr, "BOOST")) {
449 config->status |= UPSSTATUS_BOOST; 395 result.ups_status |= UPSSTATUS_BOOST;
450 } else if (!strcmp(ptr, "CHRG")) { 396 } else if (!strcmp(ptr, "CHRG")) {
451 config->status |= UPSSTATUS_CHRG; 397 result.ups_status |= UPSSTATUS_CHRG;
452 } else if (!strcmp(ptr, "DISCHRG")) { 398 } else if (!strcmp(ptr, "DISCHRG")) {
453 config->status |= UPSSTATUS_DISCHRG; 399 result.ups_status |= UPSSTATUS_DISCHRG;
454 } else if (!strcmp(ptr, "ALARM")) { 400 } else if (!strcmp(ptr, "ALARM")) {
455 config->status |= UPSSTATUS_ALARM; 401 result.ups_status |= UPSSTATUS_ALARM;
456 } else { 402 } else {
457 config->status |= UPSSTATUS_UNKNOWN; 403 result.ups_status |= UPSSTATUS_UNKNOWN;
458 } 404 }
459 } 405 }
460 406
461 return OK; 407 return result;
462} 408}
463 409
464/* gets a variable value for a specific UPS */ 410/* gets a variable value for a specific UPS */
465int get_ups_variable(const char *varname, char *buf, const ups_config config) { 411int get_ups_variable(const char *varname, char *buf, const check_ups_config config) {
466 char send_buffer[MAX_INPUT_BUFFER]; 412 char send_buffer[MAX_INPUT_BUFFER];
467 413
468 /* create the command string to send to the UPS daemon */ 414 /* create the command string to send to the UPS daemon */
469 /* Add LOGOUT to avoid read failure logs */ 415 /* Add LOGOUT to avoid read failure logs */
470 int res = snprintf(send_buffer, sizeof(send_buffer), 416 int res = snprintf(send_buffer, sizeof(send_buffer), "GET VAR %s %s\nLOGOUT\n", config.ups_name,
471 "GET VAR %s %s\nLOGOUT\n", config.ups_name, varname); 417 varname);
472 if ((res > 0) && ((size_t)res >= sizeof(send_buffer))) { 418 if ((res > 0) && ((size_t)res >= sizeof(send_buffer))) {
473 printf("%s\n", _("UPS name to long for buffer")); 419 printf("%s\n", _("UPS name to long for buffer"));
474 return ERROR; 420 return ERROR;
@@ -477,8 +423,7 @@ int get_ups_variable(const char *varname, char *buf, const ups_config config) {
477 char temp_buffer[MAX_INPUT_BUFFER]; 423 char temp_buffer[MAX_INPUT_BUFFER];
478 424
479 /* send the command to the daemon and get a response back */ 425 /* send the command to the daemon and get a response back */
480 if (process_tcp_request(config.server_address, config.server_port, 426 if (process_tcp_request(config.server_address, config.server_port, send_buffer, temp_buffer,
481 send_buffer, temp_buffer,
482 sizeof(temp_buffer)) != STATE_OK) { 427 sizeof(temp_buffer)) != STATE_OK) {
483 printf("%s\n", _("Invalid response received from host")); 428 printf("%s\n", _("Invalid response received from host"));
484 return ERROR; 429 return ERROR;
@@ -496,8 +441,7 @@ int get_ups_variable(const char *varname, char *buf, const ups_config config) {
496 ptr[len - 1] = 0; 441 ptr[len - 1] = 0;
497 } 442 }
498 if (strcmp(ptr, "ERR UNKNOWN-UPS") == 0) { 443 if (strcmp(ptr, "ERR UNKNOWN-UPS") == 0) {
499 printf(_("CRITICAL - no such UPS '%s' on that host\n"), 444 printf(_("CRITICAL - no such UPS '%s' on that host\n"), config.ups_name);
500 config.ups_name);
501 return ERROR; 445 return ERROR;
502 } 446 }
503 447
@@ -534,7 +478,7 @@ int get_ups_variable(const char *varname, char *buf, const ups_config config) {
534 [-wv warn_value] [-cv crit_value] [-to to_sec] */ 478 [-wv warn_value] [-cv crit_value] [-to to_sec] */
535 479
536/* process command-line arguments */ 480/* process command-line arguments */
537int process_arguments(int argc, char **argv, ups_config *config) { 481check_ups_config_wrapper process_arguments(int argc, char **argv) {
538 482
539 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 483 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
540 {"ups", required_argument, 0, 'u'}, 484 {"ups", required_argument, 0, 'u'},
@@ -548,8 +492,14 @@ int process_arguments(int argc, char **argv, ups_config *config) {
548 {"help", no_argument, 0, 'h'}, 492 {"help", no_argument, 0, 'h'},
549 {0, 0, 0, 0}}; 493 {0, 0, 0, 0}};
550 494
495 check_ups_config_wrapper result = {
496 .errorcode = OK,
497 .config = check_ups_config_init(),
498 };
499
551 if (argc < 2) { 500 if (argc < 2) {
552 return ERROR; 501 result.errorcode = ERROR;
502 return result;
553 } 503 }
554 504
555 int c; 505 int c;
@@ -576,52 +526,52 @@ int process_arguments(int argc, char **argv, ups_config *config) {
576 usage5(); 526 usage5();
577 case 'H': /* hostname */ 527 case 'H': /* hostname */
578 if (is_host(optarg)) { 528 if (is_host(optarg)) {
579 config->server_address = optarg; 529 result.config.server_address = optarg;
580 } else { 530 } else {
581 usage2(_("Invalid hostname/address"), optarg); 531 usage2(_("Invalid hostname/address"), optarg);
582 } 532 }
583 break; 533 break;
584 case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for 534 case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for
585 Fahrenheit) */ 535 Fahrenheit) */
586 config->temp_output_c = true; 536 result.config.temp_output_c = true;
587 break; 537 break;
588 case 'u': /* ups name */ 538 case 'u': /* ups name */
589 config->ups_name = optarg; 539 result.config.ups_name = optarg;
590 break; 540 break;
591 case 'p': /* port */ 541 case 'p': /* port */
592 if (is_intpos(optarg)) { 542 if (is_intpos(optarg)) {
593 config->server_port = atoi(optarg); 543 result.config.server_port = atoi(optarg);
594 } else { 544 } else {
595 usage2(_("Port must be a positive integer"), optarg); 545 usage2(_("Port must be a positive integer"), optarg);
596 } 546 }
597 break; 547 break;
598 case 'c': /* critical time threshold */ 548 case 'c': /* critical time threshold */
599 if (is_intnonneg(optarg)) { 549 if (is_intnonneg(optarg)) {
600 config->critical_value = atoi(optarg); 550 result.config.critical_value = atoi(optarg);
601 config->check_crit = true; 551 result.config.check_crit = true;
602 } else { 552 } else {
603 usage2(_("Critical time must be a positive integer"), optarg); 553 usage2(_("Critical time must be a positive integer"), optarg);
604 } 554 }
605 break; 555 break;
606 case 'w': /* warning time threshold */ 556 case 'w': /* warning time threshold */
607 if (is_intnonneg(optarg)) { 557 if (is_intnonneg(optarg)) {
608 config->warning_value = atoi(optarg); 558 result.config.warning_value = atoi(optarg);
609 config->check_warn = true; 559 result.config.check_warn = true;
610 } else { 560 } else {
611 usage2(_("Warning time must be a positive integer"), optarg); 561 usage2(_("Warning time must be a positive integer"), optarg);
612 } 562 }
613 break; 563 break;
614 case 'v': /* variable */ 564 case 'v': /* variable */
615 if (!strcmp(optarg, "LINE")) { 565 if (!strcmp(optarg, "LINE")) {
616 config->check_variable = UPS_UTILITY; 566 result.config.check_variable = UPS_UTILITY;
617 } else if (!strcmp(optarg, "TEMP")) { 567 } else if (!strcmp(optarg, "TEMP")) {
618 config->check_variable = UPS_TEMP; 568 result.config.check_variable = UPS_TEMP;
619 } else if (!strcmp(optarg, "BATTPCT")) { 569 } else if (!strcmp(optarg, "BATTPCT")) {
620 config->check_variable = UPS_BATTPCT; 570 result.config.check_variable = UPS_BATTPCT;
621 } else if (!strcmp(optarg, "LOADPCT")) { 571 } else if (!strcmp(optarg, "LOADPCT")) {
622 config->check_variable = UPS_LOADPCT; 572 result.config.check_variable = UPS_LOADPCT;
623 } else if (!strcmp(optarg, "REALPOWER")) { 573 } else if (!strcmp(optarg, "REALPOWER")) {
624 config->check_variable = UPS_REALPOWER; 574 result.config.check_variable = UPS_REALPOWER;
625 } else { 575 } else {
626 usage2(_("Unrecognized UPS variable"), optarg); 576 usage2(_("Unrecognized UPS variable"), optarg);
627 } 577 }
@@ -642,27 +592,27 @@ int process_arguments(int argc, char **argv, ups_config *config) {
642 } 592 }
643 } 593 }
644 594
645 if (config->server_address == NULL && argc > optind) { 595 if (result.config.server_address == NULL && argc > optind) {
646 if (is_host(argv[optind])) { 596 if (is_host(argv[optind])) {
647 config->server_address = argv[optind++]; 597 result.config.server_address = argv[optind++];
648 } else { 598 } else {
649 usage2(_("Invalid hostname/address"), optarg); 599 usage2(_("Invalid hostname/address"), optarg);
650 } 600 }
651 } 601 }
652 602
653 if (config->server_address == NULL) { 603 if (result.config.server_address == NULL) {
654 config->server_address = strdup("127.0.0.1"); 604 result.config.server_address = strdup("127.0.0.1");
655 } 605 }
656 606
657 return validate_arguments(*config); 607 return validate_arguments(result);
658} 608}
659 609
660int validate_arguments(ups_config config) { 610check_ups_config_wrapper validate_arguments(check_ups_config_wrapper config_wrapper) {
661 if (!config.ups_name) { 611 if (config_wrapper.config.ups_name) {
662 printf("%s\n", _("Error : no UPS indicated")); 612 printf("%s\n", _("Error : no UPS indicated"));
663 return ERROR; 613 config_wrapper.errorcode = ERROR;
664 } 614 }
665 return OK; 615 return config_wrapper;
666} 616}
667 617
668void print_help(void) { 618void print_help(void) {
@@ -731,8 +681,7 @@ void print_help(void) {
731 "with Russell Kroll's")); 681 "with Russell Kroll's"));
732 printf(" %s\n", _("Network UPS Tools be installed on the remote host. If " 682 printf(" %s\n", _("Network UPS Tools be installed on the remote host. If "
733 "you do not have the")); 683 "you do not have the"));
734 printf(" %s\n", 684 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")); 685 printf(" %s\n", _("http://www.networkupstools.org"));
737 686
738 printf(UT_SUPPORT); 687 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..e05edceb
--- /dev/null
+++ b/plugins/check_ups.d/config.h
@@ -0,0 +1,54 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6#define UPS_NONE 0 /* no supported options */
7#define UPS_UTILITY 1 /* supports utility line */
8#define UPS_BATTPCT 2 /* supports percent battery remaining */
9#define UPS_STATUS 4 /* supports UPS status */
10#define UPS_TEMP 8 /* supports UPS temperature */
11#define UPS_LOADPCT 16 /* supports load percent */
12#define UPS_REALPOWER 32 /* supports real power */
13
14#define UPSSTATUS_NONE 0
15#define UPSSTATUS_OFF 1
16#define UPSSTATUS_OL 2
17#define UPSSTATUS_OB 4
18#define UPSSTATUS_LB 8
19#define UPSSTATUS_CAL 16
20#define UPSSTATUS_RB 32 /*Replace Battery */
21#define UPSSTATUS_BYPASS 64
22#define UPSSTATUS_OVER 128
23#define UPSSTATUS_TRIM 256
24#define UPSSTATUS_BOOST 512
25#define UPSSTATUS_CHRG 1024
26#define UPSSTATUS_DISCHRG 2048
27#define UPSSTATUS_UNKNOWN 4096
28#define UPSSTATUS_ALARM 8192
29
30enum {
31 PORT = 3493
32};
33
34typedef struct ups_config {
35 unsigned int server_port;
36 char *server_address;
37 char *ups_name;
38 double warning_value;
39 double critical_value;
40 bool check_warn;
41 bool check_crit;
42 int check_variable;
43 bool temp_output_c;
44} check_ups_config;
45
46check_ups_config check_ups_config_init(void) {
47 check_ups_config tmp = {0};
48 tmp.server_port = PORT;
49 tmp.server_address = NULL;
50 tmp.ups_name = NULL;
51 tmp.check_variable = UPS_NONE;
52
53 return tmp;
54}
diff --git a/plugins/check_users.c b/plugins/check_users.c
index 89b95369..3b2e265e 100644
--- a/plugins/check_users.c
+++ b/plugins/check_users.c
@@ -1,282 +1,283 @@
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 "check_users.d/users.h"
38#include "utils.h" 38#include "output.h"
39#include "perfdata.h"
40#include "states.h"
41#include "utils_base.h"
42#include "./common.h"
43#include "./utils.h"
44#include "check_users.d/config.h"
45#include "thresholds.h"
39 46
40#if HAVE_WTSAPI32_H 47#if HAVE_WTSAPI32_H
41# include <windows.h> 48# include <windows.h>
42# include <wtsapi32.h> 49# include <wtsapi32.h>
43# undef ERROR 50# undef ERROR
44# define ERROR -1 51# define ERROR -1
45#elif HAVE_UTMPX_H 52#elif HAVE_UTMPX_H
46# include <utmpx.h> 53# include <utmpx.h>
47#else
48# include "popen.h"
49#endif 54#endif
50 55
51#ifdef HAVE_LIBSYSTEMD 56#ifdef HAVE_LIBSYSTEMD
52#include <systemd/sd-daemon.h> 57# include <systemd/sd-daemon.h>
53#include <systemd/sd-login.h> 58# include <systemd/sd-login.h>
54#endif 59#endif
55 60
56#define possibly_set(a,b) ((a) == 0 ? (b) : 0) 61typedef struct process_argument_wrapper {
57 62 int errorcode;
58int process_arguments (int, char **); 63 check_users_config config;
59void print_help (void); 64} check_users_config_wrapper;
60void print_usage (void); 65check_users_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
61
62char *warning_range = NULL;
63char *critical_range = NULL;
64thresholds *thlds = NULL;
65 66
66int 67void print_help(void);
67main (int argc, char **argv) 68void print_usage(void);
68{
69 int users = -1;
70 int result = STATE_UNKNOWN;
71#if HAVE_WTSAPI32_H
72 WTS_SESSION_INFO *wtsinfo;
73 DWORD wtscount;
74 DWORD index;
75#elif HAVE_UTMPX_H
76 struct utmpx *putmpx;
77#else
78 char input_buffer[MAX_INPUT_BUFFER];
79#endif
80 69
81 setlocale (LC_ALL, ""); 70int main(int argc, char **argv) {
82 bindtextdomain (PACKAGE, LOCALEDIR); 71 setlocale(LC_ALL, "");
83 textdomain (PACKAGE); 72 bindtextdomain(PACKAGE, LOCALEDIR);
73 textdomain(PACKAGE);
84 74
85 /* Parse extra opts if any */ 75 /* Parse extra opts if any */
86 argv = np_extra_opts (&argc, argv, progname); 76 argv = np_extra_opts(&argc, argv, progname);
87
88 if (process_arguments (argc, argv) == ERROR)
89 usage4 (_("Could not parse arguments"));
90 77
91 users = 0; 78 check_users_config_wrapper tmp_config = process_arguments(argc, argv);
92 79
93#ifdef HAVE_LIBSYSTEMD 80 if (tmp_config.errorcode == ERROR) {
94 if (sd_booted () > 0) 81 usage4(_("Could not parse arguments"));
95 users = sd_get_sessions (NULL);
96 else {
97#endif
98#if HAVE_WTSAPI32_H
99 if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE,
100 0, 1, &wtsinfo, &wtscount)) {
101 printf(_("Could not enumerate RD sessions: %d\n"), GetLastError());
102 return STATE_UNKNOWN;
103 } 82 }
104 83
105 for (index = 0; index < wtscount; index++) { 84 check_users_config config = tmp_config.config;
106 LPTSTR username;
107 DWORD size;
108 int len;
109
110 if (!WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,
111 wtsinfo[index].SessionId, WTSUserName, &username, &size))
112 continue;
113 85
114 len = lstrlen(username); 86#ifdef _WIN32
115 87# if HAVE_WTSAPI32_H
116 WTSFreeMemory(username); 88 get_num_of_users_wrapper user_wrapper = get_num_of_users_windows();
117 89# else
118 if (len == 0) 90# error Did not find WTSAPI32
119 continue; 91# endif // HAVE_WTSAPI32_H
120
121 if (wtsinfo[index].State == WTSActive ||
122 wtsinfo[index].State == WTSDisconnected)
123 users++;
124 }
125
126 WTSFreeMemory(wtsinfo);
127#elif HAVE_UTMPX_H
128 /* get currently logged users from utmpx */
129 setutxent ();
130
131 while ((putmpx = getutxent ()) != NULL)
132 if (putmpx->ut_type == USER_PROCESS)
133 users++;
134
135 endutxent ();
136#else 92#else
137 /* run the command */ 93# ifdef HAVE_LIBSYSTEMD
138 child_process = spopen (WHO_COMMAND); 94 get_num_of_users_wrapper user_wrapper = get_num_of_users_systemd();
139 if (child_process == NULL) { 95# elif HAVE_UTMPX_H
140 printf (_("Could not open pipe: %s\n"), WHO_COMMAND); 96 get_num_of_users_wrapper user_wrapper = get_num_of_users_utmp();
141 return STATE_UNKNOWN; 97# else // !HAVE_LIBSYSTEMD && !HAVE_UTMPX_H
98 get_num_of_users_wrapper user_wrapper = get_num_of_users_who_command();
99# endif // HAVE_LIBSYSTEMD
100#endif // _WIN32
101
102 mp_check overall = mp_check_init();
103 if (config.output_format_is_set) {
104 mp_set_format(config.output_format);
142 } 105 }
106 mp_subcheck sc_users = mp_subcheck_init();
143 107
144 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); 108 if (user_wrapper.errorcode != 0) {
145 if (child_stderr == NULL) 109 sc_users = mp_set_subcheck_state(sc_users, STATE_UNKNOWN);
146 printf (_("Could not open stderr for %s\n"), WHO_COMMAND); 110 sc_users.output = "Failed to retrieve number of users";
147 111 mp_add_subcheck_to_check(&overall, sc_users);
148 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) { 112 mp_exit(overall);
149 /* increment 'users' on all lines except total user count */
150 if (input_buffer[0] != '#') {
151 users++;
152 continue;
153 }
154
155 /* get total logged in users */
156 if (sscanf (input_buffer, _("# users=%d"), &users) == 1)
157 break;
158 } 113 }
114 /* check the user count against warning and critical thresholds */
159 115
160 /* check STDERR */ 116 mp_perfdata users_pd = {
161 if (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) 117 .label = "users",
162 result = possibly_set (result, STATE_UNKNOWN); 118 .value = mp_create_pd_value(user_wrapper.users),
163 (void) fclose (child_stderr); 119 };
164
165 /* close the pipe */
166 if (spclose (child_process))
167 result = possibly_set (result, STATE_UNKNOWN);
168#endif
169#ifdef HAVE_LIBSYSTEMD
170 }
171#endif
172 120
173 /* check the user count against warning and critical thresholds */ 121 users_pd = mp_pd_set_thresholds(users_pd, config.thresholds);
174 result = get_status((double)users, thlds); 122 mp_add_perfdata_to_subcheck(&sc_users, users_pd);
175 123
176 if (result == STATE_UNKNOWN) 124 int tmp_status = mp_get_pd_status(users_pd);
177 printf ("%s\n", _("Unable to read output")); 125 sc_users = mp_set_subcheck_state(sc_users, tmp_status);
178 else { 126
179 printf (_("USERS %s - %d users currently logged in |%s\n"), 127 switch (tmp_status) {
180 state_text(result), users, 128 case STATE_WARNING:
181 sperfdata_int("users", users, "", warning_range, 129 xasprintf(&sc_users.output,
182 critical_range, true, 0, false, 0)); 130 "%d users currently logged in. This violates the warning threshold",
131 user_wrapper.users);
132 break;
133 case STATE_CRITICAL:
134 xasprintf(&sc_users.output,
135 "%d users currently logged in. This violates the critical threshold",
136 user_wrapper.users);
137 break;
138 default:
139 xasprintf(&sc_users.output, "%d users currently logged in", user_wrapper.users);
183 } 140 }
184 141
185 return result; 142 mp_add_subcheck_to_check(&overall, sc_users);
143 mp_exit(overall);
186} 144}
187 145
146#define output_format_index CHAR_MAX + 1
147
188/* process command-line arguments */ 148/* process command-line arguments */
189int 149check_users_config_wrapper process_arguments(int argc, char **argv) {
190process_arguments (int argc, char **argv) 150 static struct option longopts[] = {{"critical", required_argument, 0, 'c'},
191{ 151 {"warning", required_argument, 0, 'w'},
192 int c; 152 {"version", no_argument, 0, 'V'},
193 int option = 0; 153 {"help", no_argument, 0, 'h'},
194 static struct option longopts[] = { 154 {"output-format", required_argument, 0, output_format_index},
195 {"critical", required_argument, 0, 'c'}, 155 {0, 0, 0, 0}};
196 {"warning", required_argument, 0, 'w'}, 156
197 {"version", no_argument, 0, 'V'}, 157 if (argc < 2) {
198 {"help", no_argument, 0, 'h'}, 158 usage(progname);
199 {0, 0, 0, 0} 159 }
200 };
201 160
202 if (argc < 2) 161 char *warning_range = NULL;
203 usage ("\n"); 162 char *critical_range = NULL;
163 check_users_config_wrapper result = {
164 .config = check_users_config_init(),
165 .errorcode = OK,
166 };
204 167
205 while (true) { 168 while (true) {
206 c = getopt_long (argc, argv, "+hVvc:w:", longopts, &option); 169 int counter = getopt_long(argc, argv, "+hVvc:w:", longopts, NULL);
207 170
208 if (c == -1 || c == EOF || c == 1) 171 if (counter == -1 || counter == EOF || counter == 1) {
209 break; 172 break;
173 }
210 174
211 switch (c) { 175 switch (counter) {
212 case '?': /* print short usage statement if args not parsable */ 176 case '?': /* print short usage statement if args not parsable */
213 usage5 (); 177 usage5();
214 case 'h': /* help */ 178 case 'h': /* help */
215 print_help (); 179 print_help();
216 exit (STATE_UNKNOWN); 180 exit(STATE_UNKNOWN);
217 case 'V': /* version */ 181 case 'V': /* version */
218 print_revision (progname, NP_VERSION); 182 print_revision(progname, NP_VERSION);
219 exit (STATE_UNKNOWN); 183 exit(STATE_UNKNOWN);
220 case 'c': /* critical */ 184 case 'c': /* critical */
221 critical_range = optarg; 185 critical_range = optarg;
222 break; 186 break;
223 case 'w': /* warning */ 187 case 'w': /* warning */
224 warning_range = optarg; 188 warning_range = optarg;
225 break; 189 break;
190 case output_format_index: {
191 parsed_output_format parser = mp_parse_output_format(optarg);
192 if (!parser.parsing_success) {
193 // TODO List all available formats here, maybe add anothoer usage function
194 printf("Invalid output format: %s\n", optarg);
195 exit(STATE_UNKNOWN);
196 }
197
198 result.config.output_format_is_set = true;
199 result.config.output_format = parser.output_format;
200 break;
201 }
226 } 202 }
227 } 203 }
228 204
229 c = optind; 205 int option_char = optind;
230 206
231 if (warning_range == NULL && argc > c) 207 if (warning_range == NULL && argc > option_char) {
232 warning_range = argv[c++]; 208 warning_range = argv[option_char++];
209 }
233 210
234 if (critical_range == NULL && argc > c) 211 if (critical_range == NULL && argc > option_char) {
235 critical_range = argv[c++]; 212 critical_range = argv[option_char++];
213 }
236 214
237 /* this will abort in case of invalid ranges */ 215 // TODO add proper verification for ranges here!
238 set_thresholds (&thlds, warning_range, critical_range); 216 mp_range_parsed tmp;
217 if (warning_range) {
218 tmp = mp_parse_range_string(warning_range);
219 } else {
220 printf("Warning threshold missing\n");
221 print_usage();
222 exit(STATE_UNKNOWN);
223 }
239 224
240 if (!thlds->warning) { 225 if (tmp.error == MP_PARSING_SUCCES) {
241 usage4 (_("Warning threshold must be a valid range expression")); 226 result.config.thresholds.warning = tmp.range;
227 result.config.thresholds.warning_is_set = true;
228 } else {
229 printf("Failed to parse warning range: %s", warning_range);
230 exit(STATE_UNKNOWN);
242 } 231 }
243 232
244 if (!thlds->critical) { 233 if (critical_range) {
245 usage4 (_("Critical threshold must be a valid range expression")); 234 tmp = mp_parse_range_string(critical_range);
235 } else {
236 printf("Critical threshold missing\n");
237 print_usage();
238 exit(STATE_UNKNOWN);
246 } 239 }
247 240
248 return OK; 241 if (tmp.error == MP_PARSING_SUCCES) {
242 result.config.thresholds.critical = tmp.range;
243 result.config.thresholds.critical_is_set = true;
244 } else {
245 printf("Failed to parse critical range: %s", critical_range);
246 exit(STATE_UNKNOWN);
247 }
248
249 return result;
249} 250}
250 251
251void 252void print_help(void) {
252print_help (void) 253 print_revision(progname, NP_VERSION);
253{
254 print_revision (progname, NP_VERSION);
255 254
256 printf ("Copyright (c) 1999 Ethan Galstad\n"); 255 printf("Copyright (c) 1999 Ethan Galstad\n");
257 printf (COPYRIGHT, copyright, email); 256 printf(COPYRIGHT, copyright, email);
258 257
259 printf ("%s\n", _("This plugin checks the number of users currently logged in on the local")); 258 printf("%s\n", _("This plugin checks the number of users currently logged in on the local"));
260 printf ("%s\n", _("system and generates an error if the number exceeds the thresholds specified.")); 259 printf("%s\n",
260 _("system and generates an error if the number exceeds the thresholds specified."));
261 261
262 printf ("\n\n"); 262 printf("\n\n");
263 263
264 print_usage (); 264 print_usage();
265 265
266 printf (UT_HELP_VRSN); 266 printf(UT_HELP_VRSN);
267 printf (UT_EXTRA_OPTS); 267 printf(UT_EXTRA_OPTS);
268 268
269 printf (" %s\n", "-w, --warning=RANGE_EXPRESSION"); 269 printf(" %s\n", "-w, --warning=RANGE_EXPRESSION");
270 printf (" %s\n", _("Set WARNING status if number of logged in users violates RANGE_EXPRESSION")); 270 printf(" %s\n",
271 printf (" %s\n", "-c, --critical=RANGE_EXPRESSION"); 271 _("Set WARNING status if number of logged in users violates RANGE_EXPRESSION"));
272 printf (" %s\n", _("Set CRITICAL status if number of logged in users violates RANGE_EXPRESSION")); 272 printf(" %s\n", "-c, --critical=RANGE_EXPRESSION");
273 printf(" %s\n",
274 _("Set CRITICAL status if number of logged in users violates RANGE_EXPRESSION"));
275 printf(UT_OUTPUT_FORMAT);
273 276
274 printf (UT_SUPPORT); 277 printf(UT_SUPPORT);
275} 278}
276 279
277void 280void print_usage(void) {
278print_usage (void) 281 printf("%s\n", _("Usage:"));
279{ 282 printf("%s -w <users> -c <users>\n", progname);
280 printf ("%s\n", _("Usage:"));
281 printf ("%s -w <users> -c <users>\n", progname);
282} 283}
diff --git a/plugins/check_users.d/config.h b/plugins/check_users.d/config.h
new file mode 100644
index 00000000..26d3ee70
--- /dev/null
+++ b/plugins/check_users.d/config.h
@@ -0,0 +1,20 @@
1#pragma once
2
3#include "output.h"
4#include "thresholds.h"
5
6typedef struct check_users_config {
7 mp_thresholds thresholds;
8
9 bool output_format_is_set;
10 mp_output_format output_format;
11} check_users_config;
12
13check_users_config check_users_config_init() {
14 check_users_config tmp = {
15 .thresholds = mp_thresholds_init(),
16
17 .output_format_is_set = false,
18 };
19 return tmp;
20}
diff --git a/plugins/check_users.d/users.c b/plugins/check_users.d/users.c
new file mode 100644
index 00000000..a08f79c5
--- /dev/null
+++ b/plugins/check_users.d/users.c
@@ -0,0 +1,169 @@
1#include "./users.h"
2
3#ifdef _WIN32
4# ifdef HAVE_WTSAPI32_H
5# include <windows.h>
6# include <wtsapi32.h>
7# undef ERROR
8# define ERROR -1
9
10get_num_of_users_wrapper get_num_of_users_windows() {
11 WTS_SESSION_INFO *wtsinfo;
12 DWORD wtscount;
13
14 get_num_of_users_wrapper result = {};
15
16 if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &wtsinfo, &wtscount)) {
17 // printf(_("Could not enumerate RD sessions: %d\n"), GetLastError());
18 result.error = WINDOWS_COULD_NOT_ENUMERATE_SESSIONS;
19 return result;
20 }
21
22 for (DWORD index = 0; index < wtscount; index++) {
23 LPTSTR username;
24 DWORD size;
25
26 if (!WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, wtsinfo[index].SessionId,
27 WTSUserName, &username, &size)) {
28 continue;
29 }
30
31 int len = lstrlen(username);
32
33 WTSFreeMemory(username);
34
35 if (len == 0) {
36 continue;
37 }
38
39 if (wtsinfo[index].State == WTSActive || wtsinfo[index].State == WTSDisconnected) {
40 result.users++;
41 }
42 }
43
44 WTSFreeMemory(wtsinfo);
45 return result;
46}
47# else // HAVE_WTSAPI32_H
48# error On windows but without the WTSAPI32 lib
49# endif // HAVE_WTSAPI32_H
50
51#else // _WIN32
52
53# include "../../config.h"
54# include <stddef.h>
55
56# ifdef HAVE_LIBSYSTEMD
57# include <systemd/sd-daemon.h>
58# include <systemd/sd-login.h>
59
60get_num_of_users_wrapper get_num_of_users_systemd() {
61 get_num_of_users_wrapper result = {};
62
63 // Test whether we booted with systemd
64 if (sd_booted() > 0) {
65 int users = sd_get_uids(NULL);
66 if (users >= 0) {
67 // Success
68 result.users = users;
69 return result;
70 }
71
72 // Failure! return the error code
73 result.errorcode = users;
74 return result;
75 }
76
77 // Looks like we are not running systemd,
78 // return with error here
79 result.errorcode = NO_SYSTEMD_ERROR;
80 return result;
81}
82# endif
83
84# ifdef HAVE_UTMPX_H
85# include <utmpx.h>
86
87get_num_of_users_wrapper get_num_of_users_utmp() {
88 int users = 0;
89
90 /* get currently logged users from utmpx */
91 setutxent();
92
93 struct utmpx *putmpx;
94 while ((putmpx = getutxent()) != NULL) {
95 if (putmpx->ut_type == USER_PROCESS) {
96 users++;
97 }
98 }
99
100 endutxent();
101
102 get_num_of_users_wrapper result = {
103 .errorcode = 0,
104 .users = users,
105 };
106
107 return result;
108}
109# endif
110
111# ifndef HAVE_WTSAPI32_H
112# ifndef HAVE_LIBSYSTEMD
113# ifndef HAVE_UTMPX_H
114// Fall back option here for the others (probably still not on windows)
115
116# include "../common.h"
117# include "../popen.h"
118# include "../utils.h"
119
120get_num_of_users_wrapper get_num_of_users_who_command() {
121 /* run the command */
122 child_process = spopen(WHO_COMMAND);
123 if (child_process == NULL) {
124 // printf(_("Could not open pipe: %s\n"), WHO_COMMAND);
125 get_num_of_users_wrapper result = {
126 .errorcode = COULD_NOT_OPEN_PIPE,
127 };
128 return result;
129 }
130
131 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
132 if (child_stderr == NULL) {
133 // printf(_("Could not open stderr for %s\n"), WHO_COMMAND);
134 // TODO this error should probably be reported
135 }
136
137 get_num_of_users_wrapper result = {};
138 char input_buffer[MAX_INPUT_BUFFER];
139 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
140 /* increment 'users' on all lines except total user count */
141 if (input_buffer[0] != '#') {
142 result.users++;
143 continue;
144 }
145
146 /* get total logged in users */
147 if (sscanf(input_buffer, _("# users=%d"), &result.users) == 1) {
148 break;
149 }
150 }
151
152 /* check STDERR */
153 if (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
154 // if this fails, something broke and the result can not be relied upon or so is the theorie
155 // here
156 result.errorcode = STDERR_COULD_NOT_BE_READ;
157 }
158 (void)fclose(child_stderr);
159
160 /* close the pipe */
161 spclose(child_process);
162
163 return result;
164}
165
166# endif
167# endif
168# endif
169#endif
diff --git a/plugins/check_users.d/users.h b/plugins/check_users.d/users.h
new file mode 100644
index 00000000..aacba775
--- /dev/null
+++ b/plugins/check_users.d/users.h
@@ -0,0 +1,18 @@
1#pragma once
2
3typedef struct get_num_of_users_wrapper {
4 int errorcode;
5 int users;
6} get_num_of_users_wrapper;
7
8enum {
9 NO_SYSTEMD_ERROR = 64,
10 WINDOWS_COULD_NOT_ENUMERATE_SESSIONS,
11 COULD_NOT_OPEN_PIPE,
12 STDERR_COULD_NOT_BE_READ,
13};
14
15get_num_of_users_wrapper get_num_of_users_systemd();
16get_num_of_users_wrapper get_num_of_users_utmp();
17get_num_of_users_wrapper get_num_of_users_windows();
18get_num_of_users_wrapper get_num_of_users_who_command();
diff --git a/plugins/common.h b/plugins/common.h
index 833479ce..ef888d08 100644
--- a/plugins/common.h
+++ b/plugins/common.h
@@ -1,126 +1,122 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring Plugins common include file 3 * Monitoring Plugins common include file
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999 Ethan Galstad (nagios@nagios.org) 6 * Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
7* Copyright (c) 2003-2007 Monitoring Plugins Development Team 7 * Copyright (c) 2003-2007 Monitoring Plugins Development Team
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains common include files and defines used in many of 11 * This file contains common include files and defines used in many of
12* the plugins. 12 * the plugins.
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 15 * This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31#ifndef _COMMON_H_ 31#ifndef _COMMON_H_
32#define _COMMON_H_ 32#define _COMMON_H_
33 33
34#include "config.h" 34#include "../config.h"
35#include "../lib/monitoringplug.h"
35 36
36#ifdef HAVE_FEATURES_H 37#ifdef HAVE_FEATURES_H
37#include <features.h> 38# include <features.h>
38#endif 39#endif
39 40
40#include <stdio.h> /* obligatory includes */ 41#include <stdio.h> /* obligatory includes */
41#include <stdlib.h> 42#include <stdlib.h>
42#include <errno.h> 43#include <errno.h>
43 44
44/* This block provides uintmax_t - should be reported to coreutils that this should be added to fsuage.h */ 45/* This block provides uintmax_t - should be reported to coreutils that this should be added to
46 * fsuage.h */
45#if HAVE_INTTYPES_H 47#if HAVE_INTTYPES_H
46# include <inttypes.h> 48# include <inttypes.h>
47#endif 49#endif
48#if HAVE_STDINT_H 50#if HAVE_STDINT_H
49# include <stdint.h> 51# include <stdint.h>
50#endif 52#endif
51#include <unistd.h> 53#include <unistd.h>
52#ifndef UINTMAX_MAX 54#ifndef UINTMAX_MAX
53# define UINTMAX_MAX ((uintmax_t) -1) 55# define UINTMAX_MAX ((uintmax_t) - 1)
54#endif 56#endif
55 57
56#include <limits.h> /* This is assumed true, because coreutils assume it too */ 58#include <limits.h> /* This is assumed true, because coreutils assume it too */
57 59
58#ifdef HAVE_MATH_H 60#ifdef HAVE_MATH_H
59#include <math.h> 61# include <math.h>
60#endif 62#endif
61 63
62#ifdef _AIX 64#ifdef _AIX
63#ifdef HAVE_MP_H 65# ifdef HAVE_MP_H
64#include <mp.h> 66# include <mp.h>
65#endif 67# endif
66#endif 68#endif
67 69
68#ifdef HAVE_STRINGS_H 70#ifdef HAVE_STRINGS_H
69#include <strings.h> 71# include <strings.h>
70#endif 72#endif
71#ifdef HAVE_STRING_H 73#ifdef HAVE_STRING_H
72#include <string.h> 74# include <string.h>
73#endif 75#endif
74 76
75#ifdef HAVE_UNISTD_H 77#ifdef HAVE_UNISTD_H
76#include <unistd.h> 78# include <unistd.h>
77#endif 79#endif
78 80
79/* GET_NUMBER_OF_CPUS is a macro to return 81/* GET_NUMBER_OF_CPUS is a macro to return
80 number of CPUs, if we can get that data. 82 number of CPUs, if we can get that data.
81 Use configure.in to test for various OS ways of 83 Use configure.in to test for various OS ways of
82 getting that data 84 getting that data
83 Will return -1 if cannot get data 85 Will return -1 if cannot get data
84*/ 86*/
85#if defined(HAVE_SYSCONF__SC_NPROCESSORS_ONLN) 87#if defined(HAVE_SYSCONF__SC_NPROCESSORS_ONLN)
86# define GET_NUMBER_OF_CPUS() sysconf(_SC_NPROCESSORS_ONLN) 88# define GET_NUMBER_OF_CPUS() sysconf(_SC_NPROCESSORS_ONLN)
87#elif defined (HAVE_SYSCONF__SC_NPROCESSORS_CONF) 89#elif defined(HAVE_SYSCONF__SC_NPROCESSORS_CONF)
88# define GET_NUMBER_OF_CPUS() sysconf(_SC_NPROCESSORS_CONF) 90# define GET_NUMBER_OF_CPUS() sysconf(_SC_NPROCESSORS_CONF)
89#else 91#else
90# define GET_NUMBER_OF_CPUS() -1 92# define GET_NUMBER_OF_CPUS() -1
91#endif 93#endif
92 94
93#ifdef TIME_WITH_SYS_TIME 95#ifdef HAVE_SYS_TIME_H
94# include <sys/time.h> 96# 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 97#endif
98#include <time.h>
103 99
104#ifdef HAVE_SYS_TYPES_H 100#ifdef HAVE_SYS_TYPES_H
105#include <sys/types.h> 101# include <sys/types.h>
106#endif 102#endif
107 103
108#ifdef HAVE_SYS_SOCKET_H 104#ifdef HAVE_SYS_SOCKET_H
109#include <sys/socket.h> 105# include <sys/socket.h>
110#endif 106#endif
111 107
112#ifdef HAVE_SIGNAL_H 108#ifdef HAVE_SIGNAL_H
113#include <signal.h> 109# include <signal.h>
114#endif 110#endif
115 111
116/* GNU Libraries */ 112/* GNU Libraries */
117#include <getopt.h> 113#include <getopt.h>
118#include "dirname.h" 114#include "../gl/dirname.h"
119 115
120#include <locale.h> 116#include <locale.h>
121 117
122#ifdef HAVE_SYS_POLL_H 118#ifdef HAVE_SYS_POLL_H
123# include "sys/poll.h" 119# include "sys/poll.h"
124#endif 120#endif
125 121
126/* 122/*
@@ -130,42 +126,42 @@
130 */ 126 */
131 127
132#ifndef HAVE_STRTOL 128#ifndef HAVE_STRTOL
133# define strtol(a,b,c) atol((a)) 129# define strtol(a, b, c) atol((a))
134#endif 130#endif
135 131
136#ifndef HAVE_STRTOUL 132#ifndef HAVE_STRTOUL
137# define strtoul(a,b,c) (unsigned long)atol((a)) 133# define strtoul(a, b, c) (unsigned long)atol((a))
138#endif 134#endif
139 135
140/* SSL implementations */ 136/* SSL implementations */
141#ifdef HAVE_GNUTLS_OPENSSL_H 137#ifdef HAVE_GNUTLS_OPENSSL_H
142# include <gnutls/openssl.h> 138# include <gnutls/openssl.h>
143#else 139#else
144# define OPENSSL_LOAD_CONF /* See the OPENSSL_config(3) man page. */ 140# define OPENSSL_LOAD_CONF /* See the OPENSSL_config(3) man page. */
145# ifdef HAVE_SSL_H 141# ifdef HAVE_SSL_H
146# include <rsa.h> 142# include <rsa.h>
147# include <crypto.h> 143# include <crypto.h>
148# include <x509.h> 144# include <x509.h>
149# include <pem.h> 145# include <pem.h>
150# include <ssl.h> 146# include <ssl.h>
151# include <err.h> 147# include <err.h>
152# else 148# else
153# ifdef HAVE_OPENSSL_SSL_H 149# ifdef HAVE_OPENSSL_SSL_H
154# include <openssl/rsa.h> 150# include <openssl/rsa.h>
155# include <openssl/crypto.h> 151# include <openssl/crypto.h>
156# include <openssl/x509.h> 152# include <openssl/x509.h>
157# include <openssl/pem.h> 153# include <openssl/pem.h>
158# include <openssl/ssl.h> 154# include <openssl/ssl.h>
159# include <openssl/err.h> 155# include <openssl/err.h>
160# endif 156# endif
161# endif 157# endif
162#endif 158#endif
163 159
164/* openssl 1.1 does not set OPENSSL_NO_SSL2 by default but ships without ssl2 */ 160/* openssl 1.1 does not set OPENSSL_NO_SSL2 by default but ships without ssl2 */
165#ifdef OPENSSL_VERSION_NUMBER 161#ifdef OPENSSL_VERSION_NUMBER
166# if OPENSSL_VERSION_NUMBER >= 0x10100000 162# if OPENSSL_VERSION_NUMBER >= 0x10100000
167# define OPENSSL_NO_SSL2 163# define OPENSSL_NO_SSL2
168# endif 164# endif
169#endif 165#endif
170 166
171/* 167/*
@@ -176,7 +172,7 @@
176 172
177/* MariaDB 10.2 client does not set MYSQL_PORT */ 173/* MariaDB 10.2 client does not set MYSQL_PORT */
178#ifndef MYSQL_PORT 174#ifndef MYSQL_PORT
179# define MYSQL_PORT 3306 175# define MYSQL_PORT 3306
180#endif 176#endif
181 177
182enum { 178enum {
@@ -185,17 +181,9 @@ enum {
185}; 181};
186 182
187enum { 183enum {
188 STATE_OK, 184 DEFAULT_SOCKET_TIMEOUT = 10, /* timeout after 10 seconds */
189 STATE_WARNING, 185 MAX_INPUT_BUFFER = 8192, /* max size of most buffers we use */
190 STATE_CRITICAL, 186 MAX_HOST_ADDRESS_LENGTH = 256 /* max size of a host address */
191 STATE_UNKNOWN,
192 STATE_DEPENDENT
193};
194
195enum {
196 DEFAULT_SOCKET_TIMEOUT = 10, /* timeout after 10 seconds */
197 MAX_INPUT_BUFFER = 8192, /* max size of most buffers we use */
198 MAX_HOST_ADDRESS_LENGTH = 256 /* max size of a host address */
199}; 187};
200 188
201/* 189/*
@@ -203,18 +191,18 @@ enum {
203 * Internationalization 191 * Internationalization
204 * 192 *
205 */ 193 */
206#include "gettext.h" 194#include "../gl/gettext.h"
207#define _(String) gettext (String) 195#define _(String) gettext(String)
208#if ! ENABLE_NLS 196#if !ENABLE_NLS
209# undef textdomain 197# undef textdomain
210# define textdomain(Domainname) /* empty */ 198# define textdomain(Domainname) /* empty */
211# undef bindtextdomain 199# undef bindtextdomain
212# define bindtextdomain(Domainname, Dirname) /* empty */ 200# define bindtextdomain(Domainname, Dirname) /* empty */
213#endif 201#endif
214 202
215/* For non-GNU compilers to ignore __attribute__ */ 203/* For non-GNU compilers to ignore __attribute__ */
216#ifndef __GNUC__ 204#ifndef __GNUC__
217# define __attribute__(x) /* do nothing */ 205# define __attribute__(x) /* do nothing */
218#endif 206#endif
219 207
220#endif /* _COMMON_H_ */ 208#endif /* _COMMON_H_ */
diff --git a/plugins/negate.c b/plugins/negate.c
index c5fe7e13..a42a6c59 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,212 @@ 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],
109 state_text(config.state[result]), sub);
106 } 110 }
107 } 111 }
108 printf ("%s\n", chld_out.line[i]); 112 printf("%s\n", chld_out.line[i]);
109 } 113 }
110 114
111 if (result >= 0 && result <= 4) { 115 if (result >= 0 && result <= 4) {
112 exit (state[result]); 116 exit(config.state[result]);
113 } else { 117 } else {
114 exit (result); 118 exit(result);
115 } 119 }
116} 120}
117 121
118
119/* process command-line arguments */ 122/* process command-line arguments */
120static const char ** 123static negate_config_wrapper process_arguments(int argc, char **argv) {
121process_arguments (int argc, char **argv)
122{
123 int c;
124 bool permute = true;
125
126 int option = 0;
127 static struct option longopts[] = { 124 static struct option longopts[] = {
128 {"help", no_argument, 0, 'h'}, 125 {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'},
129 {"version", no_argument, 0, 'V'}, 126 {"timeout", required_argument, 0, 't'}, {"timeout-result", required_argument, 0, 'T'},
130 {"timeout", required_argument, 0, 't'}, 127 {"ok", required_argument, 0, 'o'}, {"warning", required_argument, 0, 'w'},
131 {"timeout-result", required_argument, 0, 'T'}, 128 {"critical", required_argument, 0, 'c'}, {"unknown", required_argument, 0, 'u'},
132 {"ok", required_argument, 0, 'o'}, 129 {"substitute", no_argument, 0, 's'}, {0, 0, 0, 0}};
133 {"warning", required_argument, 0, 'w'}, 130
134 {"critical", required_argument, 0, 'c'}, 131 negate_config_wrapper result = {
135 {"unknown", required_argument, 0, 'u'}, 132 .errorcode = OK,
136 {"substitute", no_argument, 0, 's'}, 133 .config = negate_config_init(),
137 {0, 0, 0, 0}
138 }; 134 };
135 bool permute = true;
136 while (true) {
137 int option = 0;
138 int option_char = getopt_long(argc, argv, "+hVt:T:o:w:c:u:s", longopts, &option);
139 139
140 while (1) { 140 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; 141 break;
142 }
145 143
146 switch (c) { 144 switch (option_char) {
147 case '?': /* help */ 145 case '?': /* help */
148 usage5 (); 146 usage5();
149 break; 147 break;
150 case 'h': /* help */ 148 case 'h': /* help */
151 print_help (); 149 print_help();
152 exit (EXIT_SUCCESS); 150 exit(STATE_UNKNOWN);
153 break; 151 break;
154 case 'V': /* version */ 152 case 'V': /* version */
155 print_revision (progname, NP_VERSION); 153 print_revision(progname, NP_VERSION);
156 exit (EXIT_SUCCESS); 154 exit(STATE_UNKNOWN);
157 case 't': /* timeout period */ 155 case 't': /* timeout period */
158 if (!is_integer (optarg)) 156 if (!is_integer(optarg)) {
159 usage2 (_("Timeout interval must be a positive integer"), optarg); 157 usage2(_("Timeout interval must be a positive integer"), optarg);
160 else 158 } else {
161 timeout_interval = atoi (optarg); 159 timeout_interval = atoi(optarg);
160 }
162 break; 161 break;
163 case 'T': /* Result to return on timeouts */ 162 case 'T': /* Result to return on timeouts */
164 if ((timeout_state = mp_translate_state(optarg)) == ERROR) 163 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).")); 164 usage4(_("Timeout result must be a valid state name (OK, WARNING, CRITICAL, "
165 "UNKNOWN) or integer (0-3)."));
166 }
166 break; 167 break;
167 case 'o': /* replacement for OK */ 168 case 'o': /* replacement for OK */
168 if ((state[STATE_OK] = mp_translate_state(optarg)) == ERROR) 169 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).")); 170 usage4(_("Ok must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or "
171 "integer (0-3)."));
172 }
170 permute = false; 173 permute = false;
171 break; 174 break;
172 175
173 case 'w': /* replacement for WARNING */ 176 case 'w': /* replacement for WARNING */
174 if ((state[STATE_WARNING] = mp_translate_state(optarg)) == ERROR) 177 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).")); 178 usage4(_("Warning must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or "
179 "integer (0-3)."));
180 }
176 permute = false; 181 permute = false;
177 break; 182 break;
178 case 'c': /* replacement for CRITICAL */ 183 case 'c': /* replacement for CRITICAL */
179 if ((state[STATE_CRITICAL] = mp_translate_state(optarg)) == ERROR) 184 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).")); 185 usage4(_("Critical must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or "
186 "integer (0-3)."));
187 }
181 permute = false; 188 permute = false;
182 break; 189 break;
183 case 'u': /* replacement for UNKNOWN */ 190 case 'u': /* replacement for UNKNOWN */
184 if ((state[STATE_UNKNOWN] = mp_translate_state(optarg)) == ERROR) 191 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).")); 192 usage4(_("Unknown must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or "
193 "integer (0-3)."));
194 }
186 permute = false; 195 permute = false;
187 break; 196 break;
188 case 's': /* Substitute status text */ 197 case 's': /* Substitute status text */
189 subst_text = true; 198 result.config.subst_text = true;
190 break; 199 break;
191 } 200 }
192 } 201 }
193 202
194 validate_arguments (&argv[optind]);
195
196 if (permute) { /* No [owcu] switch specified, default to this */ 203 if (permute) { /* No [owcu] switch specified, default to this */
197 state[STATE_OK] = STATE_CRITICAL; 204 result.config.state[STATE_OK] = STATE_CRITICAL;
198 state[STATE_CRITICAL] = STATE_OK; 205 result.config.state[STATE_CRITICAL] = STATE_OK;
199 } 206 }
200 207
201 return (const char **) &argv[optind]; 208 result.config.command_line = &argv[optind];
209
210 return validate_arguments(result);
202} 211}
203 212
213negate_config_wrapper validate_arguments(negate_config_wrapper config_wrapper) {
214 if (config_wrapper.config.command_line[0] == NULL) {
215 usage4(_("Could not parse arguments"));
216 }
204 217
205void 218 if (strncmp(config_wrapper.config.command_line[0], "/", 1) != 0 &&
206validate_arguments (char **command_line) 219 strncmp(config_wrapper.config.command_line[0], "./", 2) != 0) {
207{ 220 usage4(_("Require path to command"));
208 if (command_line[0] == NULL) 221 }
209 usage4 (_("Could not parse arguments"));
210 222
211 if (strncmp(command_line[0],"/",1) != 0 && strncmp(command_line[0],"./",2) != 0) 223 return config_wrapper;
212 usage4 (_("Require path to command"));
213} 224}
214 225
226void print_help(void) {
227 print_revision(progname, NP_VERSION);
215 228
216void 229 printf(COPYRIGHT, copyright, email);
217print_help (void)
218{
219 print_revision (progname, NP_VERSION);
220 230
221 printf (COPYRIGHT, copyright, email); 231 printf("%s\n", _("Negates only the return code of a plugin (returns OK for CRITICAL and "
232 "vice-versa) by default."));
233 printf("%s\n", _("Additional switches can be used to control:\n"));
234 printf("\t - which state becomes what\n");
235 printf("\t - changing the plugin output text to match the return code");
222 236
223 printf ("%s\n", _("Negates only the return code of a plugin (returns OK for CRITICAL and vice-versa) by default.")); 237 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 238
228 printf ("\n\n"); 239 print_usage();
229 240
230 print_usage (); 241 printf(UT_HELP_VRSN);
231 242
232 printf (UT_HELP_VRSN); 243 printf(UT_PLUG_TIMEOUT, timeout_interval);
233 244 printf(" %s\n", _("Keep timeout longer than the plugin timeout to retain CRITICAL status."));
234 printf (UT_PLUG_TIMEOUT, timeout_interval); 245 printf(" -T, --timeout-result=STATUS\n");
235 printf (" %s\n", _("Keep timeout longer than the plugin timeout to retain CRITICAL status.")); 246 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 247
239 printf(" -o, --ok=STATUS\n"); 248 printf(" -o, --ok=STATUS\n");
240 printf(" -w, --warning=STATUS\n"); 249 printf(" -w, --warning=STATUS\n");
@@ -246,31 +255,30 @@ print_help (void)
246 printf(" -s, --substitute\n"); 255 printf(" -s, --substitute\n");
247 printf(_(" Substitute output text as well. Will only substitute text in CAPITALS\n")); 256 printf(_(" Substitute output text as well. Will only substitute text in CAPITALS\n"));
248 257
249 printf ("\n"); 258 printf("\n");
250 printf ("%s\n", _("Examples:")); 259 printf("%s\n", _("Examples:"));
251 printf (" %s\n", "negate /usr/local/nagios/libexec/check_ping -H host"); 260 printf(" %s\n", "negate /usr/local/nagios/libexec/check_ping -H host");
252 printf (" %s\n", _("Run check_ping and invert result. Must use full path to plugin")); 261 printf(" %s\n", _("Run check_ping and invert result. Must use full path to plugin"));
253 printf (" %s\n", "negate -w OK -c UNKNOWN /usr/local/nagios/libexec/check_procs -a 'vi negate.c'"); 262 printf(" %s\n",
254 printf (" %s\n", _("This will return OK instead of WARNING and UNKNOWN instead of CRITICAL")); 263 "negate -w OK -c UNKNOWN /usr/local/nagios/libexec/check_procs -a 'vi negate.c'");
255 printf ("\n"); 264 printf(" %s\n", _("This will return OK instead of WARNING and UNKNOWN instead of CRITICAL"));
256 printf ("%s\n", _("Notes:")); 265 printf("\n");
257 printf (" %s\n", _("This plugin is a wrapper to take the output of another plugin and invert it.")); 266 printf("%s\n", _("Notes:"));
258 printf (" %s\n", _("The full path of the plugin must be provided.")); 267 printf(" %s\n",
259 printf (" %s\n", _("If the wrapped plugin returns OK, the wrapper will return CRITICAL.")); 268 _("This plugin is a wrapper to take the output of another plugin and invert it."));
260 printf (" %s\n", _("If the wrapped plugin returns CRITICAL, the wrapper will return OK.")); 269 printf(" %s\n", _("The full path of the plugin must be provided."));
261 printf (" %s\n", _("Otherwise, the output state of the wrapped plugin is unchanged.")); 270 printf(" %s\n", _("If the wrapped plugin returns OK, the wrapper will return CRITICAL."));
262 printf ("\n"); 271 printf(" %s\n", _("If the wrapped plugin returns CRITICAL, the wrapper will return OK."));
263 printf (" %s\n", _("Using timeout-result, it is possible to override the timeout behaviour or a")); 272 printf(" %s\n", _("Otherwise, the output state of the wrapped plugin is unchanged."));
264 printf (" %s\n", _("plugin by setting the negate timeout a bit lower.")); 273 printf("\n");
265 274 printf(" %s\n",
266 printf (UT_SUPPORT); 275 _("Using timeout-result, it is possible to override the timeout behaviour or a"));
276 printf(" %s\n", _("plugin by setting the negate timeout a bit lower."));
277
278 printf(UT_SUPPORT);
267} 279}
268 280
269 281void print_usage(void) {
270 282 printf("%s\n", _("Usage:"));
271void 283 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} 284}
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..b4c6ff0a 100644
--- a/plugins/netutils.c
+++ b/plugins/netutils.c
@@ -1,40 +1,43 @@
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"
33#include <sys/types.h>
31#include "netutils.h" 34#include "netutils.h"
32 35
33unsigned int socket_timeout = DEFAULT_SOCKET_TIMEOUT; 36unsigned int socket_timeout = DEFAULT_SOCKET_TIMEOUT;
34unsigned int socket_timeout_state = STATE_CRITICAL; 37mp_state_enum socket_timeout_state = STATE_CRITICAL;
35 38mp_state_enum econn_refuse_state = STATE_CRITICAL;
36int econn_refuse_state = STATE_CRITICAL;
37bool was_refused = false; 39bool was_refused = false;
40
38#if USE_IPV6 41#if USE_IPV6
39int address_family = AF_UNSPEC; 42int address_family = AF_UNSPEC;
40#else 43#else
@@ -42,177 +45,177 @@ int address_family = AF_INET;
42#endif 45#endif
43 46
44/* handles socket timeouts */ 47/* handles socket timeouts */
45void 48void socket_timeout_alarm_handler(int sig) {
46socket_timeout_alarm_handler (int sig) 49 mp_subcheck timeout_sc = mp_subcheck_init();
47{ 50 timeout_sc = mp_set_subcheck_state(timeout_sc, socket_timeout_state);
48 if (sig == SIGALRM) 51
49 printf (_("%s - Socket timeout after %d seconds\n"), state_text(socket_timeout_state), socket_timeout); 52 if (sig == SIGALRM) {
50 else 53 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); 54 } else {
52 55 xasprintf(&timeout_sc.output, _("Abnormal timeout after %d seconds\n"), socket_timeout);
53 exit (socket_timeout_state); 56 }
54} 57
58 mp_check overall = mp_check_init();
59 mp_add_subcheck_to_check(&overall, timeout_sc);
55 60
61 mp_exit(overall);
62}
56 63
57/* connects to a host on a specified tcp port, sends a string, and gets a 64/* connects to a host on a specified tcp port, sends a string, and gets a
58 response. loops on select-recv until timeout or eof to get all of a 65 response. loops on select-recv until timeout or eof to get all of a
59 multi-packet answer */ 66 multi-packet answer */
60int 67mp_state_enum process_tcp_request2(const char *server_address, const int server_port,
61process_tcp_request2 (const char *server_address, int server_port, 68 const char *send_buffer, char *recv_buffer,
62 const char *send_buffer, char *recv_buffer, int recv_size) 69 const int recv_size) {
63{
64 70
65 int result; 71 int socket;
66 int send_result;
67 int recv_result;
68 int sd;
69 struct timeval tv;
70 fd_set readfds;
71 int recv_length = 0;
72 72
73 result = np_net_connect (server_address, server_port, &sd, IPPROTO_TCP); 73 mp_state_enum connect_result =
74 if (result != STATE_OK) 74 np_net_connect(server_address, server_port, &socket, IPPROTO_TCP);
75 if (connect_result != STATE_OK) {
75 return STATE_CRITICAL; 76 return STATE_CRITICAL;
77 }
76 78
77 send_result = send (sd, send_buffer, strlen (send_buffer), 0); 79 mp_state_enum result;
78 if (send_result<0 || (size_t)send_result!=strlen(send_buffer)) { 80 ssize_t send_result = send(socket, send_buffer, strlen(send_buffer), 0);
79 printf ("%s\n", _("Send failed")); 81 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) {
82 // printf("%s\n", _("Send failed"));
80 result = STATE_WARNING; 83 result = STATE_WARNING;
81 } 84 }
82 85
83 while (1) { 86 fd_set readfds;
87 ssize_t recv_length = 0;
88 while (true) {
84 /* wait up to the number of seconds for socket timeout 89 /* wait up to the number of seconds for socket timeout
85 minus one for data from the host */ 90 minus one for data from the host */
86 tv.tv_sec = socket_timeout - 1; 91 struct timeval timeout = {
87 tv.tv_usec = 0; 92 .tv_sec = socket_timeout - 1,
88 FD_ZERO (&readfds); 93 .tv_usec = 0,
89 FD_SET (sd, &readfds); 94 };
90 select (sd + 1, &readfds, NULL, NULL, &tv); 95 FD_ZERO(&readfds);
96 FD_SET(socket, &readfds);
97 select(socket + 1, &readfds, NULL, NULL, &timeout);
91 98
92 /* make sure some data has arrived */ 99 /* make sure some data has arrived */
93 if (!FD_ISSET (sd, &readfds)) { /* it hasn't */ 100 if (!FD_ISSET(socket, &readfds)) { /* it hasn't */
94 if (!recv_length) { 101 if (!recv_length) {
95 strcpy (recv_buffer, ""); 102 strcpy(recv_buffer, "");
96 printf ("%s\n", _("No data was received from host!")); 103 // printf("%s\n", _("No data was received from host!"));
97 result = STATE_WARNING; 104 result = STATE_WARNING;
98 } 105 } else { /* this one failed, but previous ones worked */
99 else { /* this one failed, but previous ones worked */
100 recv_buffer[recv_length] = 0; 106 recv_buffer[recv_length] = 0;
101 } 107 }
102 break; 108 break;
109 } /* it has */
110
111 ssize_t recv_result =
112 recv(socket, recv_buffer + recv_length, (size_t)(recv_size - recv_length - 1), 0);
113 if (recv_result == -1) {
114 /* recv failed, bail out */
115 strcpy(recv_buffer + recv_length, "");
116 result = STATE_WARNING;
117 break;
103 } 118 }
104 else { /* it has */ 119
105 recv_result = 120 if (recv_result == 0) {
106 recv (sd, recv_buffer + recv_length, 121 /* end of file ? */
107 (size_t)recv_size - recv_length - 1, 0); 122 recv_buffer[recv_length] = 0;
108 if (recv_result == -1) { 123 break;
109 /* recv failed, bail out */ 124 }
110 strcpy (recv_buffer + recv_length, ""); 125
111 result = STATE_WARNING; 126 /* we got data! */
112 break; 127 recv_length += recv_result;
113 } 128 if (recv_length >= recv_size - 1) {
114 else if (recv_result == 0) { 129 /* buffer full, we're done */
115 /* end of file ? */ 130 recv_buffer[recv_size - 1] = 0;
116 recv_buffer[recv_length] = 0; 131 break;
117 break;
118 }
119 else { /* we got data! */
120 recv_length += recv_result;
121 if (recv_length >= recv_size - 1) {
122 /* buffer full, we're done */
123 recv_buffer[recv_size - 1] = 0;
124 break;
125 }
126 }
127 } 132 }
128 /* end if(!FD_ISSET(sd,&readfds)) */ 133 /* end if(!FD_ISSET(sd,&readfds)) */
129 } 134 }
130 /* end while(1) */
131 135
132 close (sd); 136 close(socket);
133 return result; 137 return result;
134} 138}
135 139
136
137/* connects to a host on a specified port, sends a string, and gets a 140/* connects to a host on a specified port, sends a string, and gets a
138 response */ 141 response */
139int 142mp_state_enum process_request(const char *server_address, const int server_port, const int proto,
140process_request (const char *server_address, int server_port, int proto, 143 const char *send_buffer, char *recv_buffer, const int recv_size) {
141 const char *send_buffer, char *recv_buffer, int recv_size)
142{
143 int result;
144 int sd;
145
146 result = STATE_OK;
147 144
148 result = np_net_connect (server_address, server_port, &sd, proto); 145 mp_state_enum result = STATE_OK;
149 if (result != STATE_OK) 146 int socket;
147 result = np_net_connect(server_address, server_port, &socket, proto);
148 if (result != STATE_OK) {
150 return STATE_CRITICAL; 149 return STATE_CRITICAL;
150 }
151 151
152 result = send_request (sd, proto, send_buffer, recv_buffer, recv_size); 152 result = send_request(socket, proto, send_buffer, recv_buffer, recv_size);
153 153
154 close (sd); 154 close(socket);
155 155
156 return result; 156 return result;
157} 157}
158 158
159
160/* opens a tcp or udp connection to a remote host or local socket */ 159/* opens a tcp or udp connection to a remote host or local socket */
161int 160mp_state_enum np_net_connect(const char *host_name, int port, int *socketDescriptor,
162np_net_connect (const char *host_name, int port, int *sd, int proto) 161 const int proto) {
163{ 162 /* send back STATE_UNKOWN if there's an error
164 /* send back STATE_UNKOWN if there's an error 163 send back STATE_OK if we connect
165 send back STATE_OK if we connect 164 send back STATE_CRITICAL if we can't connect.
166 send back STATE_CRITICAL if we can't connect. 165 Let upstream figure out what to send to the user. */
167 Let upstream figure out what to send to the user. */ 166 bool is_socket = (host_name[0] == '/');
168 struct addrinfo hints; 167 int socktype = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
169 struct addrinfo *r, *res; 168
170 struct sockaddr_un su; 169 struct addrinfo hints = {};
171 char port_str[6], host[MAX_HOST_ADDRESS_LENGTH]; 170 struct addrinfo *res = NULL;
172 size_t len; 171 int result;
173 int socktype, result;
174 short is_socket = (host_name[0] == '/');
175
176 socktype = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
177
178 /* as long as it doesn't start with a '/', it's assumed a host or ip */ 172 /* as long as it doesn't start with a '/', it's assumed a host or ip */
179 if (!is_socket){ 173 if (!is_socket) {
180 memset (&hints, 0, sizeof (hints)); 174 memset(&hints, 0, sizeof(hints));
181 hints.ai_family = address_family; 175 hints.ai_family = address_family;
182 hints.ai_protocol = proto; 176 hints.ai_protocol = proto;
183 hints.ai_socktype = socktype; 177 hints.ai_socktype = socktype;
184 178
185 len = strlen (host_name); 179 size_t len = strlen(host_name);
186 /* check for an [IPv6] address (and strip the brackets) */ 180 /* check for an [IPv6] address (and strip the brackets) */
187 if (len >= 2 && host_name[0] == '[' && host_name[len - 1] == ']') { 181 if (len >= 2 && host_name[0] == '[' && host_name[len - 1] == ']') {
188 host_name++; 182 host_name++;
189 len -= 2; 183 len -= 2;
190 } 184 }
191 if (len >= sizeof(host)) 185
186 char host[MAX_HOST_ADDRESS_LENGTH];
187
188 if (len >= sizeof(host)) {
192 return STATE_UNKNOWN; 189 return STATE_UNKNOWN;
193 memcpy (host, host_name, len); 190 }
191
192 memcpy(host, host_name, len);
194 host[len] = '\0'; 193 host[len] = '\0';
195 snprintf (port_str, sizeof (port_str), "%d", port);
196 result = getaddrinfo (host, port_str, &hints, &res);
197 194
198 if (result != 0) { 195 char port_str[6];
199 printf ("%s\n", gai_strerror (result)); 196 snprintf(port_str, sizeof(port_str), "%d", port);
197 int getaddrinfo_err = getaddrinfo(host, port_str, &hints, &res);
198
199 if (getaddrinfo_err != 0) {
200 // printf("%s\n", gai_strerror(result));
200 return STATE_UNKNOWN; 201 return STATE_UNKNOWN;
201 } 202 }
202 203
203 r = res; 204 struct addrinfo *addressPointer = res;
204 while (r) { 205 while (addressPointer) {
205 /* attempt to create a socket */ 206 /* attempt to create a socket */
206 *sd = socket (r->ai_family, socktype, r->ai_protocol); 207 *socketDescriptor =
208 socket(addressPointer->ai_family, socktype, addressPointer->ai_protocol);
207 209
208 if (*sd < 0) { 210 if (*socketDescriptor < 0) {
209 printf ("%s\n", _("Socket creation failed")); 211 // printf("%s\n", _("Socket creation failed"));
210 freeaddrinfo (r); 212 freeaddrinfo(addressPointer);
211 return STATE_UNKNOWN; 213 return STATE_UNKNOWN;
212 } 214 }
213 215
214 /* attempt to open a connection */ 216 /* attempt to open a connection */
215 result = connect (*sd, r->ai_addr, r->ai_addrlen); 217 result =
218 connect(*socketDescriptor, addressPointer->ai_addr, addressPointer->ai_addrlen);
216 219
217 if (result == 0) { 220 if (result == 0) {
218 was_refused = false; 221 was_refused = false;
@@ -227,149 +230,157 @@ np_net_connect (const char *host_name, int port, int *sd, int proto)
227 } 230 }
228 } 231 }
229 232
230 close (*sd); 233 close(*socketDescriptor);
231 r = r->ai_next; 234 addressPointer = addressPointer->ai_next;
232 } 235 }
233 freeaddrinfo (res); 236
234 } 237 freeaddrinfo(res);
235 /* else the hostname is interpreted as a path to a unix socket */ 238
236 else { 239 } else {
237 if(strlen(host_name) >= UNIX_PATH_MAX){ 240 /* else the hostname is interpreted as a path to a unix socket */
241 if (strlen(host_name) >= UNIX_PATH_MAX) {
238 die(STATE_UNKNOWN, _("Supplied path too long unix domain socket")); 242 die(STATE_UNKNOWN, _("Supplied path too long unix domain socket"));
239 } 243 }
240 memset(&su, 0, sizeof(su)); 244
245 struct sockaddr_un su = {};
241 su.sun_family = AF_UNIX; 246 su.sun_family = AF_UNIX;
242 strncpy(su.sun_path, host_name, UNIX_PATH_MAX); 247 strncpy(su.sun_path, host_name, UNIX_PATH_MAX);
243 *sd = socket(PF_UNIX, SOCK_STREAM, 0); 248 *socketDescriptor = socket(PF_UNIX, SOCK_STREAM, 0);
244 if(*sd < 0){ 249
250 if (*socketDescriptor < 0) {
245 die(STATE_UNKNOWN, _("Socket creation failed")); 251 die(STATE_UNKNOWN, _("Socket creation failed"));
246 } 252 }
247 result = connect(*sd, (struct sockaddr *)&su, sizeof(su)); 253
248 if (result < 0 && errno == ECONNREFUSED) 254 result = connect(*socketDescriptor, (struct sockaddr *)&su, sizeof(su));
255 if (result < 0 && errno == ECONNREFUSED) {
249 was_refused = true; 256 was_refused = true;
257 }
250 } 258 }
251 259
252 if (result == 0) 260 if (result == 0) {
253 return STATE_OK; 261 return STATE_OK;
254 else if (was_refused) { 262 }
263
264 if (was_refused) {
255 switch (econn_refuse_state) { /* a user-defined expected outcome */ 265 switch (econn_refuse_state) { /* a user-defined expected outcome */
256 case STATE_OK: 266 case STATE_OK:
257 case STATE_WARNING: /* user wants WARN or OK on refusal, or... */ 267 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 */ 268 case STATE_CRITICAL: /* user did not set econn_refuse_state, or wanted critical */
259 if (is_socket) 269 if (is_socket) {
260 printf("connect to file socket %s: %s\n", host_name, strerror(errno)); 270 // printf("connect to file socket %s: %s\n", host_name, strerror(errno));
261 else 271 } else {
262 printf("connect to address %s and port %d: %s\n", 272 // printf("connect to address %s and port %d: %s\n", host_name, port,
263 host_name, port, strerror(errno)); 273 // strerror(errno));
274 }
264 return STATE_CRITICAL; 275 return STATE_CRITICAL;
265 break; 276 break;
266 default: /* it's a logic error if we do not end up in STATE_(OK|WARNING|CRITICAL) */ 277 default: /* it's a logic error if we do not end up in STATE_(OK|WARNING|CRITICAL) */
267 return STATE_UNKNOWN; 278 return STATE_UNKNOWN;
268 break; 279 break;
269 } 280 }
270 } 281 } else {
271 else { 282 if (is_socket) {
272 if (is_socket) 283 // 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)); 284 } else {
274 else 285 // 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", 286 }
276 host_name, port, strerror(errno));
277 return STATE_CRITICAL; 287 return STATE_CRITICAL;
278 } 288 }
279} 289}
280 290
281int 291mp_state_enum send_request(const int socket, const int proto, const char *send_buffer,
282send_request (int sd, int proto, const char *send_buffer, char *recv_buffer, int recv_size) 292 char *recv_buffer, const int recv_size) {
283{ 293 mp_state_enum result = STATE_OK;
284 int result = STATE_OK;
285 int send_result;
286 int recv_result;
287 struct timeval tv;
288 fd_set readfds;
289 294
290 send_result = send (sd, send_buffer, strlen (send_buffer), 0); 295 ssize_t send_result = send(socket, send_buffer, strlen(send_buffer), 0);
291 if (send_result<0 || (size_t)send_result!=strlen(send_buffer)) { 296 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) {
292 printf ("%s\n", _("Send failed")); 297 // printf("%s\n", _("Send failed"));
293 result = STATE_WARNING; 298 result = STATE_WARNING;
294 } 299 }
295 300
296 /* wait up to the number of seconds for socket timeout minus one 301 /* wait up to the number of seconds for socket timeout minus one
297 for data from the host */ 302 for data from the host */
298 tv.tv_sec = socket_timeout - 1; 303 struct timeval timestamp = {
299 tv.tv_usec = 0; 304 .tv_sec = socket_timeout - 1,
300 FD_ZERO (&readfds); 305 .tv_usec = 0,
301 FD_SET (sd, &readfds); 306 };
302 select (sd + 1, &readfds, NULL, NULL, &tv); 307 fd_set readfds;
308 FD_ZERO(&readfds);
309 FD_SET(socket, &readfds);
310 select(socket + 1, &readfds, NULL, NULL, &timestamp);
303 311
304 /* make sure some data has arrived */ 312 /* make sure some data has arrived */
305 if (!FD_ISSET (sd, &readfds)) { 313 if (!FD_ISSET(socket, &readfds)) {
306 strcpy (recv_buffer, ""); 314 strcpy(recv_buffer, "");
307 printf ("%s\n", _("No data was received from host!")); 315 // printf("%s\n", _("No data was received from host!"));
308 result = STATE_WARNING; 316 result = STATE_WARNING;
309 } 317 } else {
310 318 ssize_t recv_result = recv(socket, recv_buffer, (size_t)(recv_size - 1), 0);
311 else {
312 recv_result = recv (sd, recv_buffer, (size_t)recv_size - 1, 0);
313 if (recv_result == -1) { 319 if (recv_result == -1) {
314 strcpy (recv_buffer, ""); 320 strcpy(recv_buffer, "");
315 if (proto != IPPROTO_TCP) 321 if (proto != IPPROTO_TCP) {
316 printf ("%s\n", _("Receive failed")); 322 // printf("%s\n", _("Receive failed"));
323 }
317 result = STATE_WARNING; 324 result = STATE_WARNING;
318 } 325 } else {
319 else
320 recv_buffer[recv_result] = 0; 326 recv_buffer[recv_result] = 0;
327 }
321 328
322 /* die returned string */ 329 /* die returned string */
323 recv_buffer[recv_size - 1] = 0; 330 recv_buffer[recv_size - 1] = 0;
324 } 331 }
332
325 return result; 333 return result;
326} 334}
327 335
328 336bool is_host(const char *address) {
329bool is_host (const char *address) { 337 if (is_addr(address) || is_hostname(address)) {
330 if (is_addr (address) || is_hostname (address))
331 return (true); 338 return (true);
339 }
332 340
333 return (false); 341 return (false);
334} 342}
335 343
336void 344void host_or_die(const char *str) {
337host_or_die(const char *str) 345 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); 346 usage_va(_("Invalid hostname/address - %s"), str);
347 }
341} 348}
342 349
343bool is_addr (const char *address) { 350bool is_addr(const char *address) {
344#ifdef USE_IPV6 351#ifdef USE_IPV6
345 if (address_family == AF_INET && is_inet_addr (address)) 352 if (address_family == AF_INET && is_inet_addr(address)) {
346 return true; 353 return true;
347 else if (address_family == AF_INET6 && is_inet6_addr (address)) 354 }
355
356 if (address_family == AF_INET6 && is_inet6_addr(address)) {
348 return true; 357 return true;
358 }
349#else 359#else
350 if (is_inet_addr (address)) 360 if (is_inet_addr(address)) {
351 return (true); 361 return true;
362 }
352#endif 363#endif
353 364
354 return (false); 365 return false;
355} 366}
356 367
357int 368bool dns_lookup(const char *node_string, struct sockaddr_storage *ss, const int family) {
358dns_lookup (const char *in, struct sockaddr_storage *ss, int family)
359{
360 struct addrinfo hints; 369 struct addrinfo hints;
361 struct addrinfo *res; 370 memset(&hints, 0, sizeof(struct addrinfo));
362 int retval;
363
364 memset (&hints, 0, sizeof(struct addrinfo));
365 hints.ai_family = family; 371 hints.ai_family = family;
366 372
367 retval = getaddrinfo (in, NULL, &hints, &res); 373 struct addrinfo *res;
368 if (retval != 0) 374 int retval = getaddrinfo(node_string, NULL, &hints, &res);
375 if (retval != 0) {
369 return false; 376 return false;
377 }
378
379 if (ss != NULL) {
380 memcpy(ss, res->ai_addr, res->ai_addrlen);
381 }
382
383 freeaddrinfo(res);
370 384
371 if (ss != NULL)
372 memcpy (ss, res->ai_addr, res->ai_addrlen);
373 freeaddrinfo (res);
374 return true; 385 return true;
375} 386}
diff --git a/plugins/netutils.h b/plugins/netutils.h
index a95057e0..c4461113 100644
--- a/plugins/netutils.h
+++ b/plugins/netutils.h
@@ -1,120 +1,120 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring Plugins net utilities include file 3 * Monitoring Plugins net utilities include file
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999 Ethan Galstad (nagios@nagios.org) 6 * Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
7* Copyright (c) 2003-2007 Monitoring Plugins Development Team 7 * Copyright (c) 2003-2007 Monitoring Plugins Development Team
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains common include files and function definitions 11 * This file contains common include files and function definitions
12* used in many of the plugins. 12 * used in many of the plugins.
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 15 * This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31#ifndef _NETUTILS_H_ 31#ifndef _NETUTILS_H_
32#define _NETUTILS_H_ 32#define _NETUTILS_H_
33 33
34#include "common.h" 34#include "output.h"
35#include "states.h"
35#include "utils.h" 36#include "utils.h"
36#include <netinet/in.h> 37#include <netinet/in.h>
37#include <arpa/inet.h> 38#include <arpa/inet.h>
38#include <netdb.h> 39#include <netdb.h>
39 40
40#ifdef HAVE_SYS_UN_H 41#ifdef HAVE_SYS_UN_H
41# include <sys/un.h> 42# include <sys/un.h>
42# ifndef UNIX_PATH_MAX 43# ifndef UNIX_PATH_MAX
43 /* linux uses this, on sun it's hard-coded at 108 without a define, on BSD at 104 */ 44/* linux uses this, on sun it's hard-coded at 108 without a define, on BSD at 104 */
44# define UNIX_PATH_MAX 104 45# define UNIX_PATH_MAX 104
45# endif /* UNIX_PATH_MAX */ 46# endif /* UNIX_PATH_MAX */
46#endif /* HAVE_SYS_UN_H */ 47#endif /* HAVE_SYS_UN_H */
47 48
48#ifndef HOST_MAX_BYTES 49#ifndef HOST_MAX_BYTES
49# define HOST_MAX_BYTES 255 50# define HOST_MAX_BYTES 255
50#endif 51#endif
51 52
52/* process_request and wrapper macros */ 53/* process_request and wrapper macros */
53#define process_tcp_request(addr, port, sbuf, rbuf, rsize) \ 54#define process_tcp_request(addr, port, sbuf, rbuf, rsize) \
54 process_request(addr, port, IPPROTO_TCP, sbuf, rbuf, rsize) 55 process_request(addr, port, IPPROTO_TCP, sbuf, rbuf, rsize)
55#define process_udp_request(addr, port, sbuf, rbuf, rsize) \ 56#define process_udp_request(addr, port, sbuf, rbuf, rsize) \
56 process_request(addr, port, IPPROTO_UDP, sbuf, rbuf, rsize) 57 process_request(addr, port, IPPROTO_UDP, sbuf, rbuf, rsize)
57int process_tcp_request2 (const char *address, int port, 58mp_state_enum process_tcp_request2(const char *server_address, int server_port,
58 const char *sbuffer, char *rbuffer, int rsize); 59 const char *send_buffer, char *recv_buffer, int recv_size);
59int process_request (const char *address, int port, int proto, 60mp_state_enum process_request(const char *server_address, int server_port, int proto,
60 const char *sbuffer, char *rbuffer, int rsize); 61 const char *send_buffer, char *recv_buffer, int recv_size);
61 62
62/* my_connect and wrapper macros */ 63/* my_connect and wrapper macros */
63#define my_tcp_connect(addr, port, s) np_net_connect(addr, port, s, IPPROTO_TCP) 64#define my_tcp_connect(addr, port, s) np_net_connect(addr, port, s, IPPROTO_TCP)
64#define my_udp_connect(addr, port, s) np_net_connect(addr, port, s, IPPROTO_UDP) 65#define my_udp_connect(addr, port, s) np_net_connect(addr, port, s, IPPROTO_UDP)
65int np_net_connect(const char *address, int port, int *sd, int proto); 66mp_state_enum np_net_connect(const char *host_name, int port, int *socketDescriptor, int proto);
66 67
67/* send_request and wrapper macros */ 68/* send_request and wrapper macros */
68#define send_tcp_request(s, sbuf, rbuf, rsize) \ 69#define send_tcp_request(s, sbuf, rbuf, rsize) send_request(s, IPPROTO_TCP, sbuf, rbuf, rsize)
69 send_request(s, IPPROTO_TCP, sbuf, rbuf, rsize) 70#define send_udp_request(s, sbuf, rbuf, rsize) send_request(s, IPPROTO_UDP, sbuf, rbuf, rsize)
70#define send_udp_request(s, sbuf, rbuf, rsize) \ 71mp_state_enum send_request(int socket, int proto, const char *send_buffer, char *recv_buffer,
71 send_request(s, IPPROTO_UDP, sbuf, rbuf, rsize) 72 int recv_size);
72int send_request (int sd, int proto, const char *send_buffer, char *recv_buffer, int recv_size);
73
74 73
75/* "is_*" wrapper macros and functions */ 74/* "is_*" wrapper macros and functions */
76bool is_host (const char *); 75bool is_host(const char *);
77bool is_addr (const char *); 76bool is_addr(const char *);
78int dns_lookup (const char *, struct sockaddr_storage *, int); 77bool dns_lookup(const char *, struct sockaddr_storage *, int);
79void host_or_die(const char *str); 78void host_or_die(const char *str);
80#define resolve_host_or_addr(addr, family) dns_lookup(addr, NULL, family) 79#define resolve_host_or_addr(addr, family) dns_lookup(addr, NULL, family)
81#define is_inet_addr(addr) resolve_host_or_addr(addr, AF_INET) 80#define is_inet_addr(addr) resolve_host_or_addr(addr, AF_INET)
82#ifdef USE_IPV6 81#ifdef USE_IPV6
83# define is_inet6_addr(addr) resolve_host_or_addr(addr, AF_INET6) 82# define is_inet6_addr(addr) resolve_host_or_addr(addr, AF_INET6)
84# define is_hostname(addr) resolve_host_or_addr(addr, address_family) 83# define is_hostname(addr) resolve_host_or_addr(addr, address_family)
85#else 84#else
86# define is_hostname(addr) resolve_host_or_addr(addr, AF_INET) 85# define is_hostname(addr) resolve_host_or_addr(addr, AF_INET)
87#endif 86#endif
88 87
89extern unsigned int socket_timeout; 88extern unsigned int socket_timeout;
90extern unsigned int socket_timeout_state; 89extern mp_state_enum socket_timeout_state;
91extern int econn_refuse_state; 90extern mp_state_enum econn_refuse_state;
92extern bool was_refused; 91extern bool was_refused;
93extern int address_family; 92extern int address_family;
94 93
95void socket_timeout_alarm_handler (int) __attribute__((noreturn)); 94void socket_timeout_alarm_handler(int) __attribute__((noreturn));
96 95
97/* SSL-Related functionality */ 96/* SSL-Related functionality */
98#ifdef HAVE_SSL 97#ifdef HAVE_SSL
99# define MP_SSLv2 1 98# define MP_SSLv2 1
100# define MP_SSLv3 2 99# define MP_SSLv3 2
101# define MP_TLSv1 3 100# define MP_TLSv1 3
102# define MP_TLSv1_1 4 101# define MP_TLSv1_1 4
103# define MP_TLSv1_2 5 102# define MP_TLSv1_2 5
104# define MP_SSLv2_OR_NEWER 6 103# define MP_SSLv2_OR_NEWER 6
105# define MP_SSLv3_OR_NEWER 7 104# define MP_SSLv3_OR_NEWER 7
106# define MP_TLSv1_OR_NEWER 8 105# define MP_TLSv1_OR_NEWER 8
107# define MP_TLSv1_1_OR_NEWER 9 106# define MP_TLSv1_1_OR_NEWER 9
108# define MP_TLSv1_2_OR_NEWER 10 107# define MP_TLSv1_2_OR_NEWER 10
109/* maybe this could be merged with the above np_net_connect, via some flags */ 108/* maybe this could be merged with the above np_net_connect, via some flags */
110int np_net_ssl_init(int sd); 109int np_net_ssl_init(int socket);
111int np_net_ssl_init_with_hostname(int sd, char *host_name); 110int np_net_ssl_init_with_hostname(int socket, char *host_name);
112int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int version); 111int np_net_ssl_init_with_hostname_and_version(int socket, char *host_name, int version);
113int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int version, char *cert, char *privkey); 112int np_net_ssl_init_with_hostname_version_and_cert(int socket, char *host_name, int version,
114void np_net_ssl_cleanup(); 113 char *cert, char *privkey);
114void np_net_ssl_cleanup(void);
115int np_net_ssl_write(const void *buf, int num); 115int np_net_ssl_write(const void *buf, int num);
116int np_net_ssl_read(void *buf, int num); 116int np_net_ssl_read(void *buf, int num);
117int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit); 117mp_state_enum np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit);
118mp_subcheck mp_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit);
118#endif /* HAVE_SSL */ 119#endif /* HAVE_SSL */
119
120#endif /* _NETUTILS_H_ */ 120#endif /* _NETUTILS_H_ */
diff --git a/plugins/picohttpparser/picohttpparser.c b/plugins/picohttpparser/picohttpparser.c
index d0bfac62..e87388b0 100644
--- a/plugins/picohttpparser/picohttpparser.c
+++ b/plugins/picohttpparser/picohttpparser.c
@@ -28,622 +28,640 @@
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 =
97 "\0\1\0\1\1\1\1\1\0\0\1\1\0\1\1\0\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0" 97 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
98 "\0\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\1\1" 98 "\0\1\0\1\1\1\1\1\0\0\1\1\0\1\1\0\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0"
99 "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\1\0\1\0" 99 "\0\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\1\1"
100 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" 100 "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\1\0\1\0"
101 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" 101 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
102 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" 102 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
103 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 103 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
104 104 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
105static const char *findchar_fast(const char *buf, const char *buf_end, const char *ranges, size_t ranges_size, int *found) 105
106{ 106static const char *findchar_fast(const char *buf, const char *buf_end, const char *ranges,
107 *found = 0; 107 size_t ranges_size, int *found) {
108 *found = 0;
108#if __SSE4_2__ 109#if __SSE4_2__
109 if (likely(buf_end - buf >= 16)) { 110 if (likely(buf_end - buf >= 16)) {
110 __m128i ranges16 = _mm_loadu_si128((const __m128i *)ranges); 111 __m128i ranges16 = _mm_loadu_si128((const __m128i *)ranges);
111 112
112 size_t left = (buf_end - buf) & ~15; 113 size_t left = (buf_end - buf) & ~15;
113 do { 114 do {
114 __m128i b16 = _mm_loadu_si128((const __m128i *)buf); 115 __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); 116 int r = _mm_cmpestri(ranges16, ranges_size, b16, 16,
116 if (unlikely(r != 16)) { 117 _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS);
117 buf += r; 118 if (unlikely(r != 16)) {
118 *found = 1; 119 buf += r;
119 break; 120 *found = 1;
120 } 121 break;
121 buf += 16; 122 }
122 left -= 16; 123 buf += 16;
123 } while (likely(left != 0)); 124 left -= 16;
124 } 125 } while (likely(left != 0));
126 }
125#else 127#else
126 /* suppress unused parameter warning */ 128 /* suppress unused parameter warning */
127 (void)buf_end; 129 (void)buf_end;
128 (void)ranges; 130 (void)ranges;
129 (void)ranges_size; 131 (void)ranges_size;
130#endif 132#endif
131 return buf; 133 return buf;
132} 134}
133 135
134static const char *get_token_to_eol(const char *buf, const char *buf_end, const char **token, size_t *token_len, int *ret) 136static const char *get_token_to_eol(const char *buf, const char *buf_end, const char **token,
135{ 137 size_t *token_len, int *ret) {
136 const char *token_start = buf; 138 const char *token_start = buf;
137 139
138#ifdef __SSE4_2__ 140#ifdef __SSE4_2__
139 static const char ALIGNED(16) ranges1[16] = "\0\010" /* allow HT */ 141 static const char ALIGNED(16) ranges1[16] =
140 "\012\037" /* allow SP and up to but not including DEL */ 142 "\0\010" /* allow HT */
141 "\177\177"; /* allow chars w. MSB set */ 143 "\012\037" /* allow SP and up to but not including DEL */
142 int found; 144 "\177\177"; /* allow chars w. MSB set */
143 buf = findchar_fast(buf, buf_end, ranges1, 6, &found); 145 int found;
144 if (found) 146 buf = findchar_fast(buf, buf_end, ranges1, 6, &found);
145 goto FOUND_CTL; 147 if (found) {
148 goto FOUND_CTL;
149 }
146#else 150#else
147 /* find non-printable char within the next 8 bytes, this is the hottest code; manually inlined */ 151 /* find non-printable char within the next 8 bytes, this is the hottest code; manually inlined
148 while (likely(buf_end - buf >= 8)) { 152 */
149#define DOIT() \ 153 while (likely(buf_end - buf >= 8)) {
150 do { \ 154# define DOIT() \
151 if (unlikely(!IS_PRINTABLE_ASCII(*buf))) \ 155 do { \
152 goto NonPrintable; \ 156 if (unlikely(!IS_PRINTABLE_ASCII(*buf))) \
153 ++buf; \ 157 goto NonPrintable; \
154 } while (0) 158 ++buf; \
155 DOIT(); 159 } while (0)
156 DOIT(); 160 DOIT();
157 DOIT(); 161 DOIT();
158 DOIT(); 162 DOIT();
159 DOIT(); 163 DOIT();
160 DOIT(); 164 DOIT();
161 DOIT(); 165 DOIT();
162 DOIT(); 166 DOIT();
163#undef DOIT 167 DOIT();
164 continue; 168# undef DOIT
165 NonPrintable: 169 continue;
166 if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) { 170 NonPrintable:
167 goto FOUND_CTL; 171 if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) ||
168 } 172 unlikely(*buf == '\177')) {
169 ++buf; 173 goto FOUND_CTL;
170 } 174 }
175 ++buf;
176 }
171#endif 177#endif
172 for (;; ++buf) { 178 for (;; ++buf) {
173 CHECK_EOF(); 179 CHECK_EOF();
174 if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { 180 if (unlikely(!IS_PRINTABLE_ASCII(*buf))) {
175 if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) { 181 if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) ||
176 goto FOUND_CTL; 182 unlikely(*buf == '\177')) {
177 } 183 goto FOUND_CTL;
178 } 184 }
179 } 185 }
186 }
180FOUND_CTL: 187FOUND_CTL:
181 if (likely(*buf == '\015')) { 188 if (likely(*buf == '\015')) {
182 ++buf; 189 ++buf;
183 EXPECT_CHAR('\012'); 190 EXPECT_CHAR('\012');
184 *token_len = buf - 2 - token_start; 191 *token_len = buf - 2 - token_start;
185 } else if (*buf == '\012') { 192 } else if (*buf == '\012') {
186 *token_len = buf - token_start; 193 *token_len = buf - token_start;
187 ++buf; 194 ++buf;
188 } else { 195 } else {
189 *ret = -1; 196 *ret = -1;
190 return NULL; 197 return NULL;
191 } 198 }
192 *token = token_start; 199 *token = token_start;
193 200
194 return buf; 201 return buf;
195} 202}
196 203
197static const char *is_complete(const char *buf, const char *buf_end, size_t last_len, int *ret) 204static const char *is_complete(const char *buf, const char *buf_end, size_t last_len, int *ret) {
198{ 205 int ret_cnt = 0;
199 int ret_cnt = 0; 206 buf = last_len < 3 ? buf : buf + last_len - 3;
200 buf = last_len < 3 ? buf : buf + last_len - 3; 207
201 208 while (1) {
202 while (1) { 209 CHECK_EOF();
203 CHECK_EOF(); 210 if (*buf == '\015') {
204 if (*buf == '\015') { 211 ++buf;
205 ++buf; 212 CHECK_EOF();
206 CHECK_EOF(); 213 EXPECT_CHAR('\012');
207 EXPECT_CHAR('\012'); 214 ++ret_cnt;
208 ++ret_cnt; 215 } else if (*buf == '\012') {
209 } else if (*buf == '\012') { 216 ++buf;
210 ++buf; 217 ++ret_cnt;
211 ++ret_cnt; 218 } else {
212 } else { 219 ++buf;
213 ++buf; 220 ret_cnt = 0;
214 ret_cnt = 0; 221 }
215 } 222 if (ret_cnt == 2) {
216 if (ret_cnt == 2) { 223 return buf;
217 return buf; 224 }
218 } 225 }
219 } 226
220 227 *ret = -2;
221 *ret = -2; 228 return NULL;
222 return NULL;
223} 229}
224 230
225#define PARSE_INT(valp_, mul_) \ 231#define PARSE_INT(valp_, mul_) \
226 if (*buf < '0' || '9' < *buf) { \ 232 if (*buf < '0' || '9' < *buf) { \
227 buf++; \ 233 buf++; \
228 *ret = -1; \ 234 *ret = -1; \
229 return NULL; \ 235 return NULL; \
230 } \ 236 } \
231 *(valp_) = (mul_) * (*buf++ - '0'); 237 *(valp_) = (mul_) * (*buf++ - '0');
232 238
233#define PARSE_INT_3(valp_) \ 239#define PARSE_INT_3(valp_) \
234 do { \ 240 do { \
235 int res_ = 0; \ 241 int res_ = 0; \
236 PARSE_INT(&res_, 100) \ 242 PARSE_INT(&res_, 100) \
237 *valp_ = res_; \ 243 *valp_ = res_; \
238 PARSE_INT(&res_, 10) \ 244 PARSE_INT(&res_, 10) \
239 *valp_ += res_; \ 245 *valp_ += res_; \
240 PARSE_INT(&res_, 1) \ 246 PARSE_INT(&res_, 1) \
241 *valp_ += res_; \ 247 *valp_ += res_; \
242 } while (0) 248 } while (0)
243 249
244/* returned pointer is always within [buf, buf_end), or null */ 250/* 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) 251static const char *parse_http_version(const char *buf, const char *buf_end, int *major_version,
246{ 252 int *minor_version, int *ret) {
247 /* we want at least [HTTP/1.<two chars>] to try to parse */ 253 /* we want at least [HTTP/1.<two chars>] to try to parse */
248 if (buf_end - buf < 9) { 254 if (buf_end - buf < 9) {
249 *ret = -2; 255 *ret = -2;
250 return NULL; 256 return NULL;
251 } 257 }
252 EXPECT_CHAR_NO_CHECK('H'); 258 EXPECT_CHAR_NO_CHECK('H');
253 EXPECT_CHAR_NO_CHECK('T'); 259 EXPECT_CHAR_NO_CHECK('T');
254 EXPECT_CHAR_NO_CHECK('T'); 260 EXPECT_CHAR_NO_CHECK('T');
255 EXPECT_CHAR_NO_CHECK('P'); 261 EXPECT_CHAR_NO_CHECK('P');
256 EXPECT_CHAR_NO_CHECK('/'); 262 EXPECT_CHAR_NO_CHECK('/');
257 PARSE_INT(major_version, 1); 263 PARSE_INT(major_version, 1);
258 if (*major_version == 1) { 264 if (*major_version == 1) {
259 EXPECT_CHAR_NO_CHECK('.'); 265 EXPECT_CHAR_NO_CHECK('.');
260 PARSE_INT(minor_version, 1); 266 PARSE_INT(minor_version, 1);
261 } else { 267 } else {
262 *minor_version = 0; 268 *minor_version = 0;
263 } 269 }
264 return buf; 270 return buf;
265} 271}
266 272
267static const char *parse_headers(const char *buf, const char *buf_end, struct phr_header *headers, size_t *num_headers, 273static const char *parse_headers(const char *buf, const char *buf_end, struct phr_header *headers,
268 size_t max_headers, int *ret) 274 size_t *num_headers, size_t max_headers, int *ret) {
269{ 275 for (;; ++*num_headers) {
270 for (;; ++*num_headers) { 276 CHECK_EOF();
271 CHECK_EOF(); 277 if (*buf == '\015') {
272 if (*buf == '\015') { 278 ++buf;
273 ++buf; 279 EXPECT_CHAR('\012');
274 EXPECT_CHAR('\012'); 280 break;
275 break; 281 } else if (*buf == '\012') {
276 } else if (*buf == '\012') { 282 ++buf;
277 ++buf; 283 break;
278 break; 284 }
279 } 285 if (*num_headers == max_headers) {
280 if (*num_headers == max_headers) { 286 *ret = -1;
281 *ret = -1; 287 return NULL;
282 return NULL; 288 }
283 } 289 if (!(*num_headers != 0 && (*buf == ' ' || *buf == '\t'))) {
284 if (!(*num_headers != 0 && (*buf == ' ' || *buf == '\t'))) { 290 /* parsing name, but do not discard SP before colon, see
285 /* parsing name, but do not discard SP before colon, see 291 * http://www.mozilla.org/security/announce/2006/mfsa2006-33.html */
286 * http://www.mozilla.org/security/announce/2006/mfsa2006-33.html */ 292 headers[*num_headers].name = buf;
287 headers[*num_headers].name = buf; 293 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 */ 294 "\"\"" /* 0x22 */
289 "\"\"" /* 0x22 */ 295 "()" /* 0x28,0x29 */
290 "()" /* 0x28,0x29 */ 296 ",," /* 0x2c */
291 ",," /* 0x2c */ 297 "//" /* 0x2f */
292 "//" /* 0x2f */ 298 ":@" /* 0x3a-0x40 */
293 ":@" /* 0x3a-0x40 */ 299 "[]" /* 0x5b-0x5d */
294 "[]" /* 0x5b-0x5d */ 300 "{\377"; /* 0x7b-0xff */
295 "{\377"; /* 0x7b-0xff */ 301 int found;
296 int found; 302 buf = findchar_fast(buf, buf_end, ranges1, sizeof(ranges1) - 1, &found);
297 buf = findchar_fast(buf, buf_end, ranges1, sizeof(ranges1) - 1, &found); 303 if (!found) {
298 if (!found) { 304 CHECK_EOF();
299 CHECK_EOF(); 305 }
300 } 306 while (1) {
301 while (1) { 307 if (*buf == ':') {
302 if (*buf == ':') { 308 break;
303 break; 309 } else if (!token_char_map[(unsigned char)*buf]) {
304 } else if (!token_char_map[(unsigned char)*buf]) { 310 *ret = -1;
305 *ret = -1; 311 return NULL;
306 return NULL; 312 }
307 } 313 ++buf;
308 ++buf; 314 CHECK_EOF();
309 CHECK_EOF(); 315 }
310 } 316 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) { 317 *ret = -1;
312 *ret = -1; 318 return NULL;
313 return NULL; 319 }
314 } 320 ++buf;
315 ++buf; 321 for (;; ++buf) {
316 for (;; ++buf) { 322 CHECK_EOF();
317 CHECK_EOF(); 323 if (!(*buf == ' ' || *buf == '\t')) {
318 if (!(*buf == ' ' || *buf == '\t')) { 324 break;
319 break; 325 }
320 } 326 }
321 } 327 } else {
322 } else { 328 headers[*num_headers].name = NULL;
323 headers[*num_headers].name = NULL; 329 headers[*num_headers].name_len = 0;
324 headers[*num_headers].name_len = 0; 330 }
325 } 331 const char *value;
326 const char *value; 332 size_t value_len;
327 size_t value_len; 333 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) { 334 return NULL;
329 return NULL; 335 }
330 } 336 /* remove trailing SPs and HTABs */
331 /* remove trailing SPs and HTABs */ 337 const char *value_end = value + value_len;
332 const char *value_end = value + value_len; 338 for (; value_end != value; --value_end) {
333 for (; value_end != value; --value_end) { 339 const char c = *(value_end - 1);
334 const char c = *(value_end - 1); 340 if (!(c == ' ' || c == '\t')) {
335 if (!(c == ' ' || c == '\t')) { 341 break;
336 break; 342 }
337 } 343 }
338 } 344 headers[*num_headers].value = value;
339 headers[*num_headers].value = value; 345 headers[*num_headers].value_len = value_end - value;
340 headers[*num_headers].value_len = value_end - value; 346 }
341 } 347 return buf;
342 return buf;
343} 348}
344 349
345static const char *parse_request(const char *buf, const char *buf_end, const char **method, size_t *method_len, const char **path, 350static const char *parse_request(const char *buf, const char *buf_end, const char **method,
346 size_t *path_len, int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers, 351 size_t *method_len, const char **path, size_t *path_len,
347 size_t max_headers, int *ret) 352 int *major_version, int *minor_version, struct phr_header *headers,
348{ 353 size_t *num_headers, size_t max_headers, int *ret) {
349 /* skip first empty line (some clients add CRLF after POST content) */ 354 /* skip first empty line (some clients add CRLF after POST content) */
350 CHECK_EOF(); 355 CHECK_EOF();
351 if (*buf == '\015') { 356 if (*buf == '\015') {
352 ++buf; 357 ++buf;
353 EXPECT_CHAR('\012'); 358 EXPECT_CHAR('\012');
354 } else if (*buf == '\012') { 359 } else if (*buf == '\012') {
355 ++buf; 360 ++buf;
356 } 361 }
357 362
358 /* parse request line */ 363 /* parse request line */
359 ADVANCE_TOKEN(*method, *method_len); 364 ADVANCE_TOKEN(*method, *method_len);
360 do { 365 do {
361 ++buf; 366 ++buf;
362 } while (*buf == ' '); 367 } while (*buf == ' ');
363 ADVANCE_TOKEN(*path, *path_len); 368 ADVANCE_TOKEN(*path, *path_len);
364 do { 369 do {
365 ++buf; 370 ++buf;
366 } while (*buf == ' '); 371 } while (*buf == ' ');
367 if (*method_len == 0 || *path_len == 0) { 372 if (*method_len == 0 || *path_len == 0) {
368 *ret = -1; 373 *ret = -1;
369 return NULL; 374 return NULL;
370 } 375 }
371 if ((buf = parse_http_version(buf, buf_end, major_version, minor_version, ret)) == NULL) { 376 if ((buf = parse_http_version(buf, buf_end, major_version, minor_version, ret)) == NULL) {
372 return NULL; 377 return NULL;
373 } 378 }
374 if (*buf == '\015') { 379 if (*buf == '\015') {
375 ++buf; 380 ++buf;
376 EXPECT_CHAR('\012'); 381 EXPECT_CHAR('\012');
377 } else if (*buf == '\012') { 382 } else if (*buf == '\012') {
378 ++buf; 383 ++buf;
379 } else { 384 } else {
380 *ret = -1; 385 *ret = -1;
381 return NULL; 386 return NULL;
382 } 387 }
383 388
384 return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret); 389 return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret);
385} 390}
386 391
387int phr_parse_request(const char *buf_start, size_t len, const char **method, size_t *method_len, const char **path, 392int phr_parse_request(const char *buf_start, size_t len, const char **method, size_t *method_len,
388 size_t *path_len, int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len) 393 const char **path, size_t *path_len, int *major_version, int *minor_version,
389{ 394 struct phr_header *headers, size_t *num_headers, size_t last_len) {
390 const char *buf = buf_start, *buf_end = buf_start + len; 395 const char *buf = buf_start, *buf_end = buf_start + len;
391 size_t max_headers = *num_headers; 396 size_t max_headers = *num_headers;
392 int r; 397 int r;
393 398
394 *method = NULL; 399 *method = NULL;
395 *method_len = 0; 400 *method_len = 0;
396 *path = NULL; 401 *path = NULL;
397 *path_len = 0; 402 *path_len = 0;
398 *major_version = -1; 403 *major_version = -1;
399 *minor_version = -1; 404 *minor_version = -1;
400 *num_headers = 0; 405 *num_headers = 0;
401 406
402 /* if last_len != 0, check if the request is complete (a fast countermeasure 407 /* if last_len != 0, check if the request is complete (a fast countermeasure
403 against slowloris */ 408 against slowloris */
404 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { 409 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) {
405 return r; 410 return r;
406 } 411 }
407 412
408 if ((buf = parse_request(buf, buf_end, method, method_len, path, path_len, major_version, minor_version, headers, num_headers, max_headers, 413 if ((buf = parse_request(buf, buf_end, method, method_len, path, path_len, major_version,
409 &r)) == NULL) { 414 minor_version, headers, num_headers, max_headers, &r)) == NULL) {
410 return r; 415 return r;
411 } 416 }
412 417
413 return (int)(buf - buf_start); 418 return (int)(buf - buf_start);
414} 419}
415 420
416static const char *parse_response(const char *buf, const char *buf_end, int *major_version, int *minor_version, int *status, const char **msg, 421static const char *parse_response(const char *buf, const char *buf_end, int *major_version,
417 size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t max_headers, int *ret) 422 int *minor_version, int *status, const char **msg,
418{ 423 size_t *msg_len, struct phr_header *headers, size_t *num_headers,
419 /* parse "HTTP/1.x" */ 424 size_t max_headers, int *ret) {
420 if ((buf = parse_http_version(buf, buf_end, major_version, minor_version, ret)) == NULL) { 425 /* parse "HTTP/1.x" */
421 return NULL; 426 if ((buf = parse_http_version(buf, buf_end, major_version, minor_version, ret)) == NULL) {
422 } 427 return NULL;
423 /* skip space */ 428 }
424 if (*buf != ' ') { 429 /* skip space */
425 *ret = -1; 430 if (*buf != ' ') {
426 return NULL; 431 *ret = -1;
427 } 432 return NULL;
428 do { 433 }
429 ++buf; 434 do {
430 } while (*buf == ' '); 435 ++buf;
431 /* parse status code, we want at least [:digit:][:digit:][:digit:]<other char> to try to parse */ 436 } while (*buf == ' ');
432 if (buf_end - buf < 4) { 437 /* parse status code, we want at least [:digit:][:digit:][:digit:]<other char> to try to parse
433 *ret = -2; 438 */
434 return NULL; 439 if (buf_end - buf < 4) {
435 } 440 *ret = -2;
436 PARSE_INT_3(status); 441 return NULL;
437 442 }
438 /* get message including preceding space */ 443 PARSE_INT_3(status);
439 if ((buf = get_token_to_eol(buf, buf_end, msg, msg_len, ret)) == NULL) { 444
440 return NULL; 445 /* get message including preceding space */
441 } 446 if ((buf = get_token_to_eol(buf, buf_end, msg, msg_len, ret)) == NULL) {
442 if (*msg_len == 0) { 447 return NULL;
443 /* ok */ 448 }
444 } else if (**msg == ' ') { 449 if (*msg_len == 0) {
445 /* remove preceding space */ 450 /* ok */
446 do { 451 } else if (**msg == ' ') {
447 ++*msg; 452 /* remove preceding space */
448 --*msg_len; 453 do {
449 } while (**msg == ' '); 454 ++*msg;
450 } else { 455 --*msg_len;
451 /* garbage found after status code */ 456 } while (**msg == ' ');
452 *ret = -1; 457 } else {
453 return NULL; 458 /* garbage found after status code */
454 } 459 *ret = -1;
455 460 return NULL;
456 return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret); 461 }
462
463 return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret);
457} 464}
458 465
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, 466int phr_parse_response(const char *buf_start, size_t len, int *major_version, int *minor_version,
460 struct phr_header *headers, size_t *num_headers, size_t last_len) 467 int *status, const char **msg, size_t *msg_len, struct phr_header *headers,
461{ 468 size_t *num_headers, size_t last_len) {
462 const char *buf = buf_start, *buf_end = buf + len; 469 const char *buf = buf_start, *buf_end = buf + len;
463 size_t max_headers = *num_headers; 470 size_t max_headers = *num_headers;
464 int r; 471 int r;
465 472
466 *major_version = -1; 473 *major_version = -1;
467 *minor_version = -1; 474 *minor_version = -1;
468 *status = 0; 475 *status = 0;
469 *msg = NULL; 476 *msg = NULL;
470 *msg_len = 0; 477 *msg_len = 0;
471 *num_headers = 0; 478 *num_headers = 0;
472 479
473 /* if last_len != 0, check if the response is complete (a fast countermeasure 480 /* if last_len != 0, check if the response is complete (a fast countermeasure
474 against slowloris */ 481 against slowloris */
475 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { 482 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) {
476 return r; 483 return r;
477 } 484 }
478 485
479 if ((buf = parse_response(buf, buf_end, major_version, minor_version, status, msg, msg_len, headers, num_headers, max_headers, &r)) == NULL) { 486 if ((buf = parse_response(buf, buf_end, major_version, minor_version, status, msg, msg_len,
480 return r; 487 headers, num_headers, max_headers, &r)) == NULL) {
481 } 488 return r;
482 489 }
483 return (int)(buf - buf_start); 490
491 return (int)(buf - buf_start);
484} 492}
485 493
486int phr_parse_headers(const char *buf_start, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len) 494int phr_parse_headers(const char *buf_start, size_t len, struct phr_header *headers,
487{ 495 size_t *num_headers, size_t last_len) {
488 const char *buf = buf_start, *buf_end = buf + len; 496 const char *buf = buf_start, *buf_end = buf + len;
489 size_t max_headers = *num_headers; 497 size_t max_headers = *num_headers;
490 int r; 498 int r;
491 499
492 *num_headers = 0; 500 *num_headers = 0;
493 501
494 /* if last_len != 0, check if the response is complete (a fast countermeasure 502 /* if last_len != 0, check if the response is complete (a fast countermeasure
495 against slowloris */ 503 against slowloris */
496 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { 504 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) {
497 return r; 505 return r;
498 } 506 }
499 507
500 if ((buf = parse_headers(buf, buf_end, headers, num_headers, max_headers, &r)) == NULL) { 508 if ((buf = parse_headers(buf, buf_end, headers, num_headers, max_headers, &r)) == NULL) {
501 return r; 509 return r;
502 } 510 }
503 511
504 return (int)(buf - buf_start); 512 return (int)(buf - buf_start);
505} 513}
506 514
507enum { 515enum {
508 CHUNKED_IN_CHUNK_SIZE, 516 CHUNKED_IN_CHUNK_SIZE,
509 CHUNKED_IN_CHUNK_EXT, 517 CHUNKED_IN_CHUNK_EXT,
510 CHUNKED_IN_CHUNK_DATA, 518 CHUNKED_IN_CHUNK_DATA,
511 CHUNKED_IN_CHUNK_CRLF, 519 CHUNKED_IN_CHUNK_CRLF,
512 CHUNKED_IN_TRAILERS_LINE_HEAD, 520 CHUNKED_IN_TRAILERS_LINE_HEAD,
513 CHUNKED_IN_TRAILERS_LINE_MIDDLE 521 CHUNKED_IN_TRAILERS_LINE_MIDDLE
514}; 522};
515 523
516static int decode_hex(int ch) 524static int decode_hex(int ch) {
517{ 525 if ('0' <= ch && ch <= '9') {
518 if ('0' <= ch && ch <= '9') { 526 return ch - '0';
519 return ch - '0'; 527 } else if ('A' <= ch && ch <= 'F') {
520 } else if ('A' <= ch && ch <= 'F') { 528 return ch - 'A' + 0xa;
521 return ch - 'A' + 0xa; 529 } else if ('a' <= ch && ch <= 'f') {
522 } else if ('a' <= ch && ch <= 'f') { 530 return ch - 'a' + 0xa;
523 return ch - 'a' + 0xa; 531 } else {
524 } else { 532 return -1;
525 return -1; 533 }
526 }
527} 534}
528 535
529ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *_bufsz) 536ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *_bufsz) {
530{ 537 size_t dst = 0, src = 0, bufsz = *_bufsz;
531 size_t dst = 0, src = 0, bufsz = *_bufsz; 538 ssize_t ret = -2; /* incomplete */
532 ssize_t ret = -2; /* incomplete */ 539
533 540 while (1) {
534 while (1) { 541 switch (decoder->_state) {
535 switch (decoder->_state) { 542 case CHUNKED_IN_CHUNK_SIZE:
536 case CHUNKED_IN_CHUNK_SIZE: 543 for (;; ++src) {
537 for (;; ++src) { 544 int v;
538 int v; 545 if (src == bufsz) {
539 if (src == bufsz) 546 goto Exit;
540 goto Exit; 547 }
541 if ((v = decode_hex(buf[src])) == -1) { 548 if ((v = decode_hex(buf[src])) == -1) {
542 if (decoder->_hex_count == 0) { 549 if (decoder->_hex_count == 0) {
543 ret = -1; 550 ret = -1;
544 goto Exit; 551 goto Exit;
545 } 552 }
546 break; 553 break;
547 } 554 }
548 if (decoder->_hex_count == sizeof(size_t) * 2) { 555 if (decoder->_hex_count == sizeof(size_t) * 2) {
549 ret = -1; 556 ret = -1;
550 goto Exit; 557 goto Exit;
551 } 558 }
552 decoder->bytes_left_in_chunk = decoder->bytes_left_in_chunk * 16 + v; 559 decoder->bytes_left_in_chunk = decoder->bytes_left_in_chunk * 16 + v;
553 ++decoder->_hex_count; 560 ++decoder->_hex_count;
554 } 561 }
555 decoder->_hex_count = 0; 562 decoder->_hex_count = 0;
556 decoder->_state = CHUNKED_IN_CHUNK_EXT; 563 decoder->_state = CHUNKED_IN_CHUNK_EXT;
557 /* fallthru */ 564 /* fallthru */
558 case CHUNKED_IN_CHUNK_EXT: 565 case CHUNKED_IN_CHUNK_EXT:
559 /* RFC 7230 A.2 "Line folding in chunk extensions is disallowed" */ 566 /* RFC 7230 A.2 "Line folding in chunk extensions is disallowed" */
560 for (;; ++src) { 567 for (;; ++src) {
561 if (src == bufsz) 568 if (src == bufsz) {
562 goto Exit; 569 goto Exit;
563 if (buf[src] == '\012') 570 }
564 break; 571 if (buf[src] == '\012') {
565 } 572 break;
566 ++src; 573 }
567 if (decoder->bytes_left_in_chunk == 0) { 574 }
568 if (decoder->consume_trailer) { 575 ++src;
569 decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD; 576 if (decoder->bytes_left_in_chunk == 0) {
570 break; 577 if (decoder->consume_trailer) {
571 } else { 578 decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD;
572 goto Complete; 579 break;
573 } 580 } else {
574 } 581 goto Complete;
575 decoder->_state = CHUNKED_IN_CHUNK_DATA; 582 }
576 /* fallthru */ 583 }
577 case CHUNKED_IN_CHUNK_DATA: { 584 decoder->_state = CHUNKED_IN_CHUNK_DATA;
578 size_t avail = bufsz - src; 585 /* fallthru */
579 if (avail < decoder->bytes_left_in_chunk) { 586 case CHUNKED_IN_CHUNK_DATA: {
580 if (dst != src) 587 size_t avail = bufsz - src;
581 memmove(buf + dst, buf + src, avail); 588 if (avail < decoder->bytes_left_in_chunk) {
582 src += avail; 589 if (dst != src) {
583 dst += avail; 590 memmove(buf + dst, buf + src, avail);
584 decoder->bytes_left_in_chunk -= avail; 591 }
585 goto Exit; 592 src += avail;
586 } 593 dst += avail;
587 if (dst != src) 594 decoder->bytes_left_in_chunk -= avail;
588 memmove(buf + dst, buf + src, decoder->bytes_left_in_chunk); 595 goto Exit;
589 src += decoder->bytes_left_in_chunk; 596 }
590 dst += decoder->bytes_left_in_chunk; 597 if (dst != src) {
591 decoder->bytes_left_in_chunk = 0; 598 memmove(buf + dst, buf + src, decoder->bytes_left_in_chunk);
592 decoder->_state = CHUNKED_IN_CHUNK_CRLF; 599 }
593 } 600 src += decoder->bytes_left_in_chunk;
594 /* fallthru */ 601 dst += decoder->bytes_left_in_chunk;
595 case CHUNKED_IN_CHUNK_CRLF: 602 decoder->bytes_left_in_chunk = 0;
596 for (;; ++src) { 603 decoder->_state = CHUNKED_IN_CHUNK_CRLF;
597 if (src == bufsz) 604 }
598 goto Exit; 605 /* fallthru */
599 if (buf[src] != '\015') 606 case CHUNKED_IN_CHUNK_CRLF:
600 break; 607 for (;; ++src) {
601 } 608 if (src == bufsz) {
602 if (buf[src] != '\012') { 609 goto Exit;
603 ret = -1; 610 }
604 goto Exit; 611 if (buf[src] != '\015') {
605 } 612 break;
606 ++src; 613 }
607 decoder->_state = CHUNKED_IN_CHUNK_SIZE; 614 }
608 break; 615 if (buf[src] != '\012') {
609 case CHUNKED_IN_TRAILERS_LINE_HEAD: 616 ret = -1;
610 for (;; ++src) { 617 goto Exit;
611 if (src == bufsz) 618 }
612 goto Exit; 619 ++src;
613 if (buf[src] != '\015') 620 decoder->_state = CHUNKED_IN_CHUNK_SIZE;
614 break; 621 break;
615 } 622 case CHUNKED_IN_TRAILERS_LINE_HEAD:
616 if (buf[src++] == '\012') 623 for (;; ++src) {
617 goto Complete; 624 if (src == bufsz) {
618 decoder->_state = CHUNKED_IN_TRAILERS_LINE_MIDDLE; 625 goto Exit;
619 /* fallthru */ 626 }
620 case CHUNKED_IN_TRAILERS_LINE_MIDDLE: 627 if (buf[src] != '\015') {
621 for (;; ++src) { 628 break;
622 if (src == bufsz) 629 }
623 goto Exit; 630 }
624 if (buf[src] == '\012') 631 if (buf[src++] == '\012') {
625 break; 632 goto Complete;
626 } 633 }
627 ++src; 634 decoder->_state = CHUNKED_IN_TRAILERS_LINE_MIDDLE;
628 decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD; 635 /* fallthru */
629 break; 636 case CHUNKED_IN_TRAILERS_LINE_MIDDLE:
630 default: 637 for (;; ++src) {
631 assert(!"decoder is corrupt"); 638 if (src == bufsz) {
632 } 639 goto Exit;
633 } 640 }
641 if (buf[src] == '\012') {
642 break;
643 }
644 }
645 ++src;
646 decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD;
647 break;
648 default:
649 assert(!"decoder is corrupt");
650 }
651 }
634 652
635Complete: 653Complete:
636 ret = bufsz - src; 654 ret = bufsz - src;
637Exit: 655Exit:
638 if (dst != src) 656 if (dst != src) {
639 memmove(buf + dst, buf + src, bufsz - src); 657 memmove(buf + dst, buf + src, bufsz - src);
640 *_bufsz = dst; 658 }
641 return ret; 659 *_bufsz = dst;
660 return ret;
642} 661}
643 662
644int phr_decode_chunked_is_in_data(struct phr_chunked_decoder *decoder) 663int phr_decode_chunked_is_in_data(struct phr_chunked_decoder *decoder) {
645{ 664 return decoder->_state == CHUNKED_IN_CHUNK_DATA;
646 return decoder->_state == CHUNKED_IN_CHUNK_DATA;
647} 665}
648 666
649#undef CHECK_EOF 667#undef CHECK_EOF
diff --git a/plugins/picohttpparser/picohttpparser.h b/plugins/picohttpparser/picohttpparser.h
index 8f13b36f..054c2812 100644
--- a/plugins/picohttpparser/picohttpparser.h
+++ b/plugins/picohttpparser/picohttpparser.h
@@ -30,7 +30,7 @@
30#include <sys/types.h> 30#include <sys/types.h>
31 31
32#ifdef _MSC_VER 32#ifdef _MSC_VER
33#define ssize_t intptr_t 33# define ssize_t intptr_t
34#endif 34#endif
35 35
36#ifdef __cplusplus 36#ifdef __cplusplus
@@ -40,30 +40,33 @@ extern "C" {
40/* contains name and value of a header (name == NULL if is a continuing line 40/* contains name and value of a header (name == NULL if is a continuing line
41 * of a multiline header */ 41 * of a multiline header */
42struct phr_header { 42struct phr_header {
43 const char *name; 43 const char *name;
44 size_t name_len; 44 size_t name_len;
45 const char *value; 45 const char *value;
46 size_t value_len; 46 size_t value_len;
47}; 47};
48 48
49/* returns number of bytes consumed if successful, -2 if request is partial, 49/* returns number of bytes consumed if successful, -2 if request is partial,
50 * -1 if failed */ 50 * -1 if failed */
51int phr_parse_request(const char *buf, size_t len, const char **method, size_t *method_len, const char **path, size_t *path_len, 51int phr_parse_request(const char *buf, size_t len, const char **method, size_t *method_len,
52 int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len); 52 const char **path, size_t *path_len, int *major_version, int *minor_version,
53 struct phr_header *headers, size_t *num_headers, size_t last_len);
53 54
54/* ditto */ 55/* ditto */
55int phr_parse_response(const char *_buf, size_t len, int *major_version, int *minor_version, int *status, const char **msg, size_t *msg_len, 56int phr_parse_response(const char *_buf, size_t len, int *major_version, int *minor_version,
56 struct phr_header *headers, size_t *num_headers, size_t last_len); 57 int *status, const char **msg, size_t *msg_len, struct phr_header *headers,
58 size_t *num_headers, size_t last_len);
57 59
58/* ditto */ 60/* ditto */
59int phr_parse_headers(const char *buf, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len); 61int phr_parse_headers(const char *buf, size_t len, struct phr_header *headers, size_t *num_headers,
62 size_t last_len);
60 63
61/* should be zero-filled before start */ 64/* should be zero-filled before start */
62struct phr_chunked_decoder { 65struct phr_chunked_decoder {
63 size_t bytes_left_in_chunk; /* number of bytes left in current chunk */ 66 size_t bytes_left_in_chunk; /* number of bytes left in current chunk */
64 char consume_trailer; /* if trailing headers should be consumed */ 67 char consume_trailer; /* if trailing headers should be consumed */
65 char _hex_count; 68 char _hex_count;
66 char _state; 69 char _state;
67}; 70};
68 71
69/* the function rewrites the buffer given as (buf, bufsz) removing the chunked- 72/* the function rewrites the buffer given as (buf, bufsz) removing the chunked-
diff --git a/plugins/popen.c b/plugins/popen.c
index 54e63bc5..c596d1e0 100644
--- a/plugins/popen.c
+++ b/plugins/popen.c
@@ -1,294 +1,302 @@
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
110 /* if no command was passed, return with no error */ 98 /* if no command was passed, return with no error */
111 if (cmdstring == NULL) 99 if (cmdstring == NULL) {
112 return (NULL); 100 return (NULL);
101 }
113 102
103 char *cmd = NULL;
114 /* make copy of command string so strtok() doesn't silently modify it */ 104 /* make copy of command string so strtok() doesn't silently modify it */
115 /* (the calling program may want to access it later) */ 105 /* (the calling program may want to access it later) */
116 cmd = malloc (strlen (cmdstring) + 1); 106 cmd = malloc(strlen(cmdstring) + 1);
117 if (cmd == NULL) 107 if (cmd == NULL) {
118 return NULL; 108 return NULL;
119 strcpy (cmd, cmdstring); 109 }
110 strcpy(cmd, cmdstring);
120 111
121 /* This is not a shell, so we don't handle "???" */ 112 /* This is not a shell, so we don't handle "???" */
122 if (strstr (cmdstring, "\"")) 113 if (strstr(cmdstring, "\"")) {
123 return NULL; 114 return NULL;
115 }
124 116
125 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */ 117 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */
126 if (strstr (cmdstring, " ' ") || strstr (cmdstring, "'''")) 118 if (strstr(cmdstring, " ' ") || strstr(cmdstring, "'''")) {
127 return NULL; 119 return NULL;
120 }
128 121
122 int argc;
123 char **argv = NULL;
129 /* there cannot be more args than characters */ 124 /* there cannot be more args than characters */
130 argc = strlen (cmdstring) + 1; /* add 1 for NULL termination */ 125 argc = strlen(cmdstring) + 1; /* add 1 for NULL termination */
131 argv = malloc (sizeof(char*)*argc); 126 argv = malloc(sizeof(char *) * argc);
132 127
133 if (argv == NULL) { 128 if (argv == NULL) {
134 printf ("%s\n", _("Could not malloc argv array in popen()")); 129 printf("%s\n", _("Could not malloc argv array in popen()"));
135 return NULL; 130 return NULL;
136 } 131 }
137 132
133 int i = 0;
134 char *str;
138 /* loop to get arguments to command */ 135 /* loop to get arguments to command */
139 while (cmd) { 136 while (cmd) {
140 str = cmd; 137 str = cmd;
141 str += strspn (str, " \t\r\n"); /* trim any leading whitespace */ 138 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */
142 139
143 if (i >= argc - 2) { 140 if (i >= argc - 2) {
144 printf ("%s\n",_("CRITICAL - You need more args!!!")); 141 printf("%s\n", _("CRITICAL - You need more args!!!"));
145 return (NULL); 142 return (NULL);
146 } 143 }
147 144
148 if (strstr (str, "'") == str) { /* handle SIMPLE quoted strings */ 145 if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */
149 str++; 146 str++;
150 if (!strstr (str, "'")) 147 if (!strstr(str, "'")) {
151 return NULL; /* balanced? */ 148 return NULL; /* balanced? */
152 cmd = 1 + strstr (str, "'"); 149 }
153 str[strcspn (str, "'")] = 0; 150 cmd = 1 + strstr(str, "'");
154 } 151 str[strcspn(str, "'")] = 0;
155 else if (strcspn(str,"'") < strcspn (str, " \t\r\n")) { 152 } else if (strcspn(str, "'") < strcspn(str, " \t\r\n")) {
156 /* handle --option='foo bar' strings */ 153 /* handle --option='foo bar' strings */
157 tmp = str + strcspn(str, "'") + 1; 154 char *tmp = str + strcspn(str, "'") + 1;
158 if (!strstr (tmp, "'")) 155 if (!strstr(tmp, "'")) {
159 return NULL; /* balanced? */ 156 return NULL; /* balanced? */
160 tmp += strcspn(tmp,"'") + 1; 157 }
158 tmp += strcspn(tmp, "'") + 1;
161 *tmp = 0; 159 *tmp = 0;
162 cmd = tmp + 1; 160 cmd = tmp + 1;
163 } else { 161 } else {
164 if (strpbrk (str, " \t\r\n")) { 162 if (strpbrk(str, " \t\r\n")) {
165 cmd = 1 + strpbrk (str, " \t\r\n"); 163 cmd = 1 + strpbrk(str, " \t\r\n");
166 str[strcspn (str, " \t\r\n")] = 0; 164 str[strcspn(str, " \t\r\n")] = 0;
167 } 165 } else {
168 else {
169 cmd = NULL; 166 cmd = NULL;
170 } 167 }
171 } 168 }
172 169
173 if (cmd && strlen (cmd) == strspn (cmd, " \t\r\n")) 170 if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n")) {
174 cmd = NULL; 171 cmd = NULL;
172 }
175 173
176 argv[i++] = str; 174 argv[i++] = str;
177
178 } 175 }
179 argv[i] = NULL; 176 argv[i] = NULL;
180 177
181 long maxfd = mp_open_max(); 178 long maxfd = mp_open_max();
182 179
183 if (childpid == NULL) { /* first time through */ 180 if (childpid == NULL) { /* first time through */
184 if ((childpid = calloc ((size_t)maxfd, sizeof (pid_t))) == NULL) 181 if ((childpid = calloc((size_t)maxfd, sizeof(pid_t))) == NULL) {
185 return (NULL); 182 return (NULL);
183 }
186 } 184 }
187 185
188 if (child_stderr_array == NULL) { /* first time through */ 186 if (child_stderr_array == NULL) { /* first time through */
189 if ((child_stderr_array = calloc ((size_t)maxfd, sizeof (int))) == NULL) 187 if ((child_stderr_array = calloc((size_t)maxfd, sizeof(int))) == NULL) {
190 return (NULL); 188 return (NULL);
189 }
191 } 190 }
192 191
193 if (pipe (pfd) < 0) 192 int pfd[2];
194 return (NULL); /* errno set by pipe() */ 193 if (pipe(pfd) < 0) {
194 return (NULL); /* errno set by pipe() */
195 }
195 196
196 if (pipe (pfderr) < 0) 197 int pfderr[2];
197 return (NULL); /* errno set by pipe() */ 198 if (pipe(pfderr) < 0) {
199 return (NULL); /* errno set by pipe() */
200 }
198 201
199#ifdef REDHAT_SPOPEN_ERROR 202#ifdef REDHAT_SPOPEN_ERROR
200 if (signal (SIGCHLD, popen_sigchld_handler) == SIG_ERR) { 203 if (signal(SIGCHLD, popen_sigchld_handler) == SIG_ERR) {
201 usage4 (_("Cannot catch SIGCHLD")); 204 usage4(_("Cannot catch SIGCHLD"));
202 } 205 }
203#endif 206#endif
204 207
205 if ((pid = fork ()) < 0) 208 pid_t pid;
206 return (NULL); /* errno set by fork() */ 209 if ((pid = fork()) < 0) {
207 else if (pid == 0) { /* child */ 210 return (NULL); /* errno set by fork() */
208 close (pfd[0]); 211 }
212
213 if (pid == 0) { /* child */
214 close(pfd[0]);
209 if (pfd[1] != STDOUT_FILENO) { 215 if (pfd[1] != STDOUT_FILENO) {
210 dup2 (pfd[1], STDOUT_FILENO); 216 dup2(pfd[1], STDOUT_FILENO);
211 close (pfd[1]); 217 close(pfd[1]);
212 } 218 }
213 close (pfderr[0]); 219 close(pfderr[0]);
214 if (pfderr[1] != STDERR_FILENO) { 220 if (pfderr[1] != STDERR_FILENO) {
215 dup2 (pfderr[1], STDERR_FILENO); 221 dup2(pfderr[1], STDERR_FILENO);
216 close (pfderr[1]); 222 close(pfderr[1]);
217 } 223 }
218 /* close all descriptors in childpid[] */ 224 /* close all descriptors in childpid[] */
219 for (i = 0; i < maxfd; i++) 225 for (i = 0; i < maxfd; i++) {
220 if (childpid[i] > 0) 226 if (childpid[i] > 0) {
221 close (i); 227 close(i);
228 }
229 }
222 230
223 execve (argv[0], argv, env); 231 execve(argv[0], argv, env);
224 _exit (0); 232 _exit(0);
225 } 233 }
226 234
227 close (pfd[1]); /* parent */ 235 close(pfd[1]); /* parent */
228 if ((child_process = fdopen (pfd[0], "r")) == NULL) 236 if ((child_process = fdopen(pfd[0], "r")) == NULL) {
229 return (NULL); 237 return (NULL);
230 close (pfderr[1]); 238 }
239 close(pfderr[1]);
231 240
232 childpid[fileno (child_process)] = pid; /* remember child pid for this fd */ 241 childpid[fileno(child_process)] = pid; /* remember child pid for this fd */
233 child_stderr_array[fileno (child_process)] = pfderr[0]; /* remember STDERR */ 242 child_stderr_array[fileno(child_process)] = pfderr[0]; /* remember STDERR */
234 return (child_process); 243 return (child_process);
235} 244}
236 245
237int 246int spclose(FILE *fp) {
238spclose (FILE * fp) 247 if (childpid == NULL) {
239{ 248 return (1); /* popen() has never been called */
240 int fd, status; 249 }
241 pid_t pid;
242
243 if (childpid == NULL)
244 return (1); /* popen() has never been called */
245 250
246 fd = fileno (fp); 251 pid_t pid;
247 if ((pid = childpid[fd]) == 0) 252 int fd = fileno(fp);
248 return (1); /* fp wasn't opened by popen() */ 253 if ((pid = childpid[fd]) == 0) {
254 return (1); /* fp wasn't opened by popen() */
255 }
249 256
250 childpid[fd] = 0; 257 childpid[fd] = 0;
251 if (fclose (fp) == EOF) 258 if (fclose(fp) == EOF) {
252 return (1); 259 return (1);
260 }
253 261
254#ifdef REDHAT_SPOPEN_ERROR 262#ifdef REDHAT_SPOPEN_ERROR
255 while (!childtermd); /* wait until SIGCHLD */ 263 while (!childtermd)
264 ; /* wait until SIGCHLD */
256#endif 265#endif
257 266
258 while (waitpid (pid, &status, 0) < 0) 267 int status;
259 if (errno != EINTR) 268 while (waitpid(pid, &status, 0) < 0) {
260 return (1); /* error other than EINTR from waitpid() */ 269 if (errno != EINTR) {
270 return (1); /* error other than EINTR from waitpid() */
271 }
272 }
261 273
262 if (WIFEXITED (status)) 274 if (WIFEXITED(status)) {
263 return (WEXITSTATUS (status)); /* return child's termination status */ 275 return (WEXITSTATUS(status)); /* return child's termination status */
276 }
264 277
265 return (1); 278 return (1);
266} 279}
267 280
268#ifdef REDHAT_SPOPEN_ERROR 281#ifdef REDHAT_SPOPEN_ERROR
269void 282void popen_sigchld_handler(int signo) {
270popen_sigchld_handler (int signo) 283 if (signo == SIGCHLD) {
271{
272 if (signo == SIGCHLD)
273 childtermd = 1; 284 childtermd = 1;
285 }
274} 286}
275#endif 287#endif
276 288
277void 289void popen_timeout_alarm_handler(int signo) {
278popen_timeout_alarm_handler (int signo)
279{
280 int fh;
281 if (signo == SIGALRM) { 290 if (signo == SIGALRM) {
282 if (child_process != NULL) { 291 if (child_process != NULL) {
283 fh=fileno (child_process); 292 int fh = fileno(child_process);
284 if(fh >= 0){ 293 if (fh >= 0) {
285 kill (childpid[fh], SIGKILL); 294 kill(childpid[fh], SIGKILL);
286 } 295 }
287 printf (_("CRITICAL - Plugin timed out after %d seconds\n"), 296 printf(_("CRITICAL - Plugin timed out after %d seconds\n"), timeout_interval);
288 timeout_interval);
289 } else { 297 } else {
290 printf ("%s\n", _("CRITICAL - popen timeout received, but no child process")); 298 printf("%s\n", _("CRITICAL - popen timeout received, but no child process"));
291 } 299 }
292 exit (STATE_CRITICAL); 300 exit(STATE_CRITICAL);
293 } 301 }
294} 302}
diff --git a/plugins/popen.h b/plugins/popen.h
index 1ea69632..e318ce25 100644
--- a/plugins/popen.h
+++ b/plugins/popen.h
@@ -1,13 +1,13 @@
1/****************************************************************************** 1/******************************************************************************
2* 2 *
3* 3 *
4*****************************************************************************/ 4 *****************************************************************************/
5 5
6FILE *spopen (const char *); 6FILE *spopen(const char *);
7int spclose (FILE *); 7int spclose(FILE *);
8void popen_timeout_alarm_handler (int); 8void popen_timeout_alarm_handler(int);
9 9
10pid_t *childpid=NULL; 10pid_t *childpid = NULL;
11int *child_stderr_array=NULL; 11int *child_stderr_array = NULL;
12FILE *child_process=NULL; 12FILE *child_process = NULL;
13FILE *child_stderr=NULL; 13FILE *child_stderr = NULL;
diff --git a/plugins/runcmd.c b/plugins/runcmd.c
index ed49bb99..7c583b85 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,27 @@
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));
92 }
95} 93}
96 94
97
98/* Start running a command */ 95/* Start running a command */
99static int 96static 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]; 97 char *env[2];
103 char *cmd = NULL; 98 char *cmd = NULL;
104 char **argv = NULL; 99 char **argv = NULL;
@@ -112,7 +107,9 @@ np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr)
112 107
113 int i = 0; 108 int i = 0;
114 109
115 if(!np_pids) NP_RUNCMD_INIT; 110 if (!np_pids) {
111 NP_RUNCMD_INIT;
112 }
116 113
117 env[0] = strdup("LC_ALL=C"); 114 env[0] = strdup("LC_ALL=C");
118 env[1] = NULL; 115 env[1] = NULL;
@@ -120,86 +117,95 @@ np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr)
120 /* make copy of command string so strtok() doesn't silently modify it */ 117 /* make copy of command string so strtok() doesn't silently modify it */
121 /* (the calling program may want to access it later) */ 118 /* (the calling program may want to access it later) */
122 cmdlen = strlen(cmdstring); 119 cmdlen = strlen(cmdstring);
123 if((cmd = malloc(cmdlen + 1)) == NULL) return -1; 120 if ((cmd = malloc(cmdlen + 1)) == NULL) {
121 return -1;
122 }
124 memcpy(cmd, cmdstring, cmdlen); 123 memcpy(cmd, cmdstring, cmdlen);
125 cmd[cmdlen] = '\0'; 124 cmd[cmdlen] = '\0';
126 125
127 /* This is not a shell, so we don't handle "???" */ 126 /* This is not a shell, so we don't handle "???" */
128 if (strstr (cmdstring, "\"")) return -1; 127 if (strstr(cmdstring, "\"")) {
128 return -1;
129 }
129 130
130 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */ 131 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */
131 if (strstr (cmdstring, " ' ") || strstr (cmdstring, "'''")) 132 if (strstr(cmdstring, " ' ") || strstr(cmdstring, "'''")) {
132 return -1; 133 return -1;
134 }
133 135
134 /* each arg must be whitespace-separated, so args can be a maximum 136 /* each arg must be whitespace-separated, so args can be a maximum
135 * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */ 137 * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */
136 argc = (cmdlen >> 1) + 2; 138 argc = (cmdlen >> 1) + 2;
137 argv = calloc(sizeof(char *), argc); 139 argv = calloc(argc, sizeof(char *));
138 140
139 if (argv == NULL) { 141 if (argv == NULL) {
140 printf ("%s\n", _("Could not malloc argv array in popen()")); 142 printf("%s\n", _("Could not malloc argv array in popen()"));
141 return -1; 143 return -1;
142 } 144 }
143 145
144 /* get command arguments (stupidly, but fairly quickly) */ 146 /* get command arguments (stupidly, but fairly quickly) */
145 while (cmd) { 147 while (cmd) {
146 str = cmd; 148 str = cmd;
147 str += strspn (str, " \t\r\n"); /* trim any leading whitespace */ 149 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */
148 150
149 if (strstr (str, "'") == str) { /* handle SIMPLE quoted strings */ 151 if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */
150 str++; 152 str++;
151 if (!strstr (str, "'")) return -1; /* balanced? */ 153 if (!strstr(str, "'")) {
152 cmd = 1 + strstr (str, "'"); 154 return -1; /* balanced? */
153 str[strcspn (str, "'")] = 0;
154 }
155 else {
156 if (strpbrk (str, " \t\r\n")) {
157 cmd = 1 + strpbrk (str, " \t\r\n");
158 str[strcspn (str, " \t\r\n")] = 0;
159 } 155 }
160 else { 156 cmd = 1 + strstr(str, "'");
157 str[strcspn(str, "'")] = 0;
158 } else {
159 if (strpbrk(str, " \t\r\n")) {
160 cmd = 1 + strpbrk(str, " \t\r\n");
161 str[strcspn(str, " \t\r\n")] = 0;
162 } else {
161 cmd = NULL; 163 cmd = NULL;
162 } 164 }
163 } 165 }
164 166
165 if (cmd && strlen (cmd) == strspn (cmd, " \t\r\n")) 167 if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n")) {
166 cmd = NULL; 168 cmd = NULL;
169 }
167 170
168 argv[i++] = str; 171 argv[i++] = str;
169 } 172 }
170 173
171 if (pipe(pfd) < 0 || pipe(pfderr) < 0 || (pid = fork()) < 0) 174 if (pipe(pfd) < 0 || pipe(pfderr) < 0 || (pid = fork()) < 0) {
172 return -1; /* errno set by the failing function */ 175 return -1; /* errno set by the failing function */
176 }
173 177
174 /* child runs exceve() and _exit. */ 178 /* child runs exceve() and _exit. */
175 if (pid == 0) { 179 if (pid == 0) {
176#ifdef RLIMIT_CORE 180#ifdef RLIMIT_CORE
177 /* the program we execve shouldn't leave core files */ 181 /* the program we execve shouldn't leave core files */
178 getrlimit (RLIMIT_CORE, &limit); 182 getrlimit(RLIMIT_CORE, &limit);
179 limit.rlim_cur = 0; 183 limit.rlim_cur = 0;
180 setrlimit (RLIMIT_CORE, &limit); 184 setrlimit(RLIMIT_CORE, &limit);
181#endif 185#endif
182 close (pfd[0]); 186 close(pfd[0]);
183 if (pfd[1] != STDOUT_FILENO) { 187 if (pfd[1] != STDOUT_FILENO) {
184 dup2 (pfd[1], STDOUT_FILENO); 188 dup2(pfd[1], STDOUT_FILENO);
185 close (pfd[1]); 189 close(pfd[1]);
186 } 190 }
187 close (pfderr[0]); 191 close(pfderr[0]);
188 if (pfderr[1] != STDERR_FILENO) { 192 if (pfderr[1] != STDERR_FILENO) {
189 dup2 (pfderr[1], STDERR_FILENO); 193 dup2(pfderr[1], STDERR_FILENO);
190 close (pfderr[1]); 194 close(pfderr[1]);
191 } 195 }
192 196
193 /* close all descriptors in np_pids[] 197 /* close all descriptors in np_pids[]
194 * This is executed in a separate address space (pure child), 198 * This is executed in a separate address space (pure child),
195 * so we don't have to worry about async safety */ 199 * so we don't have to worry about async safety */
196 long maxfd = mp_open_max(); 200 long maxfd = mp_open_max();
197 for (i = 0; i < maxfd; i++) 201 for (i = 0; i < maxfd; i++) {
198 if(np_pids[i] > 0) 202 if (np_pids[i] > 0) {
199 close (i); 203 close(i);
204 }
205 }
200 206
201 execve (argv[0], argv, env); 207 execve(argv[0], argv, env);
202 _exit (STATE_UNKNOWN); 208 _exit(STATE_UNKNOWN);
203 } 209 }
204 210
205 /* parent picks up execution here */ 211 /* parent picks up execution here */
@@ -213,49 +219,51 @@ np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr)
213 return pfd[0]; 219 return pfd[0];
214} 220}
215 221
216 222static int np_runcmd_close(int fd) {
217static int
218np_runcmd_close(int fd)
219{
220 int status; 223 int status;
221 pid_t pid; 224 pid_t pid;
222 225
223 /* make sure this fd was opened by popen() */ 226 /* make sure this fd was opened by popen() */
224 long maxfd = mp_open_max(); 227 long maxfd = mp_open_max();
225 if(fd < 0 || fd > maxfd || !np_pids || (pid = np_pids[fd]) == 0) 228 if (fd < 0 || fd > maxfd || !np_pids || (pid = np_pids[fd]) == 0) {
226 return -1; 229 return -1;
230 }
227 231
228 np_pids[fd] = 0; 232 np_pids[fd] = 0;
229 if (close (fd) == -1) return -1; 233 if (close(fd) == -1) {
234 return -1;
235 }
230 236
231 /* EINTR is ok (sort of), everything else is bad */ 237 /* EINTR is ok (sort of), everything else is bad */
232 while (waitpid (pid, &status, 0) < 0) 238 while (waitpid(pid, &status, 0) < 0) {
233 if (errno != EINTR) return -1; 239 if (errno != EINTR) {
240 return -1;
241 }
242 }
234 243
235 /* return child's termination status */ 244 /* return child's termination status */
236 return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1; 245 return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1;
237} 246}
238 247
248void runcmd_timeout_alarm_handler(int signo) {
239 249
240void 250 if (signo == SIGALRM) {
241runcmd_timeout_alarm_handler (int signo)
242{
243
244 if (signo == SIGALRM)
245 puts(_("CRITICAL - Plugin timed out while executing system call")); 251 puts(_("CRITICAL - Plugin timed out while executing system call"));
252 }
246 253
247 long maxfd = mp_open_max(); 254 long maxfd = mp_open_max();
248 if(np_pids) for(long int i = 0; i < maxfd; i++) { 255 if (np_pids) {
249 if(np_pids[i] != 0) kill(np_pids[i], SIGKILL); 256 for (long int i = 0; i < maxfd; i++) {
257 if (np_pids[i] != 0) {
258 kill(np_pids[i], SIGKILL);
259 }
260 }
250 } 261 }
251 262
252 exit (STATE_CRITICAL); 263 exit(STATE_CRITICAL);
253} 264}
254 265
255 266static 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; 267 size_t len = 0, i = 0, lineno = 0;
260 size_t rsf = 6, ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */ 268 size_t rsf = 6, ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */
261 char *buf = NULL; 269 char *buf = NULL;
@@ -264,7 +272,7 @@ np_fetch_output(int fd, output *op, int flags)
264 272
265 op->buf = NULL; 273 op->buf = NULL;
266 op->buflen = 0; 274 op->buflen = 0;
267 while((ret = read(fd, tmpbuf, sizeof(tmpbuf))) > 0) { 275 while ((ret = read(fd, tmpbuf, sizeof(tmpbuf))) > 0) {
268 len = (size_t)ret; 276 len = (size_t)ret;
269 op->buf = realloc(op->buf, op->buflen + len + 1); 277 op->buf = realloc(op->buf, op->buflen + len + 1);
270 memcpy(op->buf + op->buflen, tmpbuf, len); 278 memcpy(op->buf + op->buflen, tmpbuf, len);
@@ -272,33 +280,35 @@ np_fetch_output(int fd, output *op, int flags)
272 i++; 280 i++;
273 } 281 }
274 282
275 if(ret < 0) { 283 if (ret < 0) {
276 printf("read() returned %d: %s\n", ret, strerror(errno)); 284 printf("read() returned %d: %s\n", ret, strerror(errno));
277 return ret; 285 return ret;
278 } 286 }
279 287
280 /* some plugins may want to keep output unbroken, and some commands 288 /* some plugins may want to keep output unbroken, and some commands
281 * will yield no output, so return here for those */ 289 * will yield no output, so return here for those */
282 if(flags & RUNCMD_NO_ARRAYS || !op->buf || !op->buflen) 290 if (flags & RUNCMD_NO_ARRAYS || !op->buf || !op->buflen) {
283 return op->buflen; 291 return op->buflen;
292 }
284 293
285 /* and some may want both */ 294 /* and some may want both */
286 if(flags & RUNCMD_NO_ASSOC) { 295 if (flags & RUNCMD_NO_ASSOC) {
287 buf = malloc(op->buflen); 296 buf = malloc(op->buflen);
288 memcpy(buf, op->buf, op->buflen); 297 memcpy(buf, op->buf, op->buflen);
298 } else {
299 buf = op->buf;
289 } 300 }
290 else buf = op->buf;
291 301
292 op->line = NULL; 302 op->line = NULL;
293 op->lens = NULL; 303 op->lens = NULL;
294 i = 0; 304 i = 0;
295 while(i < op->buflen) { 305 while (i < op->buflen) {
296 /* make sure we have enough memory */ 306 /* make sure we have enough memory */
297 if(lineno >= ary_size) { 307 if (lineno >= ary_size) {
298 /* ary_size must never be zero */ 308 /* ary_size must never be zero */
299 do { 309 do {
300 ary_size = op->buflen >> --rsf; 310 ary_size = op->buflen >> --rsf;
301 } while(!ary_size); 311 } while (!ary_size);
302 312
303 op->line = realloc(op->line, ary_size * sizeof(char *)); 313 op->line = realloc(op->line, ary_size * sizeof(char *));
304 op->lens = realloc(op->lens, ary_size * sizeof(size_t)); 314 op->lens = realloc(op->lens, ary_size * sizeof(size_t));
@@ -308,7 +318,9 @@ np_fetch_output(int fd, output *op, int flags)
308 op->line[lineno] = &buf[i]; 318 op->line[lineno] = &buf[i];
309 319
310 /* hop to next newline or end of buffer */ 320 /* hop to next newline or end of buffer */
311 while(buf[i] != '\n' && i < op->buflen) i++; 321 while (buf[i] != '\n' && i < op->buflen) {
322 i++;
323 }
312 buf[i] = '\0'; 324 buf[i] = '\0';
313 325
314 /* calculate the string length using pointer difference */ 326 /* calculate the string length using pointer difference */
@@ -321,21 +333,27 @@ np_fetch_output(int fd, output *op, int flags)
321 return lineno; 333 return lineno;
322} 334}
323 335
324 336int 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]; 337 int fd, pfd_out[2], pfd_err[2];
329 338
330 /* initialize the structs */ 339 /* initialize the structs */
331 if(out) memset(out, 0, sizeof(output)); 340 if (out) {
332 if(err) memset(err, 0, sizeof(output)); 341 memset(out, 0, sizeof(output));
342 }
343 if (err) {
344 memset(err, 0, sizeof(output));
345 }
333 346
334 if((fd = np_runcmd_open(cmd, pfd_out, pfd_err)) == -1) 347 if ((fd = np_runcmd_open(cmd, pfd_out, pfd_err)) == -1) {
335 die (STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd); 348 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd);
349 }
336 350
337 if(out) out->lines = np_fetch_output(pfd_out[0], out, flags); 351 if (out) {
338 if(err) err->lines = np_fetch_output(pfd_err[0], err, flags); 352 out->lines = np_fetch_output(pfd_out[0], out, flags);
353 }
354 if (err) {
355 err->lines = np_fetch_output(pfd_err[0], err, flags);
356 }
339 357
340 return np_runcmd_close(fd); 358 return np_runcmd_close(fd);
341} 359}
diff --git a/plugins/runcmd.h b/plugins/runcmd.h
index 2dcdadf0..63ce7b12 100644
--- a/plugins/runcmd.h
+++ b/plugins/runcmd.h
@@ -1,25 +1,25 @@
1/**************************************************************************** 1/****************************************************************************
2* 2 *
3* License: GPL 3 * License: GPL
4* Copyright (c) 2005 Monitoring Plugins Development Team 4 * Copyright (c) 2005 Monitoring Plugins Development Team
5* Author: Andreas Ericsson <ae@op5.se> 5 * Author: Andreas Ericsson <ae@op5.se>
6* 6 *
7* 7 *
8* This program is free software: you can redistribute it and/or modify 8 * This program is free software: you can redistribute it and/or modify
9* it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
10* the Free Software Foundation, either version 3 of the License, or 10 * the Free Software Foundation, either version 3 of the License, or
11* (at your option) any later version. 11 * (at your option) any later version.
12* 12 *
13* This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful,
14* but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16* GNU General Public License for more details. 16 * GNU General Public License for more details.
17* 17 *
18* You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
19* along with this program. If not, see <http://www.gnu.org/licenses/>. 19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20* 20 *
21* 21 *
22*****************************************************************************/ 22 *****************************************************************************/
23 23
24#ifndef NAGIOSPLUG_RUNCMD_H 24#ifndef NAGIOSPLUG_RUNCMD_H
25#define NAGIOSPLUG_RUNCMD_H 25#define NAGIOSPLUG_RUNCMD_H
@@ -29,8 +29,7 @@
29 29
30/** prototypes **/ 30/** prototypes **/
31int np_runcmd(const char *, output *, output *, int); 31int np_runcmd(const char *, output *, output *, int);
32void runcmd_timeout_alarm_handler(int) 32void runcmd_timeout_alarm_handler(int) __attribute__((__noreturn__));
33 __attribute__((__noreturn__));
34 33
35/* only multi-threaded plugins need to bother with this */ 34/* only multi-threaded plugins need to bother with this */
36void np_runcmd_init(void); 35void np_runcmd_init(void);
@@ -38,6 +37,6 @@ void np_runcmd_init(void);
38 37
39/* possible flags for np_runcmd()'s fourth argument */ 38/* possible flags for np_runcmd()'s fourth argument */
40#define RUNCMD_NO_ARRAYS 0x01 /* don't populate arrays at all */ 39#define RUNCMD_NO_ARRAYS 0x01 /* don't populate arrays at all */
41#define RUNCMD_NO_ASSOC 0x02 /* output.line won't point to buf */ 40#define RUNCMD_NO_ASSOC 0x02 /* output.line won't point to buf */
42 41
43#endif /* NAGIOSPLUG_RUNCMD_H */ 42#endif /* NAGIOSPLUG_RUNCMD_H */
diff --git a/plugins/sslutils.c b/plugins/sslutils.c
index 6bc0ba81..0e6d7525 100644
--- a/plugins/sslutils.c
+++ b/plugins/sslutils.c
@@ -1,42 +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#include "output.h"
29#define MAX_CN_LENGTH 256 30#define MAX_CN_LENGTH 256
30#include "common.h" 31#include "common.h"
31#include "netutils.h" 32#include "netutils.h"
33#include "../lib/monitoringplug.h"
34#include "states.h"
32 35
33#ifdef HAVE_SSL 36#ifdef HAVE_SSL
34static SSL_CTX *ctx=NULL; 37static SSL_CTX *ctx = NULL;
35static SSL *s=NULL; 38static SSL *s = NULL;
36 39
37int np_net_ssl_init(int sd) { 40int 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 41
41int np_net_ssl_init_with_hostname(int sd, char *host_name) { 42int np_net_ssl_init_with_hostname(int sd, char *host_name) {
42 return np_net_ssl_init_with_hostname_and_version(sd, host_name, 0); 43 return np_net_ssl_init_with_hostname_and_version(sd, host_name, 0);
@@ -46,7 +47,8 @@ int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int versi
46 return np_net_ssl_init_with_hostname_version_and_cert(sd, host_name, version, NULL, NULL); 47 return np_net_ssl_init_with_hostname_version_and_cert(sd, host_name, version, NULL, NULL);
47} 48}
48 49
49int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int version, char *cert, char *privkey) { 50int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int version, char *cert,
51 char *privkey) {
50 long options = 0; 52 long options = 0;
51 53
52 if ((ctx = SSL_CTX_new(TLS_client_method())) == NULL) { 54 if ((ctx = SSL_CTX_new(TLS_client_method())) == NULL) {
@@ -59,272 +61,398 @@ 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.")); 61 printf("%s\n", _("UNKNOWN - SSL protocol version 2 is not supported by your SSL library."));
60 return STATE_UNKNOWN; 62 return STATE_UNKNOWN;
61 case MP_SSLv3: /* SSLv3 protocol */ 63 case MP_SSLv3: /* SSLv3 protocol */
62#if defined(OPENSSL_NO_SSL3) 64# if defined(OPENSSL_NO_SSL3)
63 printf("%s\n", _("UNKNOWN - SSL protocol version 3 is not supported by your SSL library.")); 65 printf("%s\n", _("UNKNOWN - SSL protocol version 3 is not supported by your SSL library."));
64 return STATE_UNKNOWN; 66 return STATE_UNKNOWN;
65#else 67# else
66 SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION); 68 SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION);
67 SSL_CTX_set_max_proto_version(ctx, SSL3_VERSION); 69 SSL_CTX_set_max_proto_version(ctx, SSL3_VERSION);
68 break; 70 break;
69#endif 71# endif
70 case MP_TLSv1: /* TLSv1 protocol */ 72 case MP_TLSv1: /* TLSv1 protocol */
71#if defined(OPENSSL_NO_TLS1) 73# if defined(OPENSSL_NO_TLS1)
72 printf("%s\n", _("UNKNOWN - TLS protocol version 1 is not supported by your SSL library.")); 74 printf("%s\n", _("UNKNOWN - TLS protocol version 1 is not supported by your SSL library."));
73 return STATE_UNKNOWN; 75 return STATE_UNKNOWN;
74#else 76# else
75 SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION); 77 SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION);
76 SSL_CTX_set_max_proto_version(ctx, TLS1_VERSION); 78 SSL_CTX_set_max_proto_version(ctx, TLS1_VERSION);
77 break; 79 break;
78#endif 80# endif
79 case MP_TLSv1_1: /* TLSv1.1 protocol */ 81 case MP_TLSv1_1: /* TLSv1.1 protocol */
80#if !defined(SSL_OP_NO_TLSv1_1) 82# if !defined(SSL_OP_NO_TLSv1_1)
81 printf("%s\n", _("UNKNOWN - TLS protocol version 1.1 is not supported by your SSL library.")); 83 printf("%s\n",
84 _("UNKNOWN - TLS protocol version 1.1 is not supported by your SSL library."));
82 return STATE_UNKNOWN; 85 return STATE_UNKNOWN;
83#else 86# else
84 SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION); 87 SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION);
85 SSL_CTX_set_max_proto_version(ctx, TLS1_1_VERSION); 88 SSL_CTX_set_max_proto_version(ctx, TLS1_1_VERSION);
86 break; 89 break;
87#endif 90# endif
88 case MP_TLSv1_2: /* TLSv1.2 protocol */ 91 case MP_TLSv1_2: /* TLSv1.2 protocol */
89#if !defined(SSL_OP_NO_TLSv1_2) 92# if !defined(SSL_OP_NO_TLSv1_2)
90 printf("%s\n", _("UNKNOWN - TLS protocol version 1.2 is not supported by your SSL library.")); 93 printf("%s\n",
94 _("UNKNOWN - TLS protocol version 1.2 is not supported by your SSL library."));
91 return STATE_UNKNOWN; 95 return STATE_UNKNOWN;
92#else 96# else
93 SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); 97 SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
94 SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION); 98 SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION);
95 break; 99 break;
96#endif 100# endif
97 case MP_TLSv1_2_OR_NEWER: 101 case MP_TLSv1_2_OR_NEWER:
98#if !defined(SSL_OP_NO_TLSv1_1) 102# if !defined(SSL_OP_NO_TLSv1_1)
99 printf("%s\n", _("UNKNOWN - Disabling TLSv1.1 is not supported by your SSL library.")); 103 printf("%s\n", _("UNKNOWN - Disabling TLSv1.1 is not supported by your SSL library."));
100 return STATE_UNKNOWN; 104 return STATE_UNKNOWN;
101#else 105# else
102 SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); 106 SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
103 break; 107 break;
104#endif 108# endif
105 case MP_TLSv1_1_OR_NEWER: 109 case MP_TLSv1_1_OR_NEWER:
106#if !defined(SSL_OP_NO_TLSv1) 110# if !defined(SSL_OP_NO_TLSv1)
107 printf("%s\n", _("UNKNOWN - Disabling TLSv1 is not supported by your SSL library.")); 111 printf("%s\n", _("UNKNOWN - Disabling TLSv1 is not supported by your SSL library."));
108 return STATE_UNKNOWN; 112 return STATE_UNKNOWN;
109#else 113# else
110 SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION); 114 SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION);
111 break; 115 break;
112#endif 116# endif
113 case MP_TLSv1_OR_NEWER: 117 case MP_TLSv1_OR_NEWER:
114#if defined(SSL_OP_NO_SSLv3) 118# if defined(SSL_OP_NO_SSLv3)
115 SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION); 119 SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION);
116 break; 120 break;
117#endif 121# endif
118 case MP_SSLv3_OR_NEWER: 122 case MP_SSLv3_OR_NEWER:
119#if defined(SSL_OP_NO_SSLv2) 123# if defined(SSL_OP_NO_SSLv2)
120 SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION); 124 SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION);
121 break; 125 break;
122#endif 126# endif
123 } 127 }
124 128
125 if (cert && privkey) { 129 if (cert && privkey) {
126#ifdef USE_OPENSSL 130# ifdef USE_OPENSSL
127 if (!SSL_CTX_use_certificate_chain_file(ctx, cert)) { 131 if (!SSL_CTX_use_certificate_chain_file(ctx, cert)) {
128#elif USE_GNUTLS 132# elif USE_GNUTLS
129 if (!SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM)) { 133 if (!SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM)) {
130#else 134# else
131#error Unported for unknown SSL library 135# error Unported for unknown SSL library
132#endif 136# endif
133 printf ("%s\n", _("CRITICAL - Unable to open certificate chain file!\n")); 137 printf("%s\n", _("CRITICAL - Unable to open certificate chain file!\n"));
134 return STATE_CRITICAL; 138 return STATE_CRITICAL;
135 } 139 }
136 SSL_CTX_use_PrivateKey_file(ctx, privkey, SSL_FILETYPE_PEM); 140 SSL_CTX_use_PrivateKey_file(ctx, privkey, SSL_FILETYPE_PEM);
137#ifdef USE_OPENSSL 141# ifdef USE_OPENSSL
138 if (!SSL_CTX_check_private_key(ctx)) { 142 if (!SSL_CTX_check_private_key(ctx)) {
139 printf ("%s\n", _("CRITICAL - Private key does not seem to match certificate!\n")); 143 printf("%s\n", _("CRITICAL - Private key does not seem to match certificate!\n"));
140 return STATE_CRITICAL; 144 return STATE_CRITICAL;
141 } 145 }
142#endif 146# endif
143 } 147 }
144#ifdef SSL_OP_NO_TICKET 148# ifdef SSL_OP_NO_TICKET
145 options |= SSL_OP_NO_TICKET; 149 options |= SSL_OP_NO_TICKET;
146#endif 150# endif
147 SSL_CTX_set_options(ctx, options); 151 SSL_CTX_set_options(ctx, options);
148 SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); 152 SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
149 if ((s = SSL_new(ctx)) != NULL) { 153 if ((s = SSL_new(ctx)) != NULL) {
150#ifdef SSL_set_tlsext_host_name 154# ifdef SSL_set_tlsext_host_name
151 if (host_name != NULL) 155 if (host_name != NULL) {
152 SSL_set_tlsext_host_name(s, host_name); 156 SSL_set_tlsext_host_name(s, host_name);
153#endif 157 }
158# endif
154 SSL_set_fd(s, sd); 159 SSL_set_fd(s, sd);
155 if (SSL_connect(s) == 1) { 160 if (SSL_connect(s) == 1) {
156 return OK; 161 return OK;
157 } else { 162 } else {
158 printf("%s\n", _("CRITICAL - Cannot make SSL connection.")); 163 printf("%s\n", _("CRITICAL - Cannot make SSL connection."));
159# ifdef USE_OPENSSL /* XXX look into ERR_error_string */ 164# ifdef USE_OPENSSL /* XXX look into ERR_error_string */
160 ERR_print_errors_fp(stdout); 165 ERR_print_errors_fp(stdout);
161# endif /* USE_OPENSSL */ 166# endif /* USE_OPENSSL */
162 } 167 }
163 } else { 168 } else {
164 printf("%s\n", _("CRITICAL - Cannot initiate SSL handshake.")); 169 printf("%s\n", _("CRITICAL - Cannot initiate SSL handshake."));
165 } 170 }
166 return STATE_CRITICAL; 171 return STATE_CRITICAL;
167} 172}
168 173
169void np_net_ssl_cleanup() { 174void np_net_ssl_cleanup() {
170 if (s) { 175 if (s) {
171#ifdef SSL_set_tlsext_host_name 176# ifdef SSL_set_tlsext_host_name
172 SSL_set_tlsext_host_name(s, NULL); 177 SSL_set_tlsext_host_name(s, NULL);
173#endif 178# endif
174 SSL_shutdown(s); 179 SSL_shutdown(s);
175 SSL_free(s); 180 SSL_free(s);
176 if (ctx) { 181 if (ctx) {
177 SSL_CTX_free(ctx); 182 SSL_CTX_free(ctx);
178 ctx=NULL; 183 ctx = NULL;
179 } 184 }
180 s=NULL; 185 s = NULL;
181 } 186 }
182} 187}
183 188
184int np_net_ssl_write(const void *buf, int num) { 189int np_net_ssl_write(const void *buf, int num) { return SSL_write(s, buf, num); }
185 return SSL_write(s, buf, num);
186}
187
188int np_net_ssl_read(void *buf, int num) {
189 return SSL_read(s, buf, num);
190}
191 190
192int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit){ 191int np_net_ssl_read(void *buf, int num) { return SSL_read(s, buf, num); }
193# ifdef USE_OPENSSL
194 X509_NAME *subj=NULL;
195 char timestamp[50] = "";
196 char cn[MAX_CN_LENGTH]= "";
197 char *tz;
198
199 int cnlen =-1;
200 int status=STATE_UNKNOWN;
201
202 ASN1_STRING *tm;
203 int offset;
204 struct tm stamp;
205 float time_left;
206 int days_left;
207 int time_remaining;
208 time_t tm_t;
209 192
193mp_state_enum np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn,
194 int days_till_exp_crit) {
195# ifdef USE_OPENSSL
210 if (!certificate) { 196 if (!certificate) {
211 printf("%s\n",_("CRITICAL - Cannot retrieve server certificate.")); 197 printf("%s\n", _("CRITICAL - No server certificate present to inspect."));
212 return STATE_CRITICAL; 198 return STATE_CRITICAL;
213 } 199 }
214 200
215 /* Extract CN from certificate subject */ 201 /* Extract CN from certificate subject */
216 subj=X509_get_subject_name(certificate); 202 X509_NAME *subj = X509_get_subject_name(certificate);
217 203
218 if (!subj) { 204 if (!subj) {
219 printf("%s\n",_("CRITICAL - Cannot retrieve certificate subject.")); 205 printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject."));
220 return STATE_CRITICAL; 206 return STATE_CRITICAL;
221 } 207 }
222 cnlen = X509_NAME_get_text_by_NID(subj, NID_commonName, cn, sizeof(cn)); 208
223 if (cnlen == -1) 209 char cn[MAX_CN_LENGTH] = "";
210 int cnlen = X509_NAME_get_text_by_NID(subj, NID_commonName, cn, sizeof(cn));
211 if (cnlen == -1) {
224 strcpy(cn, _("Unknown CN")); 212 strcpy(cn, _("Unknown CN"));
213 }
225 214
226 /* Retrieve timestamp of certificate */ 215 /* Retrieve timestamp of certificate */
227 tm = X509_get_notAfter(certificate); 216 ASN1_STRING *tm = X509_get_notAfter(certificate);
228 217
218 int offset = 0;
219 struct tm stamp = {};
229 /* Generate tm structure to process timestamp */ 220 /* Generate tm structure to process timestamp */
230 if (tm->type == V_ASN1_UTCTIME) { 221 if (tm->type == V_ASN1_UTCTIME) {
231 if (tm->length < 10) { 222 if (tm->length < 10) {
232 printf("%s\n", _("CRITICAL - Wrong time format in certificate.")); 223 printf("%s\n", _("CRITICAL - Wrong time format in certificate."));
233 return STATE_CRITICAL; 224 return STATE_CRITICAL;
234 } else {
235 stamp.tm_year = (tm->data[0] - '0') * 10 + (tm->data[1] - '0');
236 if (stamp.tm_year < 50)
237 stamp.tm_year += 100;
238 offset = 0;
239 } 225 }
226 stamp.tm_year = (tm->data[0] - '0') * 10 + (tm->data[1] - '0');
227 if (stamp.tm_year < 50) {
228 stamp.tm_year += 100;
229 }
230 offset = 0;
231
240 } else { 232 } else {
241 if (tm->length < 12) { 233 if (tm->length < 12) {
242 printf("%s\n", _("CRITICAL - Wrong time format in certificate.")); 234 printf("%s\n", _("CRITICAL - Wrong time format in certificate."));
243 return STATE_CRITICAL; 235 return STATE_CRITICAL;
244 } else {
245 stamp.tm_year =
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;
249 offset = 2;
250 } 236 }
237 stamp.tm_year = (tm->data[0] - '0') * 1000 + (tm->data[1] - '0') * 100 +
238 (tm->data[2] - '0') * 10 + (tm->data[3] - '0');
239 stamp.tm_year -= 1900;
240 offset = 2;
251 } 241 }
252 stamp.tm_mon = 242 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; 243 stamp.tm_mday = (tm->data[4 + offset] - '0') * 10 + (tm->data[5 + offset] - '0');
254 stamp.tm_mday = 244 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'); 245 stamp.tm_min = (tm->data[8 + offset] - '0') * 10 + (tm->data[9 + offset] - '0');
256 stamp.tm_hour = 246 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; 247 stamp.tm_isdst = -1;
263 248
264 tm_t = timegm(&stamp); 249 time_t tm_t = timegm(&stamp);
265 time_left = difftime(tm_t, time(NULL)); 250 float time_left = difftime(tm_t, time(NULL));
266 days_left = time_left / 86400; 251 int days_left = time_left / 86400;
267 tz = getenv("TZ"); 252 char *tz = getenv("TZ");
268 setenv("TZ", "GMT", 1); 253 setenv("TZ", "GMT", 1);
269 tzset(); 254 tzset();
255
256 char timestamp[50] = "";
270 strftime(timestamp, 50, "%c %z", localtime(&tm_t)); 257 strftime(timestamp, 50, "%c %z", localtime(&tm_t));
271 if (tz) 258 if (tz) {
272 setenv("TZ", tz, 1); 259 setenv("TZ", tz, 1);
273 else 260 } else {
274 unsetenv("TZ"); 261 unsetenv("TZ");
262 }
263
275 tzset(); 264 tzset();
276 265
266 int time_remaining;
267 mp_state_enum status = STATE_UNKNOWN;
277 if (days_left > 0 && days_left <= days_till_exp_warn) { 268 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); 269 printf(_("%s - Certificate '%s' expires in %d day(s) (%s).\n"),
279 if (days_left > days_till_exp_crit) 270 (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, days_left, timestamp);
271 if (days_left > days_till_exp_crit) {
280 status = STATE_WARNING; 272 status = STATE_WARNING;
281 else 273 } else {
282 status = STATE_CRITICAL; 274 status = STATE_CRITICAL;
275 }
283 } else if (days_left == 0 && time_left > 0) { 276 } else if (days_left == 0 && time_left > 0) {
284 if (time_left >= 3600) 277 if (time_left >= 3600) {
285 time_remaining = (int) time_left / 3600; 278 time_remaining = (int)time_left / 3600;
286 else 279 } else {
287 time_remaining = (int) time_left / 60; 280 time_remaining = (int)time_left / 60;
281 }
288 282
289 printf (_("%s - Certificate '%s' expires in %u %s (%s)\n"), 283 printf(_("%s - Certificate '%s' expires in %u %s (%s)\n"),
290 (days_left>days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, time_remaining, 284 (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, time_remaining,
291 time_left >= 3600 ? "hours" : "minutes", timestamp); 285 time_left >= 3600 ? "hours" : "minutes", timestamp);
292 286
293 if ( days_left > days_till_exp_crit) 287 if (days_left > days_till_exp_crit) {
294 status = STATE_WARNING; 288 status = STATE_WARNING;
295 else 289 } else {
296 status = STATE_CRITICAL; 290 status = STATE_CRITICAL;
291 }
297 } else if (time_left < 0) { 292 } else if (time_left < 0) {
298 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), cn, timestamp); 293 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), cn, timestamp);
299 status=STATE_CRITICAL; 294 status = STATE_CRITICAL;
300 } else if (days_left == 0) { 295 } else if (days_left == 0) {
301 printf (_("%s - Certificate '%s' just expired (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", cn, timestamp); 296 printf(_("%s - Certificate '%s' just expired (%s).\n"),
302 if (days_left > days_till_exp_crit) 297 (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, timestamp);
298 if (days_left > days_till_exp_crit) {
303 status = STATE_WARNING; 299 status = STATE_WARNING;
304 else 300 } else {
305 status = STATE_CRITICAL; 301 status = STATE_CRITICAL;
302 }
306 } else { 303 } else {
307 printf(_("OK - Certificate '%s' will expire on %s.\n"), cn, timestamp); 304 printf(_("OK - Certificate '%s' will expire on %s.\n"), cn, timestamp);
308 status = STATE_OK; 305 status = STATE_OK;
309 } 306 }
310 X509_free(certificate); 307 X509_free(certificate);
311 return status; 308 return status;
312# else /* ifndef USE_OPENSSL */ 309# else /* ifndef USE_OPENSSL */
313 printf("%s\n", _("WARNING - Plugin does not support checking certificates.")); 310 printf("%s\n", _("WARNING - Plugin does not support checking certificates."));
314 return STATE_WARNING; 311 return STATE_WARNING;
315# endif /* USE_OPENSSL */ 312# endif /* USE_OPENSSL */
316} 313}
317 314
318int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit){ 315mp_state_enum np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit) {
319# ifdef USE_OPENSSL 316# ifdef USE_OPENSSL
320 X509 *certificate = NULL; 317 X509 *certificate = NULL;
321 certificate=SSL_get_peer_certificate(s); 318 certificate = SSL_get_peer_certificate(s);
322 return(np_net_ssl_check_certificate(certificate, days_till_exp_warn, days_till_exp_crit)); 319 return (np_net_ssl_check_certificate(certificate, days_till_exp_warn, days_till_exp_crit));
323# else /* ifndef USE_OPENSSL */ 320# else /* ifndef USE_OPENSSL */
324 printf("%s\n", _("WARNING - Plugin does not support checking certificates.")); 321 printf("%s\n", _("WARNING - Plugin does not support checking certificates."));
325 return STATE_WARNING; 322 return STATE_WARNING;
326# endif /* USE_OPENSSL */ 323# endif /* USE_OPENSSL */
327} 324}
328 325
326mp_subcheck mp_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn,
327 int days_till_exp_crit) {
328 mp_subcheck sc_cert = mp_subcheck_init();
329# ifdef USE_OPENSSL
330 if (!certificate) {
331 xasprintf(&sc_cert.output, _("No server certificate present to inspect"));
332 sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
333 return sc_cert;
334 }
335
336 /* Extract CN from certificate subject */
337 X509_NAME *subj = X509_get_subject_name(certificate);
338
339 if (!subj) {
340 xasprintf(&sc_cert.output, _("Cannot retrieve certificate subject"));
341 sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
342 return sc_cert;
343 }
344
345 char commonName[MAX_CN_LENGTH] = "";
346 int cnlen = X509_NAME_get_text_by_NID(subj, NID_commonName, commonName, sizeof(commonName));
347 if (cnlen == -1) {
348 strcpy(commonName, _("Unknown CN"));
349 }
329 350
351 /* Retrieve timestamp of certificate */
352 ASN1_STRING *expiry_timestamp = X509_get_notAfter(certificate);
353
354 int offset = 0;
355 struct tm stamp = {};
356 /* Generate tm structure to process timestamp */
357 if (expiry_timestamp->type == V_ASN1_UTCTIME) {
358 if (expiry_timestamp->length < 10) {
359 xasprintf(&sc_cert.output, _("Wrong time format in certificate"));
360 sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
361 return sc_cert;
362 }
363
364 stamp.tm_year = (expiry_timestamp->data[0] - '0') * 10 + (expiry_timestamp->data[1] - '0');
365 if (stamp.tm_year < 50) {
366 stamp.tm_year += 100;
367 }
368
369 offset = 0;
370 } else {
371 if (expiry_timestamp->length < 12) {
372 xasprintf(&sc_cert.output, _("Wrong time format in certificate"));
373 sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
374 return sc_cert;
375 }
376 stamp.tm_year = (expiry_timestamp->data[0] - '0') * 1000 +
377 (expiry_timestamp->data[1] - '0') * 100 +
378 (expiry_timestamp->data[2] - '0') * 10 + (expiry_timestamp->data[3] - '0');
379 stamp.tm_year -= 1900;
380 offset = 2;
381 }
382
383 stamp.tm_mon = (expiry_timestamp->data[2 + offset] - '0') * 10 +
384 (expiry_timestamp->data[3 + offset] - '0') - 1;
385 stamp.tm_mday = (expiry_timestamp->data[4 + offset] - '0') * 10 +
386 (expiry_timestamp->data[5 + offset] - '0');
387 stamp.tm_hour = (expiry_timestamp->data[6 + offset] - '0') * 10 +
388 (expiry_timestamp->data[7 + offset] - '0');
389 stamp.tm_min = (expiry_timestamp->data[8 + offset] - '0') * 10 +
390 (expiry_timestamp->data[9 + offset] - '0');
391 stamp.tm_sec = (expiry_timestamp->data[10 + offset] - '0') * 10 +
392 (expiry_timestamp->data[11 + offset] - '0');
393 stamp.tm_isdst = -1;
394
395 time_t tm_t = timegm(&stamp);
396 double time_left = difftime(tm_t, time(NULL));
397 int days_left = (int)(time_left / 86400);
398 char *timeZone = getenv("TZ");
399 setenv("TZ", "GMT", 1);
400 tzset();
401
402 char timestamp[50] = "";
403 strftime(timestamp, 50, "%c %z", localtime(&tm_t));
404 if (timeZone) {
405 setenv("TZ", timeZone, 1);
406 } else {
407 unsetenv("TZ");
408 }
409
410 tzset();
411
412 int time_remaining;
413 if (days_left > 0 && days_left <= days_till_exp_warn) {
414 xasprintf(&sc_cert.output, _("Certificate '%s' expires in %d day(s) (%s)"), commonName,
415 days_left, timestamp);
416 if (days_left > days_till_exp_crit) {
417 sc_cert = mp_set_subcheck_state(sc_cert, STATE_WARNING);
418 } else {
419 sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
420 }
421 } else if (days_left == 0 && time_left > 0) {
422 if (time_left >= 3600) {
423 time_remaining = (int)time_left / 3600;
424 } else {
425 time_remaining = (int)time_left / 60;
426 }
427
428 xasprintf(&sc_cert.output, _("Certificate '%s' expires in %u %s (%s)"), commonName,
429 time_remaining, time_left >= 3600 ? "hours" : "minutes", timestamp);
430
431 if (days_left > days_till_exp_crit) {
432 sc_cert = mp_set_subcheck_state(sc_cert, STATE_WARNING);
433 } else {
434 sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
435 }
436 } else if (time_left < 0) {
437 xasprintf(&sc_cert.output, _("Certificate '%s' expired on %s"), commonName, timestamp);
438 sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
439 } else if (days_left == 0) {
440 xasprintf(&sc_cert.output, _("Certificate '%s' just expired (%s)"), commonName, timestamp);
441 if (days_left > days_till_exp_crit) {
442 sc_cert = mp_set_subcheck_state(sc_cert, STATE_WARNING);
443 } else {
444 sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
445 }
446 } else {
447 xasprintf(&sc_cert.output, _("Certificate '%s' will expire on %s"), commonName, timestamp);
448 sc_cert = mp_set_subcheck_state(sc_cert, STATE_OK);
449 }
450 X509_free(certificate);
451 return sc_cert;
452# else /* ifndef USE_OPENSSL */
453 xasprintf(&sc_cert.output, _("Plugin does not support checking certificates"));
454 sc_cert = mp_set_subcheck_state(sc_cert, STATE_WARNING);
455 return sc_cert;
456# endif /* USE_OPENSSL */
457}
330#endif /* HAVE_SSL */ 458#endif /* HAVE_SSL */
diff --git a/plugins/t/check_apt.t b/plugins/t/check_apt.t
index 430eb53e..736bc2f2 100644
--- a/plugins/t/check_apt.t
+++ b/plugins/t/check_apt.t
@@ -5,6 +5,7 @@
5# 5#
6 6
7use strict; 7use strict;
8use warnings;
8use Test::More; 9use Test::More;
9use NPTest; 10use NPTest;
10 11
@@ -12,18 +13,18 @@ sub make_result_regexp {
12 my ($warning, $critical) = @_; 13 my ($warning, $critical) = @_;
13 my $status; 14 my $status;
14 if ($warning == 0 && $critical == 0) { 15 if ($warning == 0 && $critical == 0) {
15 $status = "OK"; 16 $status = "OK";
16 } elsif ($critical == 0) { 17 } elsif ($critical == 0) {
17 $status = "WARNING"; 18 $status = "WARNING";
18 } else { 19 } else {
19 $status = "CRITICAL"; 20 $status = "CRITICAL";
20 } 21 }
21 return sprintf('/^APT %s: %d packages available for upgrade \(%d critical updates\)\. |available_upgrades=%d;;;0 critical_updates=%d;;;0$/', 22 return sprintf('/.*[%s].*Updates available: %d.*Security updates available: %d.*\'available_upgrades\'=%d;;; \'critical_updates\'=%d;;; /s',
22 $status, $warning, $critical, $warning, $critical); 23 $status, $warning, $critical, $warning, $critical);
23} 24}
24 25
25if (-x "./check_apt") { 26if (-x "./check_apt") {
26 plan tests => 36; 27 plan tests => 35;
27} else { 28} else {
28 plan skip_all => "No check_apt compiled"; 29 plan skip_all => "No check_apt compiled";
29} 30}
@@ -42,7 +43,8 @@ like( $result->output, make_result_regexp(13, 0), "Output correct" );
42 43
43$result = NPTest->testCmd( sprintf($testfile_command, "-o", "debian2") ); 44$result = NPTest->testCmd( sprintf($testfile_command, "-o", "debian2") );
44is( $result->return_code, 0, "Debian apt output, no critical" ); 45is( $result->return_code, 0, "Debian apt output, no critical" );
45like( $result->output, make_result_regexp(13, 0), "Output correct" ); 46# this test does not work, since -o was given
47# like( $result->output, make_result_regexp(13, 0), "Output correct" );
46 48
47$result = NPTest->testCmd( sprintf($testfile_command, "", "debian3") ); 49$result = NPTest->testCmd( sprintf($testfile_command, "", "debian3") );
48is( $result->return_code, 2, "Debian apt output, some critical" ); 50is( $result->return_code, 2, "Debian apt output, some critical" );
diff --git a/plugins/t/check_curl.t b/plugins/t/check_curl.t
index 7a930a4e..2c2fafde 100644
--- a/plugins/t/check_curl.t
+++ b/plugins/t/check_curl.t
@@ -13,12 +13,12 @@ use vars qw($tests $has_ipv6);
13BEGIN { 13BEGIN {
14 use NPTest; 14 use NPTest;
15 $has_ipv6 = NPTest::has_ipv6(); 15 $has_ipv6 = NPTest::has_ipv6();
16 $tests = $has_ipv6 ? 59 : 57; 16 $tests = $has_ipv6 ? 55 : 53;
17 plan tests => $tests; 17 plan tests => $tests;
18} 18}
19 19
20 20
21my $successOutput = '/OK.*HTTP.*second/'; 21my $successOutput = '/.*HTTP.*second/';
22 22
23my $res; 23my $res;
24my $plugin = 'check_http'; 24my $plugin = 'check_http';
@@ -63,7 +63,7 @@ $res = NPTest->testCmd(
63 ); 63 );
64cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" ); 64cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" );
65# was CRITICAL only, but both check_curl and check_http print HTTP CRITICAL (puzzle?!) 65# was CRITICAL only, but both check_curl and check_http print HTTP CRITICAL (puzzle?!)
66like( $res->output, "/HTTP CRITICAL - Invalid HTTP response received from host on port 80: cURL returned 28 - Connection timed out after/", "Output OK"); 66like( $res->output, "/cURL returned 28 - Connection timed out after/", "Output OK");
67 67
68$res = NPTest->testCmd( 68$res = NPTest->testCmd(
69 "./$plugin $hostname_invalid -wt 1 -ct 2" 69 "./$plugin $hostname_invalid -wt 1 -ct 2"
@@ -124,14 +124,14 @@ SKIP: {
124 124
125 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing'" ); 125 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing'" );
126 cmp_ok( $res->return_code, "==", 2, "Not got 'mONiTORing'"); 126 cmp_ok( $res->return_code, "==", 2, "Not got 'mONiTORing'");
127 like ( $res->output, "/pattern not found/", "Error message says 'pattern not found'"); 127 like ( $res->output, "/matched not/", "Error message says 'matched not'");
128 128
129 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -R 'mONiTORing'" ); 129 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -R 'mONiTORing'" );
130 cmp_ok( $res->return_code, "==", 0, "But case insensitive doesn't mind 'mONiTORing'"); 130 cmp_ok( $res->return_code, "==", 0, "But case insensitive doesn't mind 'mONiTORing'");
131 131
132 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'monitoring' --invert-regex" ); 132 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'monitoring' --invert-regex" );
133 cmp_ok( $res->return_code, "==", 2, "Invert results work when found"); 133 cmp_ok( $res->return_code, "==", 2, "Invert results work when found");
134 like ( $res->output, "/pattern found/", "Error message says 'pattern found'"); 134 like ( $res->output, "/matched/", "Error message says 'matched'");
135 135
136 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing' --invert-regex" ); 136 $res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing' --invert-regex" );
137 cmp_ok( $res->return_code, "==", 0, "And also when not found"); 137 cmp_ok( $res->return_code, "==", 0, "And also when not found");
@@ -151,63 +151,74 @@ SKIP: {
151 151
152 $res = NPTest->testCmd( "./$plugin -C 8000,1 --ssl $host_tls_http" ); 152 $res = NPTest->testCmd( "./$plugin -C 8000,1 --ssl $host_tls_http" );
153 cmp_ok( $res->return_code, '==', 1, "Checking certificate for $host_tls_http"); 153 cmp_ok( $res->return_code, '==', 1, "Checking certificate for $host_tls_http");
154 like ( $res->output, qr/WARNING - Certificate '$host_tls_cert' expires in \d+ day/, "Output Warning" ); 154 like ( $res->output, qr/Certificate '$host_tls_cert' expires in \d+ day/, "Output Warning" );
155 155
156 $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" ); 156 $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" );
157 is( $res->return_code, 0, "Old syntax for cert checking okay" ); 157 is( $res->return_code, 0, "Old syntax for cert checking okay" );
158 is( $res->output, $saved_cert_output, "Same output as new syntax" ); 158 # deactivated since different timings will change the output
159 # TODO compare without perfdata
160 # is( $res->output, $saved_cert_output, "Same output as new syntax" );
159 161
160 $res = NPTest->testCmd( "./$plugin -H $host_tls_http -C 1" ); 162 $res = NPTest->testCmd( "./$plugin -H $host_tls_http -C 1" );
161 is( $res->return_code, 0, "Updated syntax for cert checking okay" ); 163 is( $res->return_code, 0, "Updated syntax for cert checking okay" );
162 is( $res->output, $saved_cert_output, "Same output as new syntax" ); 164 # deactivated since different timings will change the output
165 # TODO compare without perfdata
166 # is( $res->output, $saved_cert_output, "Same output as new syntax" );
163 167
164 $res = NPTest->testCmd( "./$plugin -C 1 $host_tls_http" ); 168 $res = NPTest->testCmd( "./$plugin -C 1 $host_tls_http" );
165 cmp_ok( $res->output, 'eq', $saved_cert_output, "--ssl option automatically added"); 169 # deactivated since different timings will change the output
170 # TODO compare without perfdata
171 # cmp_ok( $res->output, 'eq', $saved_cert_output, "--ssl option automatically added");
166 172
167 $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" ); 173 $res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" );
168 cmp_ok( $res->output, 'eq', $saved_cert_output, "Old syntax for cert checking still works"); 174 # deactivated since different timings will change the output
175 # TODO compare without perfdata
176 # cmp_ok( $res->output, 'eq', $saved_cert_output, "Old syntax for cert checking still works");
169 177
170 # run some certificate checks with faketime 178 # run some certificate checks with faketime
171 SKIP: { 179 SKIP: {
172 skip "No faketime binary found", 12 if !$faketime; 180 skip "No faketime binary found", 12 if !$faketime;
173 $res = NPTest->testCmd("LC_TIME=C TZ=UTC ./$plugin -C 1 $host_tls_http"); 181 $res = NPTest->testCmd("LC_TIME=C TZ=UTC ./$plugin -C 1 $host_tls_http");
174 like($res->output, qr/OK - Certificate '$host_tls_cert' will expire on/, "Catch cert output"); 182 like($res->output, qr/Certificate '$host_tls_cert' will expire on/, "Catch cert output");
175 is( $res->return_code, 0, "Catch cert output exit code" ); 183 is( $res->return_code, 0, "Catch cert output exit code" );
184
176 my($mon,$day,$hour,$min,$sec,$year) = ($res->output =~ /(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)/); 185 my($mon,$day,$hour,$min,$sec,$year) = ($res->output =~ /(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)/);
177 if(!defined $year) { 186 if(!defined $year) {
178 die("parsing date failed from: ".$res->output); 187 die("parsing date failed from: ".$res->output);
179 } 188 }
189
180 my $months = {'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3, 'May' => 4, 'Jun' => 5, 'Jul' => 6, 'Aug' => 7, 'Sep' => 8, 'Oct' => 9, 'Nov' => 10, 'Dec' => 11}; 190 my $months = {'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3, 'May' => 4, 'Jun' => 5, 'Jul' => 6, 'Aug' => 7, 'Sep' => 8, 'Oct' => 9, 'Nov' => 10, 'Dec' => 11};
181 my $ts = mktime($sec, $min, $hour, $day, $months->{$mon}, $year-1900); 191 my $ts = mktime($sec, $min, $hour, $day, $months->{$mon}, $year-1900);
182 my $time = strftime("%Y-%m-%d %H:%M:%S", localtime($ts)); 192 my $time = strftime("%Y-%m-%d %H:%M:%S", localtime($ts));
193
183 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./$plugin -C 1 $host_tls_http"); 194 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./$plugin -C 1 $host_tls_http");
184 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' just expired/, "Output on expire date"); 195 like($res->output, qr/Certificate '$host_tls_cert' just expired/, "Output on expire date");
185 is( $res->return_code, 2, "Output on expire date" ); 196 is( $res->return_code, 2, "Output on expire date" );
186 197
187 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-1))."' ./$plugin -C 1 $host_tls_http"); 198 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-1))."' ./$plugin -C 1 $host_tls_http");
188 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 0 minutes/, "cert expires in 1 second output"); 199 like($res->output, qr/Certificate '$host_tls_cert' expires in 0 minutes/, "cert expires in 1 second output");
189 is( $res->return_code, 2, "cert expires in 1 second exit code" ); 200 is( $res->return_code, 2, "cert expires in 1 second exit code" );
190 201
191 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-120))."' ./$plugin -C 1 $host_tls_http"); 202 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-120))."' ./$plugin -C 1 $host_tls_http");
192 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 2 minutes/, "cert expires in 2 minutes output"); 203 like($res->output, qr/Certificate '$host_tls_cert' expires in 2 minutes/, "cert expires in 2 minutes output");
193 is( $res->return_code, 2, "cert expires in 2 minutes exit code" ); 204 is( $res->return_code, 2, "cert expires in 2 minutes exit code" );
194 205
195 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-7200))."' ./$plugin -C 1 $host_tls_http"); 206 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-7200))."' ./$plugin -C 1 $host_tls_http");
196 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 2 hours/, "cert expires in 2 hours output"); 207 like($res->output, qr/Certificate '$host_tls_cert' expires in 2 hours/, "cert expires in 2 hours output");
197 is( $res->return_code, 2, "cert expires in 2 hours exit code" ); 208 is( $res->return_code, 2, "cert expires in 2 hours exit code" );
198 209
199 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./$plugin -C 1 $host_tls_http"); 210 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./$plugin -C 1 $host_tls_http");
200 like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expired on/, "Certificate expired output"); 211 like($res->output, qr/Certificate '$host_tls_cert' expired on/, "Certificate expired output");
201 is( $res->return_code, 2, "Certificate expired exit code" ); 212 is( $res->return_code, 2, "Certificate expired exit code" );
202 }; 213 };
203 214
204 $res = NPTest->testCmd( "./$plugin --ssl $host_tls_http -E" ); 215 $res = NPTest->testCmd( "./$plugin --ssl $host_tls_http -E" );
205 like ( $res->output, '/time_connect=[\d\.]+/', 'Extended Performance Data Output OK' ); 216 like ( $res->output, '/\'time_connect\'=[\d\.]+/', 'Extended Performance Data Output OK' );
206 like ( $res->output, '/time_ssl=[\d\.]+/', 'Extended Performance Data SSL Output OK' ); 217 like ( $res->output, '/\'time_tls\'=[\d\.]+/', 'Extended Performance Data SSL Output OK' );
207 218
208 $res = NPTest->testCmd( "./$plugin -H monitoring-plugins.org -u /download.html -f follow" ); 219 $res = NPTest->testCmd( "./$plugin -H monitoring-plugins.org -u /download.html -f follow" );
209 is( $res->return_code, 0, "Redirection based on location is okay"); 220 is( $res->return_code, 0, "Redirection based on location is okay");
210 221
211 $res = NPTest->testCmd( "./$plugin -H monitoring-plugins.org --extended-perfdata" ); 222 $res = NPTest->testCmd( "./$plugin -H monitoring-plugins.org --extended-perfdata" );
212 like ( $res->output, '/time_connect=[\d\.]+/', 'Extended Performance Data Output OK' ); 223 like ( $res->output, '/\'time_connect\'=[\d\.]+/', 'Extended Performance Data Output OK' );
213} 224}
diff --git a/plugins/t/check_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_snmp.t b/plugins/t/check_snmp.t
index 576cc506..8d435df3 100644
--- a/plugins/t/check_snmp.t
+++ b/plugins/t/check_snmp.t
@@ -10,7 +10,7 @@ use NPTest;
10 10
11BEGIN { 11BEGIN {
12 plan skip_all => 'check_snmp is not compiled' unless -x "./check_snmp"; 12 plan skip_all => 'check_snmp is not compiled' unless -x "./check_snmp";
13 plan tests => 63; 13 plan tests => 62;
14} 14}
15 15
16my $res; 16my $res;
@@ -24,7 +24,7 @@ my $user_snmp = getTestParameter("NP_SNMP_USER", "An SNMP user", "auth_
24 24
25$res = NPTest->testCmd( "./check_snmp -t 1" ); 25$res = NPTest->testCmd( "./check_snmp -t 1" );
26is( $res->return_code, 3, "No host name" ); 26is( $res->return_code, 3, "No host name" );
27is( $res->output, "No host specified" ); 27is( $res->output, "No OIDs specified" );
28 28
29$res = NPTest->testCmd( "./check_snmp -H fakehostname --ignore-mib-parsing-errors" ); 29$res = NPTest->testCmd( "./check_snmp -H fakehostname --ignore-mib-parsing-errors" );
30is( $res->return_code, 3, "No OIDs specified" ); 30is( $res->return_code, 3, "No OIDs specified" );
@@ -32,145 +32,124 @@ is( $res->output, "No OIDs specified" );
32 32
33$res = NPTest->testCmd( "./check_snmp -H fakehost --ignore-mib-parsing-errors -o oids -P 3 -U not_a_user --seclevel=rubbish" ); 33$res = NPTest->testCmd( "./check_snmp -H fakehost --ignore-mib-parsing-errors -o oids -P 3 -U not_a_user --seclevel=rubbish" );
34is( $res->return_code, 3, "Invalid seclevel" ); 34is( $res->return_code, 3, "Invalid seclevel" );
35like( $res->output, "/check_snmp: Invalid seclevel - rubbish/" ); 35like( $res->output, "/invalid security level: rubbish/" );
36 36
37$res = NPTest->testCmd( "./check_snmp -H fakehost --ignore-mib-parsing-errors -o oids -P 3c" ); 37$res = NPTest->testCmd( "./check_snmp -H fakehost --ignore-mib-parsing-errors -o oids -P 3c" );
38is( $res->return_code, 3, "Invalid protocol" ); 38is( $res->return_code, 3, "Invalid protocol" );
39like( $res->output, "/check_snmp: Invalid SNMP version - 3c/" ); 39like( $res->output, "/invalid SNMP version/protocol: 3c/" );
40 40
41SKIP: { 41SKIP: {
42 skip "no snmp host defined", 50 if ( ! $host_snmp ); 42 skip "no snmp host defined", 50 if ( ! $host_snmp );
43 43
44 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -w 1: -c 1:"); 44 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -P 2c -C $snmp_community -o system.sysUpTime.0 -w 1: -c 1:");
45 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying uptime" ); 45 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying uptime" );
46 like($res->output, '/^SNMP OK - (\d+)/', "String contains SNMP OK"); 46 $res->output =~ /\|.*=(\d+);/;
47 $res->output =~ /^SNMP OK - (\d+)/;
48 my $value = $1; 47 my $value = $1;
49 cmp_ok( $value, ">", 0, "Got a time value" ); 48 cmp_ok( $value, ">", 0, "Got a time value" );
50 like($res->perf_output, "/sysUpTime.*$1/", "Got perfdata with value '$1' in it"); 49 like($res->perf_output, "/sysUpTime.*$1/", "Got perfdata with value '$1' in it");
51 50
52 51
53 # some more threshold tests 52 # some more threshold tests
54 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1"); 53 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1 -P 2c");
55 cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1" ); 54 cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1" );
56 55
57 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1:"); 56 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1: -P 2c");
58 cmp_ok( $res->return_code, '==', 0, "Threshold test -c 1:" ); 57 cmp_ok( $res->return_code, '==', 0, "Threshold test -c 1:" );
59 58
60 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c ~:1"); 59 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c ~:1 -P 2c");
61 cmp_ok( $res->return_code, '==', 2, "Threshold test -c ~:1" ); 60 cmp_ok( $res->return_code, '==', 2, "Threshold test -c ~:1" );
62 61
63 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1:10"); 62 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1:10 -P 2c");
64 cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1:10" ); 63 cmp_ok( $res->return_code, '==', 2, "Threshold test -c 1:10" );
65 64
66 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c \@1:10"); 65 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c \@1:10 -P 2c");
67 cmp_ok( $res->return_code, '==', 0, "Threshold test -c \@1:10" ); 66 cmp_ok( $res->return_code, '==', 0, "Threshold test -c \@1:10" );
68 67
69 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 10:1");
70 cmp_ok( $res->return_code, '==', 0, "Threshold test -c 10:1" );
71
72 68
73 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o .1.3.6.1.2.1.1.3.0 -w 1: -c 1:"); 69 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o .1.3.6.1.2.1.1.3.0 -w 1: -c 1: -P 2c");
74 cmp_ok( $res->return_code, '==', 0, "Test with numeric OID (no mibs loaded)" ); 70 cmp_ok( $res->return_code, '==', 0, "Test with numeric OID (no mibs loaded)" );
75 like($res->output, '/^SNMP OK - \d+/', "String contains SNMP OK");
76 71
77 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0"); 72 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0 -P 2c");
78 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying sysDescr" ); 73 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying sysDescr" );
79 unlike($res->perf_output, '/sysDescr/', "Perfdata doesn't contain string values"); 74 unlike($res->perf_output, '/sysDescr/', "Perfdata doesn't contain string values");
80 75
81 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0,system.sysDescr.0"); 76 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0,system.sysDescr.0 -P 2c");
82 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, comma-separated" ); 77 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, comma-separated" );
83 like($res->output, '/^SNMP OK - /', "String contains SNMP OK");
84 78
85 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0 -o system.sysDescr.0"); 79 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysDescr.0 -o system.sysDescr.0 -P 2c");
86 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, repeated option" ); 80 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying two string OIDs, repeated option" );
87 like($res->output, '/^SNMP OK - /', "String contains SNMP OK");
88 81
89 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 1:1 -c 1:1"); 82 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 1:1 -c 1:1 -P 2c");
90 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrSWRunIndex.1" ); 83 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrSWRunIndex.1" );
91 like($res->output, '/^SNMP OK - 1\s.*$/', "String fits SNMP OK and output format");
92 84
93 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 0 -c 1:"); 85 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w 0 -c 1: -P 2c");
94 cmp_ok( $res->return_code, '==', 1, "Exit WARNING when querying hrSWRunIndex.1 and warn-th doesn't apply " ); 86 cmp_ok( $res->return_code, '==', 1, "Exit WARNING when querying hrSWRunIndex.1 and warn-th doesn't apply " );
95 like($res->output, '/^SNMP WARNING - \*1\*\s.*$/', "String matches SNMP WARNING and output format");
96 87
97 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w :0 -c 0"); 88 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w :0 -c 0 -P 2c");
98 cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL when querying hrSWRunIndex.1 and crit-th doesn't apply" ); 89 cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL when querying hrSWRunIndex.1 and crit-th doesn't apply" );
99 like($res->output, '/^SNMP CRITICAL - \*1\*\s.*$/', "String matches SNMP CRITICAL and output format");
100 90
101 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2 -c 1:2"); 91 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2 -c 1:2 -P 2c");
102 cmp_ok( $res->return_code, '==', 0, "Checking two OIDs at once" ); 92 cmp_ok( $res->return_code, '==', 0, "Checking two OIDs at once" );
103 like($res->output, "/^SNMP OK - 2 1/", "Got two values back" ); 93 like( $res->perf_output, "/ifIndex.2'?=2/", "Got 1st perf data" );
104 like( $res->perf_output, "/ifIndex.2=2/", "Got 1st perf data" ); 94 like( $res->perf_output, "/ifIndex.1'?=1/", "Got 2nd perf data" );
105 like( $res->perf_output, "/ifIndex.1=1/", "Got 2nd perf data" );
106 95
107 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2,1:2 -c 2:2,2:2"); 96 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o ifIndex.2,ifIndex.1 -w 1:2,1:2 -c 2:2,2:2 -P 2c");
108 cmp_ok( $res->return_code, '==', 2, "Checking critical threshold is passed if any one value crosses" ); 97 cmp_ok( $res->return_code, '==', 2, "Checking critical threshold is passed if any one value crosses" );
109 like($res->output, "/^SNMP CRITICAL - 2 *1*/", "Got two values back" ); 98 like( $res->perf_output, "/ifIndex.2'?=2/", "Got 1st perf data" );
110 like( $res->perf_output, "/ifIndex.2=2/", "Got 1st perf data" ); 99 like( $res->perf_output, "/ifIndex.1'?=1/", "Got 2nd perf data" );
111 like( $res->perf_output, "/ifIndex.1=1/", "Got 2nd perf data" );
112 100
113 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w 1:,1: -c 1:,1:"); 101 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w 1:,1: -c 1:,1: -P 2c");
114 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrMemorySize and hrSystemProcesses"); 102 cmp_ok( $res->return_code, '==', 0, "Exit OK when querying hrMemorySize and hrSystemProcesses");
115 like($res->output, '/^SNMP OK - \d+ \d+/', "String contains hrMemorySize and hrSystemProcesses");
116 103
117 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w \@:0 -c \@0"); 104 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w \@:0 -c \@0 -P 2c");
118 cmp_ok( $res->return_code, '==', 0, "Exit OK with inside-range thresholds"); 105 cmp_ok( $res->return_code, '==', 0, "Exit OK with inside-range thresholds");
119 like($res->output, '/^SNMP OK - 1\s.*$/', "String matches SNMP OK and output format");
120 106
121 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoad.3"); 107 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoadInt.3 -P 2c");
122 $res->output =~ m/^SNMP OK - (\d+\.\d{2})\s.*$/; 108 $res->output =~ m/^.*Value: (\d+).*$/;
123 my $lower = $1 - 0.05; 109 my $lower = $1 - 0.05;
124 my $higher = $1 + 0.05; 110 my $higher = $1 + 0.05;
125 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoad.3 -w $lower -c $higher"); 111 # $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o enterprises.ucdavis.laTable.laEntry.laLoadInt.3 -w $lower -c $higher -P 2c");
126 cmp_ok( $res->return_code, '==', 1, "Exit WARNING with fractionnal arguments"); 112 # cmp_ok( $res->return_code, '==', 1, "Exit WARNING with fractional arguments");
127 113
128 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0,host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w ,:0 -c ,:2"); 114 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0,host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w ,:0 -c ,:2 -P 2c");
129 cmp_ok( $res->return_code, '==', 1, "Exit WARNING on 2nd threshold"); 115 cmp_ok( $res->return_code, '==', 1, "Exit WARNING on 2nd threshold");
130 like($res->output, '/^SNMP WARNING - Timeticks:\s\(\d+\)\s+(?:\d+ days?,\s+)?\d+:\d+:\d+\.\d+\s+\*1\*\s.*$/', "First OID returned as string, 2nd checked for thresholds");
131 116
132 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w '' -c ''"); 117 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunIndex.1 -w '' -c '' -P 2c");
133 cmp_ok( $res->return_code, '==', 0, "Empty thresholds doesn't crash"); 118 cmp_ok( $res->return_code, '==', 0, "Empty thresholds doesn't crash");
134 119
135 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,,1 -c ,,2"); 120 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,,1 -c ,,2 -P 2c");
136 cmp_ok( $res->return_code, '==', 0, "Skipping first two thresholds on 2 OID check"); 121 cmp_ok( $res->return_code, '==', 0, "Skipping first two thresholds on 2 OID check");
137 like($res->output, '/^SNMP OK - \d+ \w+ \d+\s.*$/', "Skipping first two thresholds, result printed rather than parsed");
138 122
139 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,, -c ,,"); 123 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o host.hrStorage.hrMemorySize.0,host.hrSystem.hrSystemProcesses.0 -w ,, -c ,, -P 2c");
140 cmp_ok( $res->return_code, '==', 0, "Skipping all thresholds"); 124 cmp_ok( $res->return_code, '==', 0, "Skipping all thresholds");
141 like($res->output, '/^SNMP OK - \d+ \w+ \d+\s.*$/', "Skipping all thresholds, result printed rather than parsed");
142 125
143 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1000000000000: -u '1/100 sec'"); 126 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -c 1000000000000: -u '1/100 sec' -P 2c");
144 cmp_ok( $res->return_code, '==', 2, "Timetick used as a threshold"); 127 cmp_ok( $res->return_code, '==', 2, "Timetick used as a threshold");
145 like($res->output, '/^SNMP CRITICAL - \*\d+\* 1\/100 sec.*$/', "Timetick used as a threshold, parsed as numeric");
146 128
147 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0"); 129 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o system.sysUpTime.0 -P 2c");
148 cmp_ok( $res->return_code, '==', 0, "Timetick used as a string"); 130 cmp_ok( $res->return_code, '==', 0, "Timetick used as a string");
149 like($res->output, '/^SNMP OK - Timeticks:\s\(\d+\)\s+(?:\d+ days?,\s+)?\d+:\d+:\d+\.\d+\s.*$/', "Timetick used as a string, result printed rather than parsed");
150 131
151 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o HOST-RESOURCES-MIB::hrSWRunName.1"); 132 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -C $snmp_community -o HOST-RESOURCES-MIB::hrSWRunName.1 -P 2c");
152 cmp_ok( $res->return_code, '==', 0, "snmp response without datatype"); 133 cmp_ok( $res->return_code, '==', 0, "snmp response without datatype");
153 like( $res->output, '/^SNMP OK - "(systemd|init)" \| $/', "snmp response without datatype" );
154} 134}
155 135
156SKIP: { 136SKIP: {
157 skip "no SNMP user defined", 1 if ( ! $user_snmp ); 137 skip "no SNMP user defined", 1 if ( ! $user_snmp );
158 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -o HOST-RESOURCES-MIB::hrSystemUptime.0 -P 3 -U $user_snmp -L noAuthNoPriv"); 138 $res = NPTest->testCmd( "./check_snmp -H $host_snmp --ignore-mib-parsing-errors -o HOST-RESOURCES-MIB::hrSystemUptime.0 -P 3 -U $user_snmp -L noAuthNoPriv");
159 like( $res->output, '/^SNMP OK - Timeticks:\s\(\d+\)\s+(?:\d+ days?,\s+)?\d+:\d+:\d+\.\d+\s.*$/', "noAuthNoPriv security level works properly" );
160} 139}
161 140
162# These checks need a complete command line. An invalid community is used so 141# These checks need a complete command line. An invalid community is used so
163# the tests can run on hosts w/o snmp host/community in NPTest.cache. Execution will fail anyway 142# the tests can run on hosts w/o snmp host/community in NPTest.cache. Execution will fail anyway
164SKIP: { 143SKIP: {
165 skip "no non responsive host defined", 2 if ( ! $host_nonresponsive ); 144 skip "no non responsive host defined", 2 if ( ! $host_nonresponsive );
166 $res = NPTest->testCmd( "./check_snmp -H $host_nonresponsive --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1:"); 145 $res = NPTest->testCmd( "./check_snmp -H $host_nonresponsive --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1: -P 2c");
167 cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL with non responsive host" ); 146 cmp_ok( $res->return_code, '==', 2, "Exit CRITICAL with non responsive host" );
168 like($res->output, '/Plugin timed out while executing system call/', "String matches timeout problem"); 147 # like($res->output, '/Plugin timed out while executing system call/', "String matches timeout problem");
169} 148}
170 149
171SKIP: { 150SKIP: {
172 skip "no non invalid host defined", 2 if ( ! $hostname_invalid ); 151 skip "no non invalid host defined", 2 if ( ! $hostname_invalid );
173 $res = NPTest->testCmd( "./check_snmp -H $hostname_invalid --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1:"); 152 $res = NPTest->testCmd( "./check_snmp -H $hostname_invalid --ignore-mib-parsing-errors -C np_foobar -o system.sysUpTime.0 -w 1: -c 1: -P 2c");
174 cmp_ok( $res->return_code, '==', 3, "Exit UNKNOWN with non responsive host" ); 153 cmp_ok( $res->return_code, '==', 3, "Exit UNKNOWN with non responsive host" );
175 like($res->output, '/External command error: .*(nosuchhost|Name or service not known|Unknown host).*/s', "String matches invalid host"); 154 like($res->output, '/.*Unknown host.*/s', "String matches invalid host");
176} 155}
diff --git a/plugins/t/check_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/t/check_users.t b/plugins/t/check_users.t
index 21c3e53d..446e0476 100644
--- a/plugins/t/check_users.t
+++ b/plugins/t/check_users.t
@@ -15,8 +15,8 @@ use NPTest;
15use vars qw($tests); 15use vars qw($tests);
16BEGIN {$tests = 12; plan tests => $tests} 16BEGIN {$tests = 12; plan tests => $tests}
17 17
18my $successOutput = '/^USERS OK - [0-9]+ users currently logged in/'; 18my $successOutput = '/[0-9]+ users currently logged in/';
19my $failureOutput = '/^USERS CRITICAL - [0-9]+ users currently logged in/'; 19my $failureOutput = '/[0-9]+ users currently logged in/';
20my $wrongOptionOutput = '/Usage:/'; 20my $wrongOptionOutput = '/Usage:/';
21 21
22my $t; 22my $t;
diff --git a/plugins/tests/check_curl.t b/plugins/tests/check_curl.t
index eaa9f518..52c5ad1c 100755
--- a/plugins/tests/check_curl.t
+++ b/plugins/tests/check_curl.t
@@ -15,6 +15,7 @@
15# Email Address []:devel@monitoring-plugins.org 15# Email Address []:devel@monitoring-plugins.org
16 16
17use strict; 17use strict;
18use warnings;
18use Test::More; 19use Test::More;
19use NPTest; 20use NPTest;
20use FindBin qw($Bin); 21use FindBin qw($Bin);
@@ -245,21 +246,21 @@ SKIP: {
245 246
246 $result = NPTest->testCmd( "$command -p $port_https -S -C 14" ); 247 $result = NPTest->testCmd( "$command -p $port_https -S -C 14" );
247 is( $result->return_code, 0, "$command -p $port_https -S -C 14" ); 248 is( $result->return_code, 0, "$command -p $port_https -S -C 14" );
248 is( $result->output, "OK - Certificate 'Monitoring Plugins' will expire on $expiry.", "output ok" ); 249 like( $result->output, '/.*Certificate \'Monitoring Plugins\' will expire on ' . quotemeta($expiry) . '.*/', "output ok" );
249 250
250 $result = NPTest->testCmd( "$command -p $port_https -S -C 14000" ); 251 $result = NPTest->testCmd( "$command -p $port_https -S -C 14000" );
251 is( $result->return_code, 1, "$command -p $port_https -S -C 14000" ); 252 is( $result->return_code, 1, "$command -p $port_https -S -C 14000" );
252 like( $result->output, '/WARNING - Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\)./', "output ok" ); 253 like( $result->output, '/.*Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\).*/', "output ok" );
253 254
254 # Expired cert tests 255 # Expired cert tests
255 $result = NPTest->testCmd( "$command -p $port_https -S -C 13960,14000" ); 256 $result = NPTest->testCmd( "$command -p $port_https -S -C 13960,14000" );
256 is( $result->return_code, 2, "$command -p $port_https -S -C 13960,14000" ); 257 is( $result->return_code, 2, "$command -p $port_https -S -C 13960,14000" );
257 like( $result->output, '/CRITICAL - Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\)./', "output ok" ); 258 like( $result->output, '/.*Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\).*/', "output ok" );
258 259
259 $result = NPTest->testCmd( "$command -p $port_https_expired -S -C 7" ); 260 $result = NPTest->testCmd( "$command -p $port_https_expired -S -C 7" );
260 is( $result->return_code, 2, "$command -p $port_https_expired -S -C 7" ); 261 is( $result->return_code, 2, "$command -p $port_https_expired -S -C 7" );
261 is( $result->output, 262 like( $result->output,
262 'CRITICAL - Certificate \'Monitoring Plugins\' expired on Wed Jan 2 12:00:00 2008 +0000.', 263 '/.*Certificate \'Monitoring Plugins\' expired on Wed Jan\s+2 12:00:00 2008 \+0000.*/',
263 "output ok" ); 264 "output ok" );
264 265
265} 266}
@@ -274,19 +275,19 @@ SKIP: {
274 $cmd = "./$plugin -H $virtual_host -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host:$port_http\$"; 275 $cmd = "./$plugin -H $virtual_host -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host:$port_http\$";
275 $result = NPTest->testCmd( $cmd ); 276 $result = NPTest->testCmd( $cmd );
276 is( $result->return_code, 0, $cmd); 277 is( $result->return_code, 0, $cmd);
277 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 278 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
278 279
279 # http with virtual port (!= 80) 280 # http with virtual port (!= 80)
280 $cmd = "./$plugin -H $virtual_host:$virtual_port -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host:$virtual_port\$"; 281 $cmd = "./$plugin -H $virtual_host:$virtual_port -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host:$virtual_port\$";
281 $result = NPTest->testCmd( $cmd ); 282 $result = NPTest->testCmd( $cmd );
282 is( $result->return_code, 0, $cmd); 283 is( $result->return_code, 0, $cmd);
283 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 284 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
284 285
285 # http with virtual port (80) 286 # http with virtual port (80)
286 $cmd = "./$plugin -H $virtual_host:80 -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host\$"; 287 $cmd = "./$plugin -H $virtual_host:80 -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host\$";
287 $result = NPTest->testCmd( $cmd ); 288 $result = NPTest->testCmd( $cmd );
288 is( $result->return_code, 0, $cmd); 289 is( $result->return_code, 0, $cmd);
289 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 290 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
290} 291}
291 292
292# and the same for SSL 293# and the same for SSL
@@ -296,19 +297,19 @@ SKIP: {
296 $cmd = "./$plugin -H $virtual_host -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host:$port_https\$"; 297 $cmd = "./$plugin -H $virtual_host -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host:$port_https\$";
297 $result = NPTest->testCmd( $cmd ); 298 $result = NPTest->testCmd( $cmd );
298 is( $result->return_code, 0, $cmd); 299 is( $result->return_code, 0, $cmd);
299 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 300 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
300 301
301 # https with virtual port (!= 443) 302 # https with virtual port (!= 443)
302 $cmd = "./$plugin -H $virtual_host:$virtual_port -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host:$virtual_port\$"; 303 $cmd = "./$plugin -H $virtual_host:$virtual_port -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host:$virtual_port\$";
303 $result = NPTest->testCmd( $cmd ); 304 $result = NPTest->testCmd( $cmd );
304 is( $result->return_code, 0, $cmd); 305 is( $result->return_code, 0, $cmd);
305 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 306 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
306 307
307 # https with virtual port (443) 308 # https with virtual port (443)
308 $cmd = "./$plugin -H $virtual_host:443 -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host\$"; 309 $cmd = "./$plugin -H $virtual_host:443 -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host\$";
309 $result = NPTest->testCmd( $cmd ); 310 $result = NPTest->testCmd( $cmd );
310 is( $result->return_code, 0, $cmd); 311 is( $result->return_code, 0, $cmd);
311 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 312 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
312} 313}
313 314
314 315
@@ -321,165 +322,165 @@ sub run_common_tests {
321 322
322 $result = NPTest->testCmd( "$command -u /file/root" ); 323 $result = NPTest->testCmd( "$command -u /file/root" );
323 is( $result->return_code, 0, "/file/root"); 324 is( $result->return_code, 0, "/file/root");
324 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second/', "Output correct" ); 325 like( $result->output, '/.*HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second.*/', "Output correct" );
325 326
326 $result = NPTest->testCmd( "$command -u /file/root -s Root" ); 327 $result = NPTest->testCmd( "$command -u /file/root -s Root" );
327 is( $result->return_code, 0, "/file/root search for string"); 328 is( $result->return_code, 0, "/file/root search for string");
328 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second/', "Output correct" ); 329 like( $result->output, '/.*HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second.*/', "Output correct" );
329 330
330 $result = NPTest->testCmd( "$command -u /file/root -s NonRoot" ); 331 $result = NPTest->testCmd( "$command -u /file/root -s NonRoot" );
331 is( $result->return_code, 2, "Missing string check"); 332 is( $result->return_code, 2, "Missing string check");
332 like( $result->output, qr%^HTTP CRITICAL: HTTP/1\.1 200 OK - string 'NonRoot' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location"); 333 like( $result->output, qr%string 'NonRoot' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location");
333 334
334 $result = NPTest->testCmd( "$command -u /file/root -s NonRootWithOver30charsAndMoreFunThanAWetFish" ); 335 $result = NPTest->testCmd( "$command -u /file/root -s NonRootWithOver30charsAndMoreFunThanAWetFish" );
335 is( $result->return_code, 2, "Missing string check"); 336 is( $result->return_code, 2, "Missing string check");
336 like( $result->output, qr%HTTP CRITICAL: HTTP/1\.1 200 OK - string 'NonRootWithOver30charsAndM...' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location"); 337 like( $result->output, qr%string 'NonRootWithOver30charsAndM...' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location");
337 338
338 $result = NPTest->testCmd( "$command -u /header_check -d foo" ); 339 $result = NPTest->testCmd( "$command -u /header_check -d foo" );
339 is( $result->return_code, 0, "header_check search for string"); 340 is( $result->return_code, 0, "header_check search for string");
340 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 96 bytes in [\d\.]+ second/', "Output correct" ); 341 like( $result->output, '/.*HTTP/1.1 200 OK - 96 bytes in [\d\.]+ second.*/', "Output correct" );
341 342
342 $result = NPTest->testCmd( "$command -u /header_check -d bar" ); 343 $result = NPTest->testCmd( "$command -u /header_check -d bar" );
343 is( $result->return_code, 2, "Missing header string check"); 344 is( $result->return_code, 2, "Missing header string check");
344 like( $result->output, qr%^HTTP CRITICAL: HTTP/1\.1 200 OK - header 'bar' not found on 'https?://127\.0\.0\.1:\d+/header_check'%, "Shows search string and location"); 345 like( $result->output, qr%header 'bar' not found on 'https?://127\.0\.0\.1:\d+/header_check'%, "Shows search string and location");
345 346
346 $result = NPTest->testCmd( "$command -u /header_broken_check" ); 347 $result = NPTest->testCmd( "$command -u /header_broken_check" );
347 is( $result->return_code, 0, "header_check search for string"); 348 is( $result->return_code, 0, "header_check search for string");
348 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 138 bytes in [\d\.]+ second/', "Output correct" ); 349 like( $result->output, '/.*HTTP/1.1 200 OK - 138 bytes in [\d\.]+ second.*/', "Output correct" );
349 350
350 my $cmd; 351 my $cmd;
351 $cmd = "$command -u /slow"; 352 $cmd = "$command -u /slow";
352 $result = NPTest->testCmd( $cmd ); 353 $result = NPTest->testCmd( $cmd );
353 is( $result->return_code, 0, "$cmd"); 354 is( $result->return_code, 0, "$cmd");
354 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 355 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
355 $result->output =~ /in ([\d\.]+) second/; 356 $result->output =~ /in ([\d\.]+) second/;
356 cmp_ok( $1, ">", 1, "Time is > 1 second" ); 357 cmp_ok( $1, ">", 1, "Time is > 1 second" );
357 358
358 $cmd = "$command -u /statuscode/200"; 359 $cmd = "$command -u /statuscode/200";
359 $result = NPTest->testCmd( $cmd ); 360 $result = NPTest->testCmd( $cmd );
360 is( $result->return_code, 0, $cmd); 361 is( $result->return_code, 0, $cmd);
361 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 362 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
362 363
363 $cmd = "$command -u /statuscode/200 -e 200"; 364 $cmd = "$command -u /statuscode/200 -e 200";
364 $result = NPTest->testCmd( $cmd ); 365 $result = NPTest->testCmd( $cmd );
365 is( $result->return_code, 0, $cmd); 366 is( $result->return_code, 0, $cmd);
366 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - Status line output matched "200" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 367 like( $result->output, '/.*Status line output matched "200".*/', "Output correct: ".$result->output );
367 368
368 $cmd = "$command -u /statuscode/201"; 369 $cmd = "$command -u /statuscode/201";
369 $result = NPTest->testCmd( $cmd ); 370 $result = NPTest->testCmd( $cmd );
370 is( $result->return_code, 0, $cmd); 371 is( $result->return_code, 0, $cmd);
371 like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - \d+ bytes in [\d\.]+ second /', "Output correct: ".$result->output ); 372 like( $result->output, '/.*HTTP/1.1 201 Created - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
372 373
373 $cmd = "$command -u /statuscode/201 -e 201"; 374 $cmd = "$command -u /statuscode/201 -e 201";
374 $result = NPTest->testCmd( $cmd ); 375 $result = NPTest->testCmd( $cmd );
375 is( $result->return_code, 0, $cmd); 376 is( $result->return_code, 0, $cmd);
376 like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - Status line output matched "201" - \d+ bytes in [\d\.]+ second /', "Output correct: ".$result->output ); 377 like( $result->output, '/.*Status line output matched "201".*/', "Output correct: ".$result->output );
377 378
378 $cmd = "$command -u /statuscode/201 -e 200"; 379 $cmd = "$command -u /statuscode/201 -e 200";
379 $result = NPTest->testCmd( $cmd ); 380 $result = NPTest->testCmd( $cmd );
380 is( $result->return_code, 2, $cmd); 381 is( $result->return_code, 2, $cmd);
381 like( $result->output, '/^HTTP CRITICAL - Invalid HTTP response received from host on port \d+: HTTP/1.1 201 Created/', "Output correct: ".$result->output ); 382 like( $result->output, '/.*Invalid HTTP response received from host on port \d+: HTTP/1.1 201 Created.*/', "Output correct: ".$result->output );
382 383
383 $cmd = "$command -u /statuscode/200 -e 200,201,202"; 384 $cmd = "$command -u /statuscode/200 -e 200,201,202";
384 $result = NPTest->testCmd( $cmd ); 385 $result = NPTest->testCmd( $cmd );
385 is( $result->return_code, 0, $cmd); 386 is( $result->return_code, 0, $cmd);
386 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - Status line output matched "200,201,202" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 387 like( $result->output, '/.*Status line output matched "200,201,202".*/', "Output correct: ".$result->output );
387 388
388 $cmd = "$command -u /statuscode/201 -e 200,201,202"; 389 $cmd = "$command -u /statuscode/201 -e 200,201,202";
389 $result = NPTest->testCmd( $cmd ); 390 $result = NPTest->testCmd( $cmd );
390 is( $result->return_code, 0, $cmd); 391 is( $result->return_code, 0, $cmd);
391 like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - Status line output matched "200,201,202" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 392 like( $result->output, '/.*Status line output matched "200,201,202".*/', "Output correct: ".$result->output );
392 393
393 $cmd = "$command -u /statuscode/203 -e 200,201,202"; 394 $cmd = "$command -u /statuscode/203 -e 200,201,202";
394 $result = NPTest->testCmd( $cmd ); 395 $result = NPTest->testCmd( $cmd );
395 is( $result->return_code, 2, $cmd); 396 is( $result->return_code, 2, $cmd);
396 like( $result->output, '/^HTTP CRITICAL - Invalid HTTP response received from host on port (\d+): HTTP/1.1 203 Non-Authoritative Information/', "Output correct: ".$result->output ); 397 like( $result->output, '/.*Invalid HTTP response received from host on port (\d+): HTTP/1.1 203 Non-Authoritative Information.*/', "Output correct: ".$result->output );
397 398
398 $cmd = "$command -j HEAD -u /method"; 399 $cmd = "$command -j HEAD -u /method";
399 $result = NPTest->testCmd( $cmd ); 400 $result = NPTest->testCmd( $cmd );
400 is( $result->return_code, 0, $cmd); 401 is( $result->return_code, 0, $cmd);
401 like( $result->output, '/^HTTP OK: HTTP/1.1 200 HEAD - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 402 like( $result->output, '/.*HTTP/1.1 200 HEAD - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
402 403
403 $cmd = "$command -j POST -u /method"; 404 $cmd = "$command -j POST -u /method";
404 $result = NPTest->testCmd( $cmd ); 405 $result = NPTest->testCmd( $cmd );
405 is( $result->return_code, 0, $cmd); 406 is( $result->return_code, 0, $cmd);
406 like( $result->output, '/^HTTP OK: HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 407 like( $result->output, '/.*HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
407 408
408 $cmd = "$command -j GET -u /method"; 409 $cmd = "$command -j GET -u /method";
409 $result = NPTest->testCmd( $cmd ); 410 $result = NPTest->testCmd( $cmd );
410 is( $result->return_code, 0, $cmd); 411 is( $result->return_code, 0, $cmd);
411 like( $result->output, '/^HTTP OK: HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 412 like( $result->output, '/.*HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
412 413
413 $cmd = "$command -u /method"; 414 $cmd = "$command -u /method";
414 $result = NPTest->testCmd( $cmd ); 415 $result = NPTest->testCmd( $cmd );
415 is( $result->return_code, 0, $cmd); 416 is( $result->return_code, 0, $cmd);
416 like( $result->output, '/^HTTP OK: HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 417 like( $result->output, '/.*HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
417 418
418 $cmd = "$command -P foo -u /method"; 419 $cmd = "$command -P foo -u /method";
419 $result = NPTest->testCmd( $cmd ); 420 $result = NPTest->testCmd( $cmd );
420 is( $result->return_code, 0, $cmd); 421 is( $result->return_code, 0, $cmd);
421 like( $result->output, '/^HTTP OK: HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 422 like( $result->output, '/.*HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
422 423
423 $cmd = "$command -j DELETE -u /method"; 424 $cmd = "$command -j DELETE -u /method";
424 $result = NPTest->testCmd( $cmd ); 425 $result = NPTest->testCmd( $cmd );
425 is( $result->return_code, 1, $cmd); 426 is( $result->return_code, 1, $cmd);
426 like( $result->output, '/^HTTP WARNING: HTTP/1.1 405 Method Not Allowed/', "Output correct: ".$result->output ); 427 like( $result->output, '/.*HTTP/1.1 405 Method Not Allowed.*/', "Output correct: ".$result->output );
427 428
428 $cmd = "$command -j foo -u /method"; 429 $cmd = "$command -j foo -u /method";
429 $result = NPTest->testCmd( $cmd ); 430 $result = NPTest->testCmd( $cmd );
430 is( $result->return_code, 2, $cmd); 431 is( $result->return_code, 2, $cmd);
431 like( $result->output, '/^HTTP CRITICAL: HTTP/1.1 501 Not Implemented/', "Output correct: ".$result->output ); 432 like( $result->output, '/.*HTTP/1.1 501 Not Implemented.*/', "Output correct: ".$result->output );
432 433
433 $cmd = "$command -P stufftoinclude -u /postdata -s POST:stufftoinclude"; 434 $cmd = "$command -P stufftoinclude -u /postdata -s POST:stufftoinclude";
434 $result = NPTest->testCmd( $cmd ); 435 $result = NPTest->testCmd( $cmd );
435 is( $result->return_code, 0, $cmd); 436 is( $result->return_code, 0, $cmd);
436 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 437 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
437 438
438 $cmd = "$command -j PUT -P stufftoinclude -u /postdata -s PUT:stufftoinclude"; 439 $cmd = "$command -j PUT -P stufftoinclude -u /postdata -s PUT:stufftoinclude";
439 $result = NPTest->testCmd( $cmd ); 440 $result = NPTest->testCmd( $cmd );
440 is( $result->return_code, 0, $cmd); 441 is( $result->return_code, 0, $cmd);
441 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 442 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
442 443
443 # To confirm that the free doesn't segfault 444 # To confirm that the free doesn't segfault
444 $cmd = "$command -P stufftoinclude -j PUT -u /postdata -s PUT:stufftoinclude"; 445 $cmd = "$command -P stufftoinclude -j PUT -u /postdata -s PUT:stufftoinclude";
445 $result = NPTest->testCmd( $cmd ); 446 $result = NPTest->testCmd( $cmd );
446 is( $result->return_code, 0, $cmd); 447 is( $result->return_code, 0, $cmd);
447 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 448 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
448 449
449 $cmd = "$command -u /redirect"; 450 $cmd = "$command -u /redirect";
450 $result = NPTest->testCmd( $cmd ); 451 $result = NPTest->testCmd( $cmd );
451 is( $result->return_code, 0, $cmd); 452 is( $result->return_code, 0, $cmd);
452 like( $result->output, '/^HTTP OK: HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 453 like( $result->output, '/.*HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
453 454
454 $cmd = "$command -f follow -u /redirect"; 455 $cmd = "$command -f follow -u /redirect";
455 $result = NPTest->testCmd( $cmd ); 456 $result = NPTest->testCmd( $cmd );
456 is( $result->return_code, 0, $cmd); 457 is( $result->return_code, 0, $cmd);
457 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 458 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
458 459
459 $cmd = "$command -u /redirect -k 'follow: me'"; 460 $cmd = "$command -u /redirect -k 'follow: me'";
460 $result = NPTest->testCmd( $cmd ); 461 $result = NPTest->testCmd( $cmd );
461 is( $result->return_code, 0, $cmd); 462 is( $result->return_code, 0, $cmd);
462 like( $result->output, '/^HTTP OK: HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 463 like( $result->output, '/.*HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
463 464
464 $cmd = "$command -f follow -u /redirect -k 'follow: me'"; 465 $cmd = "$command -f follow -u /redirect -k 'follow: me'";
465 $result = NPTest->testCmd( $cmd ); 466 $result = NPTest->testCmd( $cmd );
466 is( $result->return_code, 0, $cmd); 467 is( $result->return_code, 0, $cmd);
467 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 468 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
468 469
469 $cmd = "$command -f sticky -u /redirect -k 'follow: me'"; 470 $cmd = "$command -f sticky -u /redirect -k 'follow: me'";
470 $result = NPTest->testCmd( $cmd ); 471 $result = NPTest->testCmd( $cmd );
471 is( $result->return_code, 0, $cmd); 472 is( $result->return_code, 0, $cmd);
472 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 473 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
473 474
474 $cmd = "$command -f stickyport -u /redirect -k 'follow: me'"; 475 $cmd = "$command -f stickyport -u /redirect -k 'follow: me'";
475 $result = NPTest->testCmd( $cmd ); 476 $result = NPTest->testCmd( $cmd );
476 is( $result->return_code, 0, $cmd); 477 is( $result->return_code, 0, $cmd);
477 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 478 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
478 479
479 $cmd = "$command -f follow -u /redirect_rel -s redirected"; 480 $cmd = "$command -f follow -u /redirect_rel -s redirected";
480 $result = NPTest->testCmd( $cmd ); 481 $result = NPTest->testCmd( $cmd );
481 is( $result->return_code, 0, $cmd); 482 is( $result->return_code, 0, $cmd);
482 like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output ); 483 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
483 484
484 # These tests may block 485 # These tests may block
485 # stickyport - on full urlS port is set back to 80 otherwise 486 # stickyport - on full urlS port is set back to 80 otherwise
diff --git a/plugins/tests/check_snmp.t b/plugins/tests/check_snmp.t
index bfe42e16..26d67898 100755
--- a/plugins/tests/check_snmp.t
+++ b/plugins/tests/check_snmp.t
@@ -4,12 +4,13 @@
4# 4#
5 5
6use strict; 6use strict;
7use warnings;
7use Test::More; 8use Test::More;
8use NPTest; 9use NPTest;
9use FindBin qw($Bin); 10use FindBin qw($Bin);
10use POSIX qw/strftime/; 11use POSIX qw/strftime/;
11 12
12my $tests = 81; 13my $tests = 75;
13# Check that all dependent modules are available 14# Check that all dependent modules are available
14eval { 15eval {
15 require NetSNMP::OID; 16 require NetSNMP::OID;
@@ -76,49 +77,36 @@ my $res;
76 77
77$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.0"); 78$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.0");
78cmp_ok( $res->return_code, '==', 0, "Exit OK when querying a multi-line string" ); 79cmp_ok( $res->return_code, '==', 0, "Exit OK when querying a multi-line string" );
79like($res->output, '/^SNMP OK - /', "String contains SNMP OK"); 80like($res->output, '/.*Cisco Internetwork Operating System Software.*/m', "String contains all lines");
80like($res->output, '/'.quotemeta('SNMP OK - Cisco Internetwork Operating System Software |
81.1.3.6.1.4.1.8072.3.2.67.0:
82"Cisco Internetwork Operating System Software
83IOS (tm) Catalyst 4000 \"L3\" Switch Software (cat4000-I9K91S-M), Version
8412.2(20)EWA, RELEASE SOFTWARE (fc1)
85Technical Support: http://www.cisco.com/techsupport
86Copyright (c) 1986-2004 by cisco Systems, Inc.
87"').'/m', "String contains all lines");
88 81
89# sysContact.0 is "Alice" (from our snmpd.conf) 82# sysContact.0 is "Alice" (from our snmpd.conf)
90$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.0 -o sysContact.0 -o .1.3.6.1.4.1.8072.3.2.67.1"); 83$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.0 -o sysContact.0 -o .1.3.6.1.4.1.8072.3.2.67.1");
91cmp_ok( $res->return_code, '==', 0, "Exit OK when querying multi-line OIDs" ); 84cmp_ok( $res->return_code, '==', 0, "Exit OK when querying multi-line OIDs" );
92like($res->output, '/^SNMP OK - /', "String contains SNMP OK"); 85# like($res->output, '/^SNMP OK - /', "String contains SNMP OK");
93like($res->output, '/'.quotemeta('SNMP OK - Cisco Internetwork Operating System Software ').'"?Alice"?'.quotemeta(' Kisco Outernetwork Oserating Gystem Totware | 86like($res->output, '/.*Cisco Internetwork Operating System Software.*/m', "String contains all lines with multiple OIDs");
94.1.3.6.1.4.1.8072.3.2.67.0: 87like($res->output, '/.*Alice.*/m', "String contains all lines with multiple OIDs");
95"Cisco Internetwork Operating System Software 88like($res->output, '/.*Kisco Outernetwork Oserating Gystem Totware.*/m', "String contains all lines with multiple OIDs");
96IOS (tm) Catalyst 4000 \"L3\" Switch Software (cat4000-I9K91S-M), Version
9712.2(20)EWA, RELEASE SOFTWARE (fc1)
98Technical Support: http://www.cisco.com/techsupport
99Copyright (c) 1986-2004 by cisco Systems, Inc.
100"
101.1.3.6.1.4.1.8072.3.2.67.1:
102"Kisco Outernetwork Oserating Gystem Totware
103Copyleft (c) 2400-2689 by kisco Systrems, Inc."').'/m', "String contains all lines with multiple OIDs");
104 89
105$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.2"); 90$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.2");
106like($res->output, '/'.quotemeta('SNMP OK - This should not confuse check_snmp \"parser\" | 91cmp_ok( $res->return_code, '==', 0, "Exit OK when querying multi-line OIDs" );
107.1.3.6.1.4.1.8072.3.2.67.2: 92# like($res->output, '/'.quotemeta('This should not confuse check_snmp \"parser\" |
108"This should not confuse check_snmp \"parser\" 93# .1.3.6.1.4.1.8072.3.2.67.2:
109into thinking there is no 2nd line"').'/m', "Attempt to confuse parser No.1"); 94# "This should not confuse check_snmp \"parser\"
95# into thinking there is no 2nd line"').'/m', "Attempt to confuse parser No.1");
110 96
111$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.3"); 97$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.3");
112like($res->output, '/'.quotemeta('SNMP OK - It\'s getting even harder if the line | 98cmp_ok( $res->return_code, '==', 0, "Exit OK when querying multi-line OIDs" );
113.1.3.6.1.4.1.8072.3.2.67.3: 99# like($res->output, '/'.quotemeta('It\'s getting even harder if the line |
114"It\'s getting even harder if the line 100# .1.3.6.1.4.1.8072.3.2.67.3:
115ends with with this: C:\\\\"').'/m', "Attempt to confuse parser No.2"); 101# "It\'s getting even harder if the line
102# ends with with this: C:\\\\"').'/m', "Attempt to confuse parser No.2");
116 103
117$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.4"); 104$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.4");
118like($res->output, '/'.quotemeta('SNMP OK - And now have fun with with this: \"C:\\\\\" | 105cmp_ok( $res->return_code, '==', 0, "Exit OK when querying multi-line OIDs" );
119.1.3.6.1.4.1.8072.3.2.67.4: 106# like($res->output, '/'.quotemeta('And now have fun with with this: \"C:\\\\\" |
120"And now have fun with with this: \"C:\\\\\" 107# .1.3.6.1.4.1.8072.3.2.67.4:
121because we\'re not done yet!"').'/m', "Attempt to confuse parser No.3"); 108# "And now have fun with with this: \"C:\\\\\"
109# because we\'re not done yet!"').'/m', "Attempt to confuse parser No.3");
122 110
123system("rm -f ".$ENV{'MP_STATE_PATH'}."/*/check_snmp/*"); 111system("rm -f ".$ENV{'MP_STATE_PATH'}."/*/check_snmp/*");
124 112
@@ -131,156 +119,159 @@ SKIP: {
131 my $ts = time(); 119 my $ts = time();
132 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" ); 120 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" );
133 is($res->return_code, 0, "Returns OK"); 121 is($res->return_code, 0, "Returns OK");
134 is($res->output, "No previous data to calculate rate - assume okay"); 122 like($res->output, "/.*No previous data to calculate rate - assume okay.*/");
135 123
136 # test rate 1 second later 124 # test rate 1 second later
137 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" ); 125 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" );
138 is($res->return_code, 1, "WARNING - due to going above rate calculation" ); 126 is($res->return_code, 1, "WARNING - due to going above rate calculation" );
139 is($res->output, "SNMP RATE WARNING - *666* | iso.3.6.1.4.1.8072.3.2.67.10=666;600 "); 127 like($res->output, "/.*=666.*/");
140 128
141 # test rate with same time 129 # test rate with same time
142 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" ); 130 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -w 600" );
143 is($res->return_code, 3, "UNKNOWN - basically the divide by zero error" ); 131 is($res->return_code, 3, "UNKNOWN - basically the divide by zero error" );
144 is($res->output, "Time duration between plugin calls is invalid"); 132 like($res->output, "/.*Time duration between plugin calls is invalid.*/");
145 133
146 134
147 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" ); 135 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" );
148 is($res->return_code, 0, "OK for first call" ); 136 is($res->return_code, 0, "OK for first call" );
149 is($res->output, "No previous data to calculate rate - assume okay" ); 137 like($res->output, "/.*No previous data to calculate rate - assume okay.*/" );
150 138
151 # test rate 1 second later 139 # test rate 1 second later
152 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" ); 140 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" );
153 is($res->return_code, 0, "OK as no thresholds" ); 141 is($res->return_code, 0, "OK as no thresholds" );
154 is($res->output, "SNMP RATE OK - inoctets 666 | inoctets=666 ", "Check label"); 142 like($res->output, "/.*inoctets.*=666.*/m", "Check label");
155 143
156 # test rate 3 seconds later 144 # test rate 3 seconds later
157 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+3))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" ); 145 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+3))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets" );
158 is($res->return_code, 0, "OK as no thresholds" ); 146 is($res->return_code, 0, "OK as no thresholds" );
159 is($res->output, "SNMP RATE OK - inoctets 333 | inoctets=333 ", "Check rate decreases due to longer interval"); 147 like($res->output, "/.*inoctets.*333.*/", "Check rate decreases due to longer interval");
160 148
161 149
162 # label performance data check 150 # label performance data check
163 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l test" ); 151 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l test" );
164 is($res->return_code, 0, "OK as no thresholds" ); 152 is($res->return_code, 0, "OK as no thresholds" );
165 is($res->output, "SNMP OK - test 67996 | test=67996c ", "Check label"); 153 like($res->output, "/.*test.?=67996c/", "Check label");
166 154
167 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l \"test'test\"" ); 155 # following test is deactivated since it was not valid due to the guidelines (no single quote in label allowed)
168 is($res->return_code, 0, "OK as no thresholds" ); 156 # $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l \"test'test\"" );
169 is($res->output, "SNMP OK - test'test 68662 | \"test'test\"=68662c ", "Check label"); 157 # is($res->return_code, 0, "OK as no thresholds" );
158 # is($res->output, "test'test 68662 | \"test'test\"=68662c ", "Check label");
170 159
171 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l 'test\"test'" ); 160 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l 'test\"test'" );
172 is($res->return_code, 0, "OK as no thresholds" ); 161 is($res->return_code, 0, "OK as no thresholds" );
173 is($res->output, "SNMP OK - test\"test 69328 | 'test\"test'=69328c ", "Check label"); 162 like($res->output, "/.*'test\"test'=68662c.*/", "Check label");
174 163
175 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l test -O" ); 164 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l test -O" );
176 is($res->return_code, 0, "OK as no thresholds" ); 165 is($res->return_code, 0, "OK as no thresholds" );
177 is($res->output, "SNMP OK - test 69994 | iso.3.6.1.4.1.8072.3.2.67.10=69994c ", "Check label"); 166 like($res->output, "/.*.67.10.?=69328c.*/", "Check label");
178 167
179 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10" ); 168 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10" );
180 is($res->return_code, 0, "OK as no thresholds" ); 169 is($res->return_code, 0, "OK as no thresholds" );
181 is($res->output, "SNMP OK - 70660 | iso.3.6.1.4.1.8072.3.2.67.10=70660c ", "Check label"); 170 like($res->output, "/.*8072.3.2.67.10.?=69994c.*/", "Check label");
182 171
183 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l 'test test'" ); 172 $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 -l 'test test'" );
184 is($res->return_code, 0, "OK as no thresholds" ); 173 is($res->return_code, 0, "OK as no thresholds" );
185 is($res->output, "SNMP OK - test test 71326 | 'test test'=71326c ", "Check label"); 174 like($res->output, "/.*'test test'=70660c/", "Check label");
186 175
187 176
188 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets_per_minute --rate-multiplier=60" ); 177 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets_per_minute --rate-multiplier=60" );
189 is($res->return_code, 0, "OK for first call" ); 178 is($res->return_code, 0, "OK for first call" );
190 is($res->output, "No previous data to calculate rate - assume okay" ); 179 like($res->output, "/.*No previous data to calculate rate - assume okay.*/" );
191 180
192 # test 1 second later 181 # test 1 second later
193 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets_per_minute --rate-multiplier=60" ); 182 $res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10 --rate -l inoctets_per_minute --rate-multiplier=60" );
194 is($res->return_code, 0, "OK as no thresholds" ); 183 is($res->return_code, 0, "OK as no thresholds" );
195 is($res->output, "SNMP RATE OK - inoctets_per_minute 39960 | inoctets_per_minute=39960 ", "Checking multiplier"); 184 like($res->output, "/.*inoctets_per_minute.*=39960/", "Checking multiplier");
196}; 185};
197 186
198 187
199 188
200$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 -s '\"stringtests\"'" ); 189$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 -s 'stringtests'" );
201is($res->return_code, 0, "OK as string matches" ); 190is($res->return_code, 0, "OK as string matches" );
202is($res->output, 'SNMP OK - "stringtests" | ', "Good string match" ); 191like($res->output, '/.*stringtests.*/', "Good string match" );
203 192
204$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 -s ring" ); 193$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 -s ring" );
205is($res->return_code, 2, "CRITICAL as string doesn't match (though is a substring)" ); 194is($res->return_code, 2, "CRITICAL as string doesn't match (though is a substring)" );
206is($res->output, 'SNMP CRITICAL - *"stringtests"* | ', "Failed string match" ); 195like($res->output, '/.*stringtests.*/', "Failed string match" );
207 196
208$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 --invert-search -s '\"stringtests\"'" ); 197$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 --invert-search -s 'stringtests'" );
209is($res->return_code, 2, "CRITICAL as string matches but inverted" ); 198is($res->return_code, 2, "CRITICAL as string matches but inverted" );
210is($res->output, 'SNMP CRITICAL - *"stringtests"* | ', "Inverted string match" ); 199like($res->output, '/.*"stringtests".*/', "Inverted string match" );
211 200
212$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 --invert-search -s ring" ); 201$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.11 --invert-search -s ring" );
213is($res->return_code, 0, "OK as string doesn't match but inverted" ); 202is($res->return_code, 0, "OK as string doesn't match but inverted" );
214is($res->output, 'SNMP OK - "stringtests" | ', "OK as inverted string no match" ); 203like($res->output, '/.*"stringtests".*/', "OK as inverted string no match" );
215 204
216$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.12 -w 4:5" ); 205$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.12 -w 4:5" );
217is($res->return_code, 1, "Numeric in string test" ); 206# a string is a string and not a number
218is($res->output, 'SNMP WARNING - *3.5* | iso.3.6.1.4.1.8072.3.2.67.12=3.5;4:5 ', "WARNING threshold checks for string masquerading as number" ); 207is($res->return_code, 0, "Numeric in string test" );
208like($res->output, '/.*3.5.*| iso.3.6.1.4.1.8072.3.2.67.12=3.5;4:5/', "WARNING threshold checks for string masquerading as number" );
219 209
220$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.13" ); 210$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.13" );
221is($res->return_code, 0, "Not really numeric test" ); 211is($res->return_code, 0, "Not really numeric test" );
222is($res->output, 'SNMP OK - "87.4startswithnumberbutshouldbestring" | ', "Check string with numeric start is still string" ); 212like($res->output, '/.*"87.4startswithnumberbutshouldbestring".*/', "Check string with numeric start is still string" );
223 213
224$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.14" ); 214$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.14" );
225is($res->return_code, 0, "Not really numeric test (trying best to fool it)" ); 215is($res->return_code, 0, "Not really numeric test (trying best to fool it)" );
226is($res->output, 'SNMP OK - "555\"I said\"" | ', "Check string with a double quote following is still a string (looks like the perl routine will always escape though)" ); 216like($res->output, '/.*\'555"I said"\'.*/', "Check string with a double quote following is still a string (looks like the perl routine will always escape though)" );
227 217
228$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.15 -r 'CUSTOM CHECK OK'" ); 218$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.15 -r 'CUSTOM CHECK OK'" );
229is($res->return_code, 0, "String check should check whole string, not a parsed number" ); 219is($res->return_code, 0, "String check should check whole string, not a parsed number" );
230is($res->output, 'SNMP OK - "CUSTOM CHECK OK: foo is 12345" | ', "String check with numbers returns whole string"); 220like($res->output, '/.*CUSTOM CHECK OK: foo is 12345.*/', "String check with numbers returns whole string");
231 221
232$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" ); 222$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" );
233is($res->return_code, 0, "Negative integer check OK" ); 223is($res->return_code, 0, "Negative integer check OK" );
234is($res->output, 'SNMP OK - -2 | iso.3.6.1.4.1.8072.3.2.67.16=-2;-2:;-3: ', "Negative integer check OK output" ); 224like($res->output, '/.*-2.*| iso.3.6.1.4.1.8072.3.2.67.16=-2;-2:;-3:/', "Negative integer check OK output" );
235 225
236$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" ); 226$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" );
237is($res->return_code, 1, "Negative integer check WARNING" ); 227is($res->return_code, 1, "Negative integer check WARNING" );
238is($res->output, 'SNMP WARNING - *-3* | iso.3.6.1.4.1.8072.3.2.67.16=-3;-2:;-3: ', "Negative integer check WARNING output" ); 228like($res->output, '/.*-3.*| iso.3.6.1.4.1.8072.3.2.67.16=-3;-2:;-3:/', "Negative integer check WARNING output" );
239 229
240$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" ); 230$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.16 -w -2: -c -3:" );
241is($res->return_code, 2, "Negative integer check CRITICAL" ); 231is($res->return_code, 2, "Negative integer check CRITICAL" );
242is($res->output, 'SNMP CRITICAL - *-4* | iso.3.6.1.4.1.8072.3.2.67.16=-4;-2:;-3: ', "Negative integer check CRITICAL output" ); 232like($res->output, '/.*-4.*| iso.3.6.1.4.1.8072.3.2.67.16=-4;-2:;-3:/', "Negative integer check CRITICAL output" );
243 233
244$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.17 -w -3: -c -6:" ); 234$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.17 -w -3: -c -6:" );
245is($res->return_code, 1, "Negative integer as string, WARNING" ); 235is($res->return_code, 1, "Negative integer as string, WARNING" );
246is($res->output, 'SNMP WARNING - *-4* | iso.3.6.1.4.1.8072.3.2.67.17=-4;-3:;-6: ', "Negative integer as string, WARNING output" ); 236like($res->output, '/.*-4.*| iso.3.6.1.4.1.8072.3.2.67.17=-4;-3:;-6:/', "Negative integer as string, WARNING output" );
247 237
248$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.17 -w -2: -c -3:" ); 238$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.17 -w -2: -c -3:" );
249is($res->return_code, 2, "Negative integer as string, CRITICAL" ); 239is($res->return_code, 2, "Negative integer as string, CRITICAL" );
250is($res->output, 'SNMP CRITICAL - *-4* | iso.3.6.1.4.1.8072.3.2.67.17=-4;-2:;-3: ', "Negative integer as string, CRITICAL output" ); 240like($res->output, '/.*-4.*| iso.3.6.1.4.1.8072.3.2.67.17=-4;-2:;-3:/', "Negative integer as string, CRITICAL output" );
251 241
252$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.18 -c '~:-6.5'" ); 242# deactivated since the perl agent api of snmpd really does not allow floats
253is($res->return_code, 0, "Negative float OK" ); 243# $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.18 -c '~:-6.5'" );
254is($res->output, 'SNMP OK - -6.6 | iso.3.6.1.4.1.8072.3.2.67.18=-6.6;;@-6.5:~ ', "Negative float OK output" ); 244# is($res->return_code, 0, "Negative float OK" );
245# is($res->output, '-6.6 | iso.3.6.1.4.1.8072.3.2.67.18=-6.6;;@-6.5:~ ', "Negative float OK output" );
255 246
256$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.18 -w '~:-6.65' -c '~:-6.55'" ); 247# $res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.18 -w '~:-6.65' -c '~:-6.55'" );
257is($res->return_code, 1, "Negative float WARNING" ); 248# is($res->return_code, 1, "Negative float WARNING" );
258is($res->output, 'SNMP WARNING - *-6.6* | iso.3.6.1.4.1.8072.3.2.67.18=-6.6;@-6.65:~;@-6.55:~ ', "Negative float WARNING output" ); 249# like($res->output, '/-6.6.*| .*67.18=-6.6;@-6.65:~;@-6.55:~/', "Negative float WARNING output" );
259 250
260$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w '1:100000,-10:20' -c '2:200000,-20:30'" ); 251$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w '1:100000,-10:20' -c '2:200000,-20:30'" );
261is($res->return_code, 0, "Multiple OIDs with thresholds" ); 252is($res->return_code, 0, "Multiple OIDs with thresholds" );
262like($res->output, '/SNMP OK - \d+ -4 | iso.3.6.1.4.1.8072.3.2.67.10=\d+c;1:100000;2:200000 iso.3.6.1.4.1.8072.3.2.67.17=-4;-10:20;-20:30/', "Multiple OIDs with thresholds output" ); 253like($res->output, '/-4.*| .*67.10=\d+c;1:100000;2:200000 .*67.17=-4;-10:20;-20:30/', "Multiple OIDs with thresholds output" );
263 254
264$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w '1:100000,-1:2' -c '2:200000,-20:30'" ); 255$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w '1:100000,-1:2' -c '2:200000,-20:30'" );
265is($res->return_code, 1, "Multiple OIDs with thresholds" ); 256is($res->return_code, 1, "Multiple OIDs with thresholds" );
266like($res->output, '/SNMP WARNING - \d+ \*-4\* | iso.3.6.1.4.1.8072.3.2.67.10=\d+c;1:100000;2:200000 iso.3.6.1.4.1.8072.3.2.67.17=-4;-10:20;-20:30/', "Multiple OIDs with thresholds output" ); 257like($res->output, '/-4.*| iso.3.6.1.4.1.8072.3.2.67.10=\d+c;1:100000;2:200000 iso.3.6.1.4.1.8072.3.2.67.17=-4;-10:20;-20:30/', "Multiple OIDs with thresholds output" );
267 258
268$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w 1,2 -c 1" ); 259$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.10,.1.3.6.1.4.1.8072.3.2.67.17 -w 1,2 -c 1 -O" );
269is($res->return_code, 2, "Multiple OIDs with some thresholds" ); 260is($res->return_code, 2, "Multiple OIDs with some thresholds" );
270like($res->output, '/SNMP CRITICAL - \*\d+\* \*-4\* | iso.3.6.1.4.1.8072.3.2.67.10=\d+c;1;2 iso.3.6.1.4.1.8072.3.2.67.17=-4;;/', "Multiple OIDs with thresholds output" ); 261like($res->output, '/.*-4.*| iso.3.6.1.4.1.8072.3.2.67.10=\d+c;1;2 iso.3.6.1.4.1.8072.3.2.67.17=-4;;/', "Multiple OIDs with thresholds output" );
271 262
272$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19"); 263$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19");
273is($res->return_code, 0, "Test plain .1.3.6.1.4.1.8072.3.2.67.6 RC" ); 264is($res->return_code, 0, "Test plain .1.3.6.1.4.1.8072.3.2.67.6 RC" );
274is($res->output,'SNMP OK - 42 | iso.3.6.1.4.1.8072.3.2.67.19=42 ', "Test plain value of .1.3.6.1.4.1.8072.3.2.67.1" ); 265like($res->output,'/.*42.*| iso.3.6.1.4.1.8072.3.2.67.19=42/', "Test plain value of .1.3.6.1.4.1.8072.3.2.67.1" );
275 266
276$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 -M .1"); 267$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 -M .1");
277is($res->return_code, 0, "Test multiply RC" ); 268is($res->return_code, 0, "Test multiply RC" );
278is($res->output,'SNMP OK - 4.200000 | iso.3.6.1.4.1.8072.3.2.67.19=4.200000 ' , "Test multiply .1 output" ); 269like($res->output,'/.*4.200000.*| iso.3.6.1.4.1.8072.3.2.67.19=4.200000/' , "Test multiply .1 output" );
279 270
280$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 --multiplier=.1 -f '%.2f' "); 271$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 --multiplier=.1");
281is($res->return_code, 0, "Test multiply RC + format" ); 272is($res->return_code, 0, "Test multiply RC" );
282is($res->output, 'SNMP OK - 4.20 | iso.3.6.1.4.1.8072.3.2.67.19=4.20 ', "Test multiply .1 output + format" ); 273like($res->output, '/.*4.20.*| iso.3.6.1.4.1.8072.3.2.67.19=4.20/', "Test multiply .1 output" );
283 274
284$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 --multiplier=.1 -f '%.2f' -w 1"); 275$res = NPTest->testCmd( "./check_snmp -H 127.0.0.1 -C public -p $port_snmp -o .1.3.6.1.4.1.8072.3.2.67.19 --multiplier=.1 -w 1");
285is($res->return_code, 1, "Test multiply RC + format + thresholds" ); 276is($res->return_code, 1, "Test multiply RC + thresholds" );
286is($res->output, 'SNMP WARNING - *4.20* | iso.3.6.1.4.1.8072.3.2.67.19=4.20;1 ', "Test multiply .1 output + format + thresholds" ); 277like($res->output, '/.*4.20.* | iso.3.6.1.4.1.8072.3.2.67.19=4.20+;1/', "Test multiply .1 output + thresholds" );
diff --git a/plugins/tests/check_snmp_agent.pl b/plugins/tests/check_snmp_agent.pl
index 38912e98..608b6f92 100644
--- a/plugins/tests/check_snmp_agent.pl
+++ b/plugins/tests/check_snmp_agent.pl
@@ -4,9 +4,10 @@
4# 4#
5 5
6#use strict; # Doesn't work 6#use strict; # Doesn't work
7use warnings;
7use NetSNMP::OID qw(:all); 8use NetSNMP::OID qw(:all);
8use NetSNMP::agent; 9use NetSNMP::agent;
9use NetSNMP::ASN qw(ASN_OCTET_STR ASN_COUNTER ASN_COUNTER64 ASN_INTEGER ASN_INTEGER64 ASN_UNSIGNED ASN_UNSIGNED64); 10use NetSNMP::ASN qw(ASN_OCTET_STR ASN_COUNTER ASN_COUNTER64 ASN_INTEGER ASN_INTEGER64 ASN_UNSIGNED ASN_UNSIGNED64 ASN_FLOAT);
10#use Math::Int64 qw(uint64); # Skip that module while we don't need it 11#use Math::Int64 qw(uint64); # Skip that module while we don't need it
11sub uint64 { return $_ } 12sub uint64 { return $_ }
12 13
@@ -22,21 +23,82 @@ IOS (tm) Catalyst 4000 "L3" Switch Software (cat4000-I9K91S-M), Version
22Technical Support: http://www.cisco.com/techsupport 23Technical Support: http://www.cisco.com/techsupport
23Copyright (c) 1986-2004 by cisco Systems, Inc. 24Copyright (c) 1986-2004 by cisco Systems, Inc.
24'; 25';
25my $multilin2 = "Kisco Outernetwork Oserating Gystem Totware 26my $multiline2 = "Kisco Outernetwork Oserating Gystem Totware
26Copyleft (c) 2400-2689 by kisco Systrems, Inc."; 27Copyleft (c) 2400-2689 by kisco Systrems, Inc.";
27my $multilin3 = 'This should not confuse check_snmp "parser" 28my $multiline3 = 'This should not confuse check_snmp "parser"
28into thinking there is no 2nd line'; 29into thinking there is no 2nd line';
29my $multilin4 = 'It\'s getting even harder if the line 30my $multiline4 = 'It\'s getting even harder if the line
30ends with with this: C:\\'; 31ends with with this: C:\\';
31my $multilin5 = 'And now have fun with with this: "C:\\" 32my $multiline5 = 'And now have fun with with this: "C:\\"
32because we\'re not done yet!'; 33because we\'re not done yet!';
33 34
34# Next are arrays of indexes (Type, initial value and increments) 35# Next are arrays of indexes (Type, initial value and increments)
35# 0..19 <---- please update comment when adding/removing fields 36# 0..19 <---- please update comment when adding/removing fields
36my @fields = (ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_UNSIGNED, ASN_UNSIGNED, ASN_COUNTER, ASN_COUNTER64, ASN_UNSIGNED, ASN_COUNTER, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_OCTET_STR, ASN_INTEGER, ASN_OCTET_STR, ASN_OCTET_STR, ASN_INTEGER ); 37my @fields = (ASN_OCTET_STR, # 0
37my @values = ($multiline, $multilin2, $multilin3, $multilin4, $multilin5, 4294965296, 1000, 4294965296, uint64("18446744073709351616"), int(rand(2**32)), 64000, "stringtests", "3.5", "87.4startswithnumberbutshouldbestring", '555"I said"', 'CUSTOM CHECK OK: foo is 12345', -2, '-4', '-6.6', 42 ); 38 ASN_OCTET_STR, # 1
39 ASN_OCTET_STR, # 2
40 ASN_OCTET_STR, # 3
41 ASN_OCTET_STR, # 4
42 ASN_UNSIGNED, # 5
43 ASN_UNSIGNED, # 6
44 ASN_COUNTER, # 7
45 ASN_COUNTER64, # 8
46 ASN_UNSIGNED, # 9
47 ASN_COUNTER, # 10
48 ASN_OCTET_STR, # 11
49 ASN_OCTET_STR, # 12
50 ASN_OCTET_STR, # 13
51 ASN_OCTET_STR, # 14
52 ASN_OCTET_STR, # 15
53 ASN_INTEGER, # 16
54 ASN_INTEGER, # 17
55 ASN_FLOAT, # 18
56 ASN_INTEGER # 19
57 );
58my @values = ($multiline, # 0
59 $multiline2, # 1
60 $multiline3, # 2
61 $multiline4, # 3
62 $multiline5, # 4
63 4294965296, # 5
64 1000, # 6
65 4294965296, # 7
66 uint64("18446744073709351616"), # 8
67 int(rand(2**32)), # 9
68 64000, # 10
69 "stringtests", # 11
70 "3.5", # 12
71 "87.4startswithnumberbutshouldbestring", # 13
72 '555"I said"', # 14
73 'CUSTOM CHECK OK: foo is 12345', # 15
74 '-2', # 16
75 '-4', # 17
76 '-6.6', # 18
77 42 # 19
78 );
38# undef increments are randomized 79# undef increments are randomized
39my @incrts = (undef, undef, undef, undef, undef, 1000, -500, 1000, 100000, undef, 666, undef, undef, undef, undef, undef, -1, undef, undef, 0 ); 80my @incrts = (
81 undef, # 0
82 undef, # 1
83 undef, # 2
84 undef, # 3
85 undef, # 4
86 1000, # 5
87 -500, # 6
88 1000, # 7
89 100000, # 8
90 undef, # 9
91 666, # 10
92 undef, # 11
93 undef, # 12
94 undef, # 13
95 undef, # 14
96 undef, # 15
97 -1, # 16
98 0, # 17
99 undef, # 18
100 0 # 19
101 );
40 102
41# Number of elements in our OID 103# Number of elements in our OID
42my $oidelts; 104my $oidelts;
diff --git a/plugins/tests/conf/snmpd.conf b/plugins/tests/conf/snmpd.conf
index eff5b0b3..1724c027 100644
--- a/plugins/tests/conf/snmpd.conf
+++ b/plugins/tests/conf/snmpd.conf
@@ -19,5 +19,5 @@ syscontact Alice
19# Embedded Subagents 19# Embedded Subagents
20############################################################################### 20###############################################################################
21 21
22perl do "tests/check_snmp_agent.pl"; 22perl do "./tests/check_snmp_agent.pl";
23 23
diff --git a/plugins/tests/test_check_disk.c b/plugins/tests/test_check_disk.c
new file mode 100644
index 00000000..32b46c2d
--- /dev/null
+++ b/plugins/tests/test_check_disk.c
@@ -0,0 +1,213 @@
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,
25 int expect, char *desc);
26
27int main(int argc, char **argv) {
28 plan_tests(35);
29
30 struct name_list *exclude_filesystem = NULL;
31 ok(np_find_name(exclude_filesystem, "/var/log") == false, "/var/log not in list");
32 np_add_name(&exclude_filesystem, "/var/log");
33 ok(np_find_name(exclude_filesystem, "/var/log") == true, "is in list now");
34 ok(np_find_name(exclude_filesystem, "/home") == false, "/home not in list");
35 np_add_name(&exclude_filesystem, "/home");
36 ok(np_find_name(exclude_filesystem, "/home") == true, "is in list now");
37 ok(np_find_name(exclude_filesystem, "/var/log") == true, "/var/log still in list");
38
39 struct name_list *exclude_fstype = NULL;
40 ok(np_find_name(exclude_fstype, "iso9660") == false, "iso9660 not in list");
41 np_add_name(&exclude_fstype, "iso9660");
42 ok(np_find_name(exclude_fstype, "iso9660") == true, "is in list now");
43
44 ok(np_find_name(exclude_filesystem, "iso9660") == false, "Make sure no clashing in variables");
45
46 /*
47 for (temp_name = exclude_filesystem; temp_name; temp_name = temp_name->next) {
48 printf("Name: %s\n", temp_name->name);
49 }
50 */
51
52 struct mount_entry *dummy_mount_list;
53 struct mount_entry **mtail = &dummy_mount_list;
54 struct mount_entry *me = (struct mount_entry *)malloc(sizeof *me);
55 me->me_devname = strdup("/dev/c0t0d0s0");
56 me->me_mountdir = strdup("/");
57 *mtail = me;
58 mtail = &me->me_next;
59
60 me = (struct mount_entry *)malloc(sizeof *me);
61 me->me_devname = strdup("/dev/c1t0d1s0");
62 me->me_mountdir = strdup("/var");
63 *mtail = me;
64 mtail = &me->me_next;
65
66 me = (struct mount_entry *)malloc(sizeof *me);
67 me->me_devname = strdup("/dev/c2t0d0s0");
68 me->me_mountdir = strdup("/home");
69 *mtail = me;
70 mtail = &me->me_next;
71
72 int cflags = REG_NOSUB | REG_EXTENDED;
73 np_test_mount_entry_regex(dummy_mount_list, strdup("/"), cflags, 3, strdup("a"));
74 np_test_mount_entry_regex(dummy_mount_list, strdup("/dev"), cflags, 3,
75 strdup("regex on dev names:"));
76 np_test_mount_entry_regex(dummy_mount_list, strdup("/foo"), cflags, 0,
77 strdup("regex on non existent dev/path:"));
78 np_test_mount_entry_regex(dummy_mount_list, strdup("/Foo"), cflags | REG_ICASE, 0,
79 strdup("regi on non existent dev/path:"));
80 np_test_mount_entry_regex(dummy_mount_list, strdup("/c.t0"), cflags, 3,
81 strdup("partial devname regex match:"));
82 np_test_mount_entry_regex(dummy_mount_list, strdup("c0t0"), cflags, 1,
83 strdup("partial devname regex match:"));
84 np_test_mount_entry_regex(dummy_mount_list, strdup("C0t0"), cflags | REG_ICASE, 1,
85 strdup("partial devname regi match:"));
86 np_test_mount_entry_regex(dummy_mount_list, strdup("home"), cflags, 1,
87 strdup("partial pathname regex match:"));
88 np_test_mount_entry_regex(dummy_mount_list, strdup("hOme"), cflags | REG_ICASE, 1,
89 strdup("partial pathname regi match:"));
90 np_test_mount_entry_regex(dummy_mount_list, strdup("(/home)|(/var)"), cflags, 2,
91 strdup("grouped regex pathname match:"));
92 np_test_mount_entry_regex(dummy_mount_list, strdup("(/homE)|(/Var)"), cflags | REG_ICASE, 2,
93 strdup("grouped regi pathname match:"));
94
95 filesystem_list test_paths = filesystem_list_init();
96 mp_int_fs_list_append(&test_paths, "/home/groups");
97 mp_int_fs_list_append(&test_paths, "/var");
98 mp_int_fs_list_append(&test_paths, "/tmp");
99 mp_int_fs_list_append(&test_paths, "/home/tonvoon");
100 mp_int_fs_list_append(&test_paths, "/dev/c2t0d0s0");
101 ok(test_paths.length == 5, "List counter works correctly with appends");
102
103 mp_int_fs_list_set_best_match(test_paths, dummy_mount_list, false);
104 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
105 struct mount_entry *temp_me;
106 temp_me = p->best_match;
107 if (!strcmp(p->name, "/home/groups")) {
108 ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"),
109 "/home/groups got right best match: /home");
110 } else if (!strcmp(p->name, "/var")) {
111 ok(temp_me && !strcmp(temp_me->me_mountdir, "/var"), "/var got right best match: /var");
112 } else if (!strcmp(p->name, "/tmp")) {
113 ok(temp_me && !strcmp(temp_me->me_mountdir, "/"), "/tmp got right best match: /");
114 } else if (!strcmp(p->name, "/home/tonvoon")) {
115 ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"),
116 "/home/tonvoon got right best match: /home");
117 } else if (!strcmp(p->name, "/dev/c2t0d0s0")) {
118 ok(temp_me && !strcmp(temp_me->me_devname, "/dev/c2t0d0s0"),
119 "/dev/c2t0d0s0 got right best match: /dev/c2t0d0s0");
120 }
121 }
122
123 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
124 mp_int_fs_list_del(&test_paths, p);
125 }
126 ok(test_paths.length == 0, "List delete sets counter properly");
127
128 mp_int_fs_list_append(&test_paths, "/home/groups");
129 mp_int_fs_list_append(&test_paths, "/var");
130 mp_int_fs_list_append(&test_paths, "/tmp");
131 mp_int_fs_list_append(&test_paths, "/home/tonvoon");
132 mp_int_fs_list_append(&test_paths, "/home");
133
134 mp_int_fs_list_set_best_match(test_paths, dummy_mount_list, true);
135 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
136 if (!strcmp(p->name, "/home/groups")) {
137 ok(!p->best_match, "/home/groups correctly not found");
138 } else if (!strcmp(p->name, "/var")) {
139 ok(p->best_match, "/var found");
140 } else if (!strcmp(p->name, "/tmp")) {
141 ok(!p->best_match, "/tmp correctly not found");
142 } else if (!strcmp(p->name, "/home/tonvoon")) {
143 ok(!p->best_match, "/home/tonvoon not found");
144 } else if (!strcmp(p->name, "/home")) {
145 ok(p->best_match, "/home found");
146 }
147 }
148
149 bool found = false;
150 /* test deleting first element in paths */
151 mp_int_fs_list_del(&test_paths, NULL);
152 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
153 if (!strcmp(p->name, "/home/groups")) {
154 found = true;
155 }
156 }
157 ok(!found, "first element successfully deleted");
158 found = false;
159
160 parameter_list_elem *prev = NULL;
161 parameter_list_elem *p = NULL;
162 for (parameter_list_elem *path = test_paths.first; path; path = mp_int_fs_list_get_next(path)) {
163 if (!strcmp(path->name, "/tmp")) {
164 mp_int_fs_list_del(&test_paths, path);
165 }
166 p = path;
167 }
168
169 parameter_list_elem *last = NULL;
170 for (parameter_list_elem *path = test_paths.first; path; path = mp_int_fs_list_get_next(path)) {
171 if (!strcmp(path->name, "/tmp")) {
172 found = true;
173 }
174 if (path->next) {
175 prev = path;
176 } else {
177 last = path;
178 }
179 }
180 ok(!found, "/tmp element successfully deleted");
181
182 int count = 0;
183 mp_int_fs_list_del(&test_paths, p);
184 for (p = test_paths.first; p; p = p->next) {
185 if (!strcmp(p->name, "/home")) {
186 found = true;
187 }
188 last = p;
189 count++;
190 }
191 ok(!found, "last (/home) element successfully deleted");
192 ok(count == 2, "two elements remaining");
193
194 return exit_status();
195}
196
197void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags,
198 int expect, char *desc) {
199 regex_t regex;
200 if (regcomp(&regex, regstr, cflags) == 0) {
201 int matches = 0;
202 for (struct mount_entry *me = dummy_mount_list; me; me = me->me_next) {
203 if (np_regex_match_mount_entry(me, &regex)) {
204 matches++;
205 }
206 }
207 ok(matches == expect, "%s '%s' matched %i/3 entries. ok: %i/3", desc, regstr, expect,
208 matches);
209
210 } else {
211 ok(false, "regex '%s' not compilable", regstr);
212 }
213}
diff --git a/plugins/tests/test_check_disk.t b/plugins/tests/test_check_disk.t
new file mode 100755
index 00000000..56354650
--- /dev/null
+++ b/plugins/tests/test_check_disk.t
@@ -0,0 +1,6 @@
1#!/usr/bin/perl
2use Test::More;
3if (! -e "./test_check_disk") {
4 plan skip_all => "./test_check_disk not compiled - please enable libtap library to test";
5}
6exec "./test_check_disk";
diff --git a/plugins/tests/test_check_snmp.c b/plugins/tests/test_check_snmp.c
new file mode 100644
index 00000000..d71706d0
--- /dev/null
+++ b/plugins/tests/test_check_snmp.c
@@ -0,0 +1,175 @@
1/*****************************************************************************
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 *
17 *****************************************************************************/
18
19#include "tap.h"
20#include "../../config.h"
21
22#include <unistd.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25
26#include "utils_base.c"
27#include "../check_snmp.d/check_snmp_helpers.h"
28
29char *_np_state_generate_key(int argc, char **argv);
30char *_np_state_calculate_location_prefix(void);
31
32int main(int argc, char **argv) {
33 char *temp_string = (char *)_np_state_generate_key(argc, argv);
34 ok(!strcmp(temp_string, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"),
35 "Got hash with exe and no parameters") ||
36 diag("You are probably running in wrong directory. Must run as ./test_utils");
37
38 int fake_argc = 4;
39 char *fake_argv[] = {
40 "./test_utils",
41 "here",
42 "--and",
43 "now",
44 };
45 temp_string = (char *)_np_state_generate_key(fake_argc, fake_argv);
46 ok(!strcmp(temp_string, "bd72da9f78ff1419fad921ea5e43ce56508aef6c"),
47 "Got based on expected argv");
48
49 unsetenv("MP_STATE_PATH");
50 temp_string = (char *)_np_state_calculate_location_prefix();
51 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory");
52
53 setenv("MP_STATE_PATH", "", 1);
54 temp_string = (char *)_np_state_calculate_location_prefix();
55 ok(!strcmp(temp_string, NP_STATE_DIR_PREFIX), "Got default directory even with empty string");
56
57 setenv("MP_STATE_PATH", "/usr/local/nagios/var", 1);
58 temp_string = (char *)_np_state_calculate_location_prefix();
59 ok(!strcmp(temp_string, "/usr/local/nagios/var"), "Got default directory");
60
61 fake_argc = 1;
62 fake_argv[0] = "./test_utils";
63 state_key temp_state_key1 = np_enable_state(NULL, 51, "check_test", fake_argc, fake_argv);
64 ok(!strcmp(temp_state_key1.plugin_name, "check_test"), "Got plugin name");
65 ok(!strcmp(temp_state_key1.name, "e2d17f995fd4c020411b85e3e3d0ff7306d4147e"),
66 "Got generated filename");
67
68 state_key temp_state_key2 =
69 np_enable_state("allowedchars_in_keyname", 77, "check_snmp", fake_argc, fake_argv);
70
71 char state_path[1024];
72 sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/allowedchars_in_keyname",
73 (unsigned long)geteuid());
74 ok(!strcmp(temp_state_key2.plugin_name, "check_test"), "Got plugin name");
75 ok(!strcmp(temp_state_key2.name, "allowedchars_in_keyname"), "Got key name with valid chars");
76 ok(!strcmp(temp_state_key2._filename, state_path), "Got internal filename");
77
78 /* Don't do this test just yet. Will die */
79 /*
80 np_enable_state("bad^chars$in@here", 77);
81 temp_state_key = this_monitoring_plugin->state;
82 ok( !strcmp(temp_state_key->name, "bad_chars_in_here"), "Got key name with bad chars replaced"
83 );
84 */
85
86 state_key temp_state_key3 =
87 np_enable_state("funnykeyname", 54, "check_snmp", fake_argc, fake_argv);
88 sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/funnykeyname",
89 (unsigned long)geteuid());
90 ok(!strcmp(temp_state_key3.plugin_name, "check_test"), "Got plugin name");
91 ok(!strcmp(temp_state_key3.name, "funnykeyname"), "Got key name");
92
93 ok(!strcmp(temp_state_key3._filename, state_path), "Got internal filename");
94 ok(temp_state_key3.data_version == 54, "Version set");
95
96 state_data *temp_state_data = np_state_read(temp_state_key3);
97 ok(temp_state_data == NULL, "Got no state data as file does not exist");
98
99 /*
100 temp_fp = fopen("var/statefile", "r");
101 if (temp_fp==NULL)
102 printf("Error opening. errno=%d\n", errno);
103 printf("temp_fp=%s\n", temp_fp);
104 ok( _np_state_read_file(temp_fp) == true, "Can read state file" );
105 fclose(temp_fp);
106 */
107
108 temp_state_key3._filename = "var/statefile";
109 temp_state_data = np_state_read(temp_state_key3);
110 ok(temp_state_data != NULL, "Got state data now") ||
111 diag("Are you running in right directory? Will get coredump next if not");
112 ok(temp_state_data->time == 1234567890, "Got time");
113 ok(!strcmp((char *)temp_state_data->data, "String to read"), "Data as expected");
114
115 temp_state_key3.data_version = 53;
116 temp_state_data = np_state_read(temp_state_key3);
117 ok(temp_state_data == NULL, "Older data version gives NULL");
118 temp_state_key3.data_version = 54;
119
120 temp_state_key3._filename = "var/nonexistent";
121 temp_state_data = np_state_read(temp_state_key3);
122 ok(temp_state_data == NULL, "Missing file gives NULL");
123
124 temp_state_key3._filename = "var/oldformat";
125 temp_state_data = np_state_read(temp_state_key3);
126 ok(temp_state_data == NULL, "Old file format gives NULL");
127
128 temp_state_key3._filename = "var/baddate";
129 temp_state_data = np_state_read(temp_state_key3);
130 ok(temp_state_data == NULL, "Bad date gives NULL");
131
132 temp_state_key3._filename = "var/missingdataline";
133 temp_state_data = np_state_read(temp_state_key3);
134 ok(temp_state_data == NULL, "Missing data line gives NULL");
135
136 unlink("var/generated");
137 temp_state_key3._filename = "var/generated";
138
139 time_t current_time = 1234567890;
140 np_state_write_string(temp_state_key3, current_time, "String to read");
141 ok(system("cmp var/generated var/statefile") == 0, "Generated file same as expected");
142
143 unlink("var/generated_directory/statefile");
144 unlink("var/generated_directory");
145 temp_state_key3._filename = "var/generated_directory/statefile";
146 current_time = 1234567890;
147 np_state_write_string(temp_state_key3, current_time, "String to read");
148 ok(system("cmp var/generated_directory/statefile var/statefile") == 0,
149 "Have created directory");
150
151 /* This test to check cannot write to dir - can't automate yet */
152 /*
153 unlink("var/generated_bad_dir");
154 mkdir("var/generated_bad_dir", S_IRUSR);
155 np_state_write_string(current_time, "String to read");
156 */
157
158 temp_state_key3._filename = "var/generated";
159 time(&current_time);
160 np_state_write_string(temp_state_key3, 0, "String to read");
161 temp_state_data = np_state_read(temp_state_key3);
162 /* Check time is set to current_time */
163 ok(system("cmp var/generated var/statefile > /dev/null") != 0,
164 "Generated file should be different this time");
165 ok(temp_state_data->time - current_time <= 1, "Has time generated from current time");
166
167 /* Don't know how to automatically test this. Need to be able to redefine die and catch the
168 * error */
169 /*
170 temp_state_key->_filename="/dev/do/not/expect/to/be/able/to/write";
171 np_state_write_string(0, "Bad file");
172 */
173
174 np_cleanup();
175}
diff --git a/plugins/tests/test_check_snmp.t b/plugins/tests/test_check_snmp.t
new file mode 100755
index 00000000..967633e9
--- /dev/null
+++ b/plugins/tests/test_check_snmp.t
@@ -0,0 +1,6 @@
1#!/usr/bin/perl
2use Test::More;
3if (! -e "./test_check_snmp") {
4 plan skip_all => "./test_check_snmp not compiled - please enable libtap library to test";
5}
6exec "./test_check_snmp";
diff --git a/plugins/tests/test_check_swap.c b/plugins/tests/test_check_swap.c
new file mode 100644
index 00000000..94d56ce7
--- /dev/null
+++ b/plugins/tests/test_check_swap.c
@@ -0,0 +1,21 @@
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) { (void)config; }
9
10const char *progname = "test_check_swap";
11
12int main(void) {
13 swap_result test_data = getSwapFromProcMeminfo("./var/proc_meminfo");
14
15 plan_tests(4);
16
17 ok(test_data.errorcode == 0, "Test whether we manage to retrieve swap data");
18 ok(test_data.metrics.total == 34233905152, "Is the total Swap correct");
19 ok(test_data.metrics.free == 34233905152, "Is the free Swap correct");
20 ok(test_data.metrics.used == 0, "Is the used Swap correct");
21}
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..a8590fae 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;
@@ -55,144 +53,141 @@ main (int argc, char **argv)
55 53
56 int c; 54 int c;
57 int option = 0; 55 int option = 0;
58 static struct option longopts[] = { 56 static struct option longopts[] = {{"help", no_argument, 0, 'h'},
59 {"help", no_argument, 0, 'h'}, 57 {"version", no_argument, 0, 'V'},
60 {"version", no_argument, 0, 'V'}, 58 {"url", required_argument, 0, 'u'},
61 {"url", required_argument, 0, 'u'}, 59 {0, 0, 0, 0}};
62 {0, 0, 0, 0}
63 };
64 60
65 setlocale (LC_ALL, ""); 61 setlocale(LC_ALL, "");
66 bindtextdomain (PACKAGE, LOCALEDIR); 62 bindtextdomain(PACKAGE, LOCALEDIR);
67 textdomain (PACKAGE); 63 textdomain(PACKAGE);
68 64
69 /* Need at least 2 args */ 65 /* Need at least 2 args */
70 if (argc < 3) { 66 if (argc < 3) {
71 print_help(); 67 print_help();
72 exit (STATE_UNKNOWN); 68 exit(STATE_UNKNOWN);
73 } 69 }
74 70
75 while (1) { 71 while (1) {
76 c = getopt_long (argc, argv, "+hVu:", longopts, &option); 72 c = getopt_long(argc, argv, "+hVu:", longopts, &option);
77 73
78 if (c == -1 || c == EOF) 74 if (c == -1 || c == EOF) {
79 break; 75 break;
76 }
80 77
81 switch (c) { 78 switch (c) {
82 case 'h': /* help */ 79 case 'h': /* help */
83 print_help (); 80 print_help();
84 exit (EXIT_SUCCESS); 81 exit(EXIT_SUCCESS);
85 break; 82 break;
86 case 'V': /* version */ 83 case 'V': /* version */
87 print_revision (progname, NP_VERSION); 84 print_revision(progname, NP_VERSION);
88 exit (EXIT_SUCCESS); 85 exit(EXIT_SUCCESS);
89 break; 86 break;
90 case 'u': 87 case 'u':
91 url = strdup (argv[optind]); 88 url = strdup(argv[optind]);
92 break; 89 break;
93 case '?': 90 case '?':
94 default: 91 default:
95 usage5 (); 92 usage5();
96 } 93 }
97 } 94 }
98 95
99 if (url == NULL) 96 if (url == NULL) {
100 url = strdup (argv[optind++]); 97 url = strdup(argv[optind++]);
98 }
101 99
102 cmd = strdup (argv[optind++]); 100 cmd = strdup(argv[optind++]);
103 for (c = optind; c < argc; c++) { 101 for (c = optind; c < argc; c++) {
104 xasprintf (&cmd, "%s %s", cmd, argv[c]); 102 xasprintf(&cmd, "%s %s", cmd, argv[c]);
105 } 103 }
106 104
107 child_process = spopen (cmd); 105 child_process = spopen(cmd);
108 if (child_process == NULL) { 106 if (child_process == NULL) {
109 printf (_("Could not open pipe: %s\n"), cmd); 107 printf(_("Could not open pipe: %s\n"), cmd);
110 exit (STATE_UNKNOWN); 108 exit(STATE_UNKNOWN);
111 } 109 }
112 110
113 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); 111 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
114 if (child_stderr == NULL) { 112 if (child_stderr == NULL) {
115 printf (_("Could not open stderr for %s\n"), cmd); 113 printf(_("Could not open stderr for %s\n"), cmd);
116 } 114 }
117 115
118 bzero(tstr, sizeof(tstr)); 116 bzero(tstr, sizeof(tstr));
119 buf = malloc(MAX_INPUT_BUFFER); 117 buf = malloc(MAX_INPUT_BUFFER);
120 printf ("<A href=\"%s\">", argv[1]); 118 printf("<A href=\"%s\">", argv[1]);
121 while (fgets (buf, MAX_INPUT_BUFFER - 1, child_process)) { 119 while (fgets(buf, MAX_INPUT_BUFFER - 1, child_process)) {
122 found++; 120 found++;
123 /* Collect the string in temp str so we can tokenize */ 121 /* Collect the string in temp str so we can tokenize */
124 strcat(tstr, buf); 122 strcat(tstr, buf);
125 } 123 }
126 124
127 if (!found) 125 if (!found) {
128 die (STATE_UNKNOWN, 126 die(STATE_UNKNOWN, _("%s UNKNOWN - No data received from host\nCMD: %s</A>\n"), argv[0],
129 _("%s UNKNOWN - No data received from host\nCMD: %s</A>\n"), 127 cmd);
130 argv[0], cmd); 128 }
131
132 129
133 /* chop the newline character */ 130 /* chop the newline character */
134 if ((nstr = strchr(tstr, NEWLINE_CHARACTER)) != NULL) 131 if ((nstr = strchr(tstr, NEWLINE_CHARACTER)) != NULL) {
135 *nstr = '\0'; 132 *nstr = '\0';
133 }
136 134
137 /* tokenize the string for Perfdata if there is some */ 135 /* tokenize the string for Perfdata if there is some */
138 nstr = strtok(tstr, PERF_CHARACTER); 136 nstr = strtok(tstr, PERF_CHARACTER);
139 printf ("%s", nstr); 137 printf("%s", nstr);
140 printf ("</A>"); 138 printf("</A>");
141 nstr = strtok(NULL, PERF_CHARACTER); 139 nstr = strtok(NULL, PERF_CHARACTER);
142 if (nstr != NULL) 140 if (nstr != NULL) {
143 printf (" | %s", nstr); 141 printf(" | %s", nstr);
142 }
144 143
145 /* close the pipe */ 144 /* close the pipe */
146 result = spclose (child_process); 145 result = spclose(child_process);
147 146
148 /* WARNING if output found on stderr */ 147 /* WARNING if output found on stderr */
149 if (fgets (buf, MAX_INPUT_BUFFER - 1, child_stderr)) 148 if (fgets(buf, MAX_INPUT_BUFFER - 1, child_stderr)) {
150 result = max_state (result, STATE_WARNING); 149 result = max_state(result, STATE_WARNING);
150 }
151 151
152 /* close stderr */ 152 /* close stderr */
153 (void) fclose (child_stderr); 153 (void)fclose(child_stderr);
154 154
155 return result; 155 return result;
156} 156}
157 157
158void print_help(void) {
159 print_revision(progname, NP_VERSION);
158 160
161 printf("Copyright (c) 2000 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n");
162 printf(COPYRIGHT, copyright, email);
159 163
160void 164 printf("%s\n", _("This plugin wraps the text output of another command (plugin) in HTML <A>"));
161print_help (void) 165 printf("%s\n",
162{ 166 _("tags, thus displaying the child plugin's output as a clickable link in compatible"));
163 print_revision (progname, NP_VERSION); 167 printf("%s\n",
164 168 _("monitoring status screen. This plugin returns the status of the invoked plugin."));
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 169
172 printf ("\n\n"); 170 printf("\n\n");
173 171
174 print_usage (); 172 print_usage();
175 173
176 printf (UT_HELP_VRSN); 174 printf(UT_HELP_VRSN);
177 175
178 printf ("\n"); 176 printf("\n");
179 printf ("%s\n", _("Examples:")); 177 printf("%s\n", _("Examples:"));
180 printf ("%s\n", _("Pay close attention to quoting to ensure that the shell passes the expected")); 178 printf("%s\n",
181 printf ("%s\n\n", _("data to the plugin. For example, in:")); 179 _("Pay close attention to quoting to ensure that the shell passes the expected"));
182 printf (" %s\n\n", _("urlize http://example.com/ check_http -H example.com -r 'two words'")); 180 printf("%s\n\n", _("data to the plugin. For example, in:"));
183 printf (" %s\n", _("the shell will remove the single quotes and urlize will see:")); 181 printf(" %s\n\n", _("urlize http://example.com/ check_http -H example.com -r 'two words'"));
184 printf (" %s\n\n", _("urlize http://example.com/ check_http -H example.com -r two words")); 182 printf(" %s\n", _("the shell will remove the single quotes and urlize will see:"));
185 printf (" %s\n\n", _("You probably want:")); 183 printf(" %s\n\n", _("urlize http://example.com/ check_http -H example.com -r two words"));
186 printf (" %s\n", _("urlize http://example.com/ \"check_http -H example.com -r 'two words'\"")); 184 printf(" %s\n\n", _("You probably want:"));
185 printf(" %s\n", _("urlize http://example.com/ \"check_http -H example.com -r 'two words'\""));
187 186
188 printf (UT_SUPPORT); 187 printf(UT_SUPPORT);
189} 188}
190 189
191 190void print_usage(void) {
192 191 printf("%s\n", _("Usage:"));
193void 192 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} 193}
diff --git a/plugins/utils.c b/plugins/utils.c
index 77d6a6f9..41fe5fcf 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,61 @@ 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) +
289 (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
347} 290}
348 291
349 292long deltime(struct timeval tv) {
350
351long
352deltime (struct timeval tv)
353{
354 struct timeval now; 293 struct timeval now;
355 gettimeofday (&now, NULL); 294 gettimeofday(&now, NULL);
356 return (now.tv_sec - tv.tv_sec)*1000000 + now.tv_usec - tv.tv_usec; 295 return (now.tv_sec - tv.tv_sec) * 1000000 + now.tv_usec - tv.tv_usec;
357} 296}
358 297
359 298void strip(char *buffer) {
360
361
362void
363strip (char *buffer)
364{
365 size_t x; 299 size_t x;
366 int i; 300 int i;
367 301
368 for (x = strlen (buffer); x >= 1; x--) { 302 for (x = strlen(buffer); x >= 1; x--) {
369 i = x - 1; 303 i = x - 1;
370 if (buffer[i] == ' ' || 304 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'; 305 buffer[i] = '\0';
373 else 306 } else {
374 break; 307 break;
308 }
375 } 309 }
376 return; 310 return;
377} 311}
378 312
379
380/****************************************************************************** 313/******************************************************************************
381 * 314 *
382 * Copies one string to another. Any previously existing data in 315 * Copies one string to another. Any previously existing data in
@@ -389,19 +322,16 @@ strip (char *buffer)
389 * 322 *
390 *****************************************************************************/ 323 *****************************************************************************/
391 324
392char * 325char *strscpy(char *dest, const char *src) {
393strscpy (char *dest, const char *src) 326 if (src == NULL) {
394{
395 if (src == NULL)
396 return NULL; 327 return NULL;
328 }
397 329
398 xasprintf (&dest, "%s", src); 330 xasprintf(&dest, "%s", src);
399 331
400 return dest; 332 return dest;
401} 333}
402 334
403
404
405/****************************************************************************** 335/******************************************************************************
406 * 336 *
407 * Returns a pointer to the next line of a multiline string buffer 337 * Returns a pointer to the next line of a multiline string buffer
@@ -418,7 +348,7 @@ strscpy (char *dest, const char *src)
418 * This 348 * This
419 * is 349 * is
420 * a 350 * a
421 * 351 *
422 * multiline string buffer 352 * multiline string buffer
423 * ============================== 353 * ==============================
424 * 354 *
@@ -431,7 +361,7 @@ strscpy (char *dest, const char *src)
431 * printf("%d %s",i++,firstword(ptr)); 361 * printf("%d %s",i++,firstword(ptr));
432 * ptr = strnl(ptr); 362 * ptr = strnl(ptr);
433 * } 363 * }
434 * 364 *
435 * Produces the following: 365 * Produces the following:
436 * 366 *
437 * 1 This 367 * 1 This
@@ -452,25 +382,26 @@ strscpy (char *dest, const char *src)
452 * 382 *
453 *****************************************************************************/ 383 *****************************************************************************/
454 384
455char * 385char *strnl(char *str) {
456strnl (char *str)
457{
458 size_t len; 386 size_t len;
459 if (str == NULL) 387 if (str == NULL) {
460 return NULL; 388 return NULL;
461 str = strpbrk (str, "\r\n"); 389 }
462 if (str == NULL) 390 str = strpbrk(str, "\r\n");
391 if (str == NULL) {
463 return NULL; 392 return NULL;
464 len = strspn (str, "\r\n"); 393 }
465 if (str[len] == '\0') 394 len = strspn(str, "\r\n");
395 if (str[len] == '\0') {
466 return NULL; 396 return NULL;
397 }
467 str += len; 398 str += len;
468 if (strlen (str) == 0) 399 if (strlen(str) == 0) {
469 return NULL; 400 return NULL;
401 }
470 return str; 402 return str;
471} 403}
472 404
473
474/****************************************************************************** 405/******************************************************************************
475 * 406 *
476 * Like strscpy, except only the portion of the source string up to 407 * Like strscpy, except only the portion of the source string up to
@@ -487,29 +418,28 @@ strnl (char *str)
487 * 418 *
488 *****************************************************************************/ 419 *****************************************************************************/
489 420
490char * 421char *strpcpy(char *dest, const char *src, const char *str) {
491strpcpy (char *dest, const char *src, const char *str)
492{
493 size_t len; 422 size_t len;
494 423
495 if (src) 424 if (src) {
496 len = strcspn (src, str); 425 len = strcspn(src, str);
497 else 426 } else {
498 return NULL; 427 return NULL;
428 }
499 429
500 if (dest == NULL || strlen (dest) < len) 430 if (dest == NULL || strlen(dest) < len) {
501 dest = realloc (dest, len + 1); 431 dest = realloc(dest, len + 1);
502 if (dest == NULL) 432 }
503 die (STATE_UNKNOWN, _("failed realloc in strpcpy\n")); 433 if (dest == NULL) {
434 die(STATE_UNKNOWN, _("failed realloc in strpcpy\n"));
435 }
504 436
505 strncpy (dest, src, len); 437 strncpy(dest, src, len);
506 dest[len] = '\0'; 438 dest[len] = '\0';
507 439
508 return dest; 440 return dest;
509} 441}
510 442
511
512
513/****************************************************************************** 443/******************************************************************************
514 * 444 *
515 * Like strscat, except only the portion of the source string up to 445 * Like strscat, except only the portion of the source string up to
@@ -518,62 +448,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"); 448 * 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"); 449 * str = strpcat(str,"This is a line of text with no trailing newline","x");
520 * printf("%s\n",str); 450 * printf("%s\n",str);
521 * 451 *
522 *This is a line of texThis is a line of tex 452 *This is a line of texThis is a line of tex
523 * 453 *
524 *****************************************************************************/ 454 *****************************************************************************/
525 455
526char * 456char *strpcat(char *dest, const char *src, const char *str) {
527strpcat (char *dest, const char *src, const char *str)
528{
529 size_t len, l2; 457 size_t len, l2;
530 458
531 if (dest) 459 if (dest) {
532 len = strlen (dest); 460 len = strlen(dest);
533 else 461 } else {
534 len = 0; 462 len = 0;
463 }
535 464
536 if (src) { 465 if (src) {
537 l2 = strcspn (src, str); 466 l2 = strcspn(src, str);
538 } 467 } else {
539 else {
540 return dest; 468 return dest;
541 } 469 }
542 470
543 dest = realloc (dest, len + l2 + 1); 471 dest = realloc(dest, len + l2 + 1);
544 if (dest == NULL) 472 if (dest == NULL) {
545 die (STATE_UNKNOWN, _("failed malloc in strscat\n")); 473 die(STATE_UNKNOWN, _("failed malloc in strscat\n"));
474 }
546 475
547 strncpy (dest + len, src, l2); 476 strncpy(dest + len, src, l2);
548 dest[len + l2] = '\0'; 477 dest[len + l2] = '\0';
549 478
550 return dest; 479 return dest;
551} 480}
552 481
553
554/****************************************************************************** 482/******************************************************************************
555 * 483 *
556 * asprintf, but die on failure 484 * asprintf, but die on failure
557 * 485 *
558 ******************************************************************************/ 486 ******************************************************************************/
559 487
560int 488int xvasprintf(char **strp, const char *fmt, va_list ap) {
561xvasprintf (char **strp, const char *fmt, va_list ap) 489 int result = vasprintf(strp, fmt, ap);
562{ 490 if (result == -1 || *strp == NULL) {
563 int result = vasprintf (strp, fmt, ap); 491 die(STATE_UNKNOWN, _("failed malloc in xvasprintf\n"));
564 if (result == -1 || *strp == NULL) 492 }
565 die (STATE_UNKNOWN, _("failed malloc in xvasprintf\n"));
566 return result; 493 return result;
567} 494}
568 495
569int 496int xasprintf(char **strp, const char *fmt, ...) {
570xasprintf (char **strp, const char *fmt, ...)
571{
572 va_list ap; 497 va_list ap;
573 int result; 498 int result;
574 va_start (ap, fmt); 499 va_start(ap, fmt);
575 result = xvasprintf (strp, fmt, ap); 500 result = xvasprintf(strp, fmt, ap);
576 va_end (ap); 501 va_end(ap);
577 return result; 502 return result;
578} 503}
579 504
@@ -583,247 +508,223 @@ xasprintf (char **strp, const char *fmt, ...)
583 * 508 *
584 ******************************************************************************/ 509 ******************************************************************************/
585 510
586char *perfdata (const char *label, 511char *perfdata(const char *label, long int val, const char *uom, bool warnp, long int warn,
587 long int val, 512 bool critp, long int crit, bool minp, 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; 513 char *data = NULL;
599 514
600 if (strpbrk (label, "'= ")) 515 if (strpbrk(label, "'= ")) {
601 xasprintf (&data, "'%s'=%ld%s;", label, val, uom); 516 xasprintf(&data, "'%s'=%ld%s;", label, val, uom);
602 else 517 } else {
603 xasprintf (&data, "%s=%ld%s;", label, val, uom); 518 xasprintf(&data, "%s=%ld%s;", label, val, uom);
519 }
604 520
605 if (warnp) 521 if (warnp) {
606 xasprintf (&data, "%s%ld;", data, warn); 522 xasprintf(&data, "%s%ld;", data, warn);
607 else 523 } else {
608 xasprintf (&data, "%s;", data); 524 xasprintf(&data, "%s;", data);
525 }
609 526
610 if (critp) 527 if (critp) {
611 xasprintf (&data, "%s%ld;", data, crit); 528 xasprintf(&data, "%s%ld;", data, crit);
612 else 529 } else {
613 xasprintf (&data, "%s;", data); 530 xasprintf(&data, "%s;", data);
531 }
614 532
615 if (minp) 533 if (minp) {
616 xasprintf (&data, "%s%ld;", data, minv); 534 xasprintf(&data, "%s%ld;", data, minv);
617 else 535 } else {
618 xasprintf (&data, "%s;", data); 536 xasprintf(&data, "%s;", data);
537 }
619 538
620 if (maxp) 539 if (maxp) {
621 xasprintf (&data, "%s%ld", data, maxv); 540 xasprintf(&data, "%s%ld", data, maxv);
541 }
622 542
623 return data; 543 return data;
624} 544}
625 545
626 546char *perfdata_uint64(const char *label, uint64_t val, const char *uom,
627char *perfdata_uint64 (const char *label, 547 bool warnp, /* Warning present */
628 uint64_t val, 548 uint64_t warn, bool critp, /* Critical present */
629 const char *uom, 549 uint64_t crit, bool minp, /* Minimum present */
630 int warnp, /* Warning present */ 550 uint64_t minv, bool maxp, /* Maximum present */
631 uint64_t warn, 551 uint64_t maxv) {
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; 552 char *data = NULL;
640 553
641 if (strpbrk (label, "'= ")) 554 if (strpbrk(label, "'= ")) {
642 xasprintf (&data, "'%s'=%" PRIu64 "%s;", label, val, uom); 555 xasprintf(&data, "'%s'=%" PRIu64 "%s;", label, val, uom);
643 else 556 } else {
644 xasprintf (&data, "%s=%" PRIu64 "%s;", label, val, uom); 557 xasprintf(&data, "%s=%" PRIu64 "%s;", label, val, uom);
558 }
645 559
646 if (warnp) 560 if (warnp) {
647 xasprintf (&data, "%s%" PRIu64 ";", data, warn); 561 xasprintf(&data, "%s%" PRIu64 ";", data, warn);
648 else 562 } else {
649 xasprintf (&data, "%s;", data); 563 xasprintf(&data, "%s;", data);
564 }
650 565
651 if (critp) 566 if (critp) {
652 xasprintf (&data, "%s%" PRIu64 ";", data, crit); 567 xasprintf(&data, "%s%" PRIu64 ";", data, crit);
653 else 568 } else {
654 xasprintf (&data, "%s;", data); 569 xasprintf(&data, "%s;", data);
570 }
655 571
656 if (minp) 572 if (minp) {
657 xasprintf (&data, "%s%" PRIu64 ";", data, minv); 573 xasprintf(&data, "%s%" PRIu64 ";", data, minv);
658 else 574 } else {
659 xasprintf (&data, "%s;", data); 575 xasprintf(&data, "%s;", data);
576 }
660 577
661 if (maxp) 578 if (maxp) {
662 xasprintf (&data, "%s%" PRIu64, data, maxv); 579 xasprintf(&data, "%s%" PRIu64, data, maxv);
580 }
663 581
664 return data; 582 return data;
665} 583}
666 584
667 585char *perfdata_int64(const char *label, int64_t val, const char *uom,
668char *perfdata_int64 (const char *label, 586 bool warnp, /* Warning present */
669 int64_t val, 587 int64_t warn, bool critp, /* Critical present */
670 const char *uom, 588 int64_t crit, bool minp, /* Minimum present */
671 int warnp, /* Warning present */ 589 int64_t minv, bool maxp, /* Maximum present */
672 int64_t warn, 590 int64_t maxv) {
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; 591 char *data = NULL;
681 592
682 if (strpbrk (label, "'= ")) 593 if (strpbrk(label, "'= ")) {
683 xasprintf (&data, "'%s'=%" PRId64 "%s;", label, val, uom); 594 xasprintf(&data, "'%s'=%" PRId64 "%s;", label, val, uom);
684 else 595 } else {
685 xasprintf (&data, "%s=%" PRId64 "%s;", label, val, uom); 596 xasprintf(&data, "%s=%" PRId64 "%s;", label, val, uom);
597 }
686 598
687 if (warnp) 599 if (warnp) {
688 xasprintf (&data, "%s%" PRId64 ";", data, warn); 600 xasprintf(&data, "%s%" PRId64 ";", data, warn);
689 else 601 } else {
690 xasprintf (&data, "%s;", data); 602 xasprintf(&data, "%s;", data);
603 }
691 604
692 if (critp) 605 if (critp) {
693 xasprintf (&data, "%s%" PRId64 ";", data, crit); 606 xasprintf(&data, "%s%" PRId64 ";", data, crit);
694 else 607 } else {
695 xasprintf (&data, "%s;", data); 608 xasprintf(&data, "%s;", data);
609 }
696 610
697 if (minp) 611 if (minp) {
698 xasprintf (&data, "%s%" PRId64 ";", data, minv); 612 xasprintf(&data, "%s%" PRId64 ";", data, minv);
699 else 613 } else {
700 xasprintf (&data, "%s;", data); 614 xasprintf(&data, "%s;", data);
615 }
701 616
702 if (maxp) 617 if (maxp) {
703 xasprintf (&data, "%s%" PRId64, data, maxv); 618 xasprintf(&data, "%s%" PRId64, data, maxv);
619 }
704 620
705 return data; 621 return data;
706} 622}
707 623
708 624char *fperfdata(const char *label, double val, const char *uom, bool warnp, double warn, bool critp,
709char *fperfdata (const char *label, 625 double crit, bool minp, double minv, 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; 626 char *data = NULL;
722 627
723 if (strpbrk (label, "'= ")) 628 if (strpbrk(label, "'= ")) {
724 xasprintf (&data, "'%s'=", label); 629 xasprintf(&data, "'%s'=", label);
725 else 630 } else {
726 xasprintf (&data, "%s=", label); 631 xasprintf(&data, "%s=", label);
632 }
727 633
728 xasprintf (&data, "%s%f", data, val); 634 xasprintf(&data, "%s%f", data, val);
729 xasprintf (&data, "%s%s;", data, uom); 635 xasprintf(&data, "%s%s;", data, uom);
730 636
731 if (warnp) 637 if (warnp) {
732 xasprintf (&data, "%s%f", data, warn); 638 xasprintf(&data, "%s%f", data, warn);
639 }
733 640
734 xasprintf (&data, "%s;", data); 641 xasprintf(&data, "%s;", data);
735 642
736 if (critp) 643 if (critp) {
737 xasprintf (&data, "%s%f", data, crit); 644 xasprintf(&data, "%s%f", data, crit);
645 }
738 646
739 xasprintf (&data, "%s;", data); 647 xasprintf(&data, "%s;", data);
740 648
741 if (minp) 649 if (minp) {
742 xasprintf (&data, "%s%f", data, minv); 650 xasprintf(&data, "%s%f", data, minv);
651 }
743 652
744 if (maxp) { 653 if (maxp) {
745 xasprintf (&data, "%s;", data); 654 xasprintf(&data, "%s;", data);
746 xasprintf (&data, "%s%f", data, maxv); 655 xasprintf(&data, "%s%f", data, maxv);
747 } 656 }
748 657
749 return data; 658 return data;
750} 659}
751 660
752char *sperfdata (const char *label, 661char *sperfdata(const char *label, double val, const char *uom, char *warn, char *crit, bool minp,
753 double val, 662 double minv, bool maxp, double maxv) {
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; 663 char *data = NULL;
763 if (strpbrk (label, "'= ")) 664 if (strpbrk(label, "'= ")) {
764 xasprintf (&data, "'%s'=", label); 665 xasprintf(&data, "'%s'=", label);
765 else 666 } else {
766 xasprintf (&data, "%s=", label); 667 xasprintf(&data, "%s=", label);
668 }
767 669
768 xasprintf (&data, "%s%f", data, val); 670 xasprintf(&data, "%s%f", data, val);
769 xasprintf (&data, "%s%s;", data, uom); 671 xasprintf(&data, "%s%s;", data, uom);
770 672
771 if (warn!=NULL) 673 if (warn != NULL) {
772 xasprintf (&data, "%s%s", data, warn); 674 xasprintf(&data, "%s%s", data, warn);
675 }
773 676
774 xasprintf (&data, "%s;", data); 677 xasprintf(&data, "%s;", data);
775 678
776 if (crit!=NULL) 679 if (crit != NULL) {
777 xasprintf (&data, "%s%s", data, crit); 680 xasprintf(&data, "%s%s", data, crit);
681 }
778 682
779 xasprintf (&data, "%s;", data); 683 xasprintf(&data, "%s;", data);
780 684
781 if (minp) 685 if (minp) {
782 xasprintf (&data, "%s%f", data, minv); 686 xasprintf(&data, "%s%f", data, minv);
687 }
783 688
784 if (maxp) { 689 if (maxp) {
785 xasprintf (&data, "%s;", data); 690 xasprintf(&data, "%s;", data);
786 xasprintf (&data, "%s%f", data, maxv); 691 xasprintf(&data, "%s%f", data, maxv);
787 } 692 }
788 693
789 return data; 694 return data;
790} 695}
791 696
792char *sperfdata_int (const char *label, 697char *sperfdata_int(const char *label, int val, const char *uom, char *warn, char *crit, bool minp,
793 int val, 698 int minv, bool maxp, int maxv) {
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; 699 char *data = NULL;
803 if (strpbrk (label, "'= ")) 700 if (strpbrk(label, "'= ")) {
804 xasprintf (&data, "'%s'=", label); 701 xasprintf(&data, "'%s'=", label);
805 else 702 } else {
806 xasprintf (&data, "%s=", label); 703 xasprintf(&data, "%s=", label);
704 }
807 705
808 xasprintf (&data, "%s%d", data, val); 706 xasprintf(&data, "%s%d", data, val);
809 xasprintf (&data, "%s%s;", data, uom); 707 xasprintf(&data, "%s%s;", data, uom);
810 708
811 if (warn!=NULL) 709 if (warn != NULL) {
812 xasprintf (&data, "%s%s", data, warn); 710 xasprintf(&data, "%s%s", data, warn);
711 }
813 712
814 xasprintf (&data, "%s;", data); 713 xasprintf(&data, "%s;", data);
815 714
816 if (crit!=NULL) 715 if (crit != NULL) {
817 xasprintf (&data, "%s%s", data, crit); 716 xasprintf(&data, "%s%s", data, crit);
717 }
818 718
819 xasprintf (&data, "%s;", data); 719 xasprintf(&data, "%s;", data);
820 720
821 if (minp) 721 if (minp) {
822 xasprintf (&data, "%s%d", data, minv); 722 xasprintf(&data, "%s%d", data, minv);
723 }
823 724
824 if (maxp) { 725 if (maxp) {
825 xasprintf (&data, "%s;", data); 726 xasprintf(&data, "%s;", data);
826 xasprintf (&data, "%s%d", data, maxv); 727 xasprintf(&data, "%s%d", data, maxv);
827 } 728 }
828 729
829 return data; 730 return data;
diff --git a/plugins/utils.h b/plugins/utils.h
index f939e337..1f0e021b 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,148 @@ 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,
95 int, long int, int, long int, int, long int); 92 bool, long int);
96 93
97char *perfdata_uint64 (const char *, uint64_t , const char *, int, uint64_t, 94char *perfdata_uint64(const char *, uint64_t, const char *, bool, uint64_t, bool, uint64_t, bool,
98 int, uint64_t, int, uint64_t, int, uint64_t); 95 uint64_t, bool, uint64_t);
99 96
100char *perfdata_int64 (const char *, int64_t, const char *, int, int64_t, 97char *perfdata_int64(const char *, int64_t, const char *, bool, int64_t, bool, int64_t, bool,
101 int, int64_t, int, int64_t, int, int64_t); 98 int64_t, bool, int64_t);
102 99
103char *fperfdata (const char *, double, const char *, int, double, 100char *fperfdata(const char *, double, const char *, bool, double, bool, double, bool, double, bool,
104 int, double, int, double, int, double); 101 double);
105 102
106char *sperfdata (const char *, double, const char *, char *, char *, 103char *sperfdata(const char *, double, const char *, char *, char *, bool, double, bool, double);
107 int, double, int, double);
108 104
109char *sperfdata_int (const char *, int, const char *, char *, char *, 105char *sperfdata_int(const char *, int, const char *, char *, char *, bool, int, bool, int);
110 int, int, int, int);
111 106
112/* The idea here is that, although not every plugin will use all of these, 107/* 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 108 most will or should. Therefore, for consistency, these very common
114 options should have only these meanings throughout the overall suite */ 109 options should have only these meanings throughout the overall suite */
115 110
116#define STD_LONG_OPTS \ 111#define STD_LONG_OPTS \
117{"version",no_argument,0,'V'},\ 112 {"version", no_argument, 0, 'V'}, {"verbose", no_argument, 0, 'v'}, \
118{"verbose",no_argument,0,'v'},\ 113 {"help", no_argument, 0, 'h'}, {"timeout", required_argument, 0, 't'}, \
119{"help",no_argument,0,'h'},\ 114 {"critical", required_argument, 0, 'c'}, {"warning", required_argument, 0, 'w'}, \
120{"timeout",required_argument,0,'t'},\ 115 {"hostname", required_argument, 0, 'H'}
121{"critical",required_argument,0,'c'},\
122{"warning",required_argument,0,'w'},\
123{"hostname",required_argument,0,'H'}
124 116
125#define COPYRIGHT "Copyright (c) %s Monitoring Plugins Development Team\n\ 117#define COPYRIGHT \
118 "Copyright (c) %s Monitoring Plugins Development Team\n\
126\t<%s>\n\n" 119\t<%s>\n\n"
127 120
128#define UT_HLP_VRS _("\ 121#define UT_HLP_VRS \
122 _("\
129 %s (-h | --help) for detailed help\n\ 123 %s (-h | --help) for detailed help\n\
130 %s (-V | --version) for version information\n") 124 %s (-V | --version) for version information\n")
131 125
132#define UT_HELP_VRSN _("\ 126#define UT_HELP_VRSN \
127 _("\
133\nOptions:\n\ 128\nOptions:\n\
134 -h, --help\n\ 129 -h, --help\n\
135 Print detailed help screen\n\ 130 Print detailed help screen\n\
136 -V, --version\n\ 131 -V, --version\n\
137 Print version information\n") 132 Print version information\n")
138 133
139#define UT_HOST_PORT _("\ 134#define UT_HOST_PORT \
135 _("\
140 -H, --hostname=ADDRESS\n\ 136 -H, --hostname=ADDRESS\n\
141 Host name, IP Address, or unix socket (must be an absolute path)\n\ 137 Host name, IP Address, or unix socket (must be an absolute path)\n\
142 -%c, --port=INTEGER\n\ 138 -%c, --port=INTEGER\n\
143 Port number (default: %s)\n") 139 Port number (default: %s)\n")
144 140
145#define UT_IPv46 _("\ 141#define UT_IPv46 \
142 _("\
146 -4, --use-ipv4\n\ 143 -4, --use-ipv4\n\
147 Use IPv4 connection\n\ 144 Use IPv4 connection\n\
148 -6, --use-ipv6\n\ 145 -6, --use-ipv6\n\
149 Use IPv6 connection\n") 146 Use IPv6 connection\n")
150 147
151#define UT_VERBOSE _("\ 148#define UT_VERBOSE \
149 _("\
152 -v, --verbose\n\ 150 -v, --verbose\n\
153 Show details for command-line debugging (output may be truncated by\n\ 151 Show details for command-line debugging (output may be truncated by\n\
154 the monitoring system)\n") 152 the monitoring system)\n")
155 153
156#define UT_WARN_CRIT _("\ 154#define UT_WARN_CRIT \
155 _("\
157 -w, --warning=DOUBLE\n\ 156 -w, --warning=DOUBLE\n\
158 Response time to result in warning status (seconds)\n\ 157 Response time to result in warning status (seconds)\n\
159 -c, --critical=DOUBLE\n\ 158 -c, --critical=DOUBLE\n\
160 Response time to result in critical status (seconds)\n") 159 Response time to result in critical status (seconds)\n")
161 160
162#define UT_WARN_CRIT_RANGE _("\ 161#define UT_WARN_CRIT_RANGE \
162 _("\
163 -w, --warning=RANGE\n\ 163 -w, --warning=RANGE\n\
164 Warning range (format: start:end). Alert if outside this range\n\ 164 Warning range (format: start:end). Alert if outside this range\n\
165 -c, --critical=RANGE\n\ 165 -c, --critical=RANGE\n\
166 Critical range\n") 166 Critical range\n")
167 167
168#define UT_CONN_TIMEOUT _("\ 168#define UT_CONN_TIMEOUT \
169 _("\
169 -t, --timeout=INTEGER\n\ 170 -t, --timeout=INTEGER\n\
170 Seconds before connection times out (default: %d)\n") 171 Seconds before connection times out (default: %d)\n")
171 172
172#define UT_PLUG_TIMEOUT _("\ 173#define UT_PLUG_TIMEOUT \
174 _("\
173 -t, --timeout=INTEGER\n\ 175 -t, --timeout=INTEGER\n\
174 Seconds before plugin times out (default: %d)\n") 176 Seconds before plugin times out (default: %d)\n")
175 177
176#ifdef NP_EXTRA_OPTS 178#ifdef NP_EXTRA_OPTS
177#define UT_EXTRA_OPTS _("\ 179# define UT_EXTRA_OPTS \
180 _("\
178 --extra-opts=[section][@file]\n\ 181 --extra-opts=[section][@file]\n\
179 Read options from an ini file. See\n\ 182 Read options from an ini file. See\n\
180 https://www.monitoring-plugins.org/doc/extra-opts.html\n\ 183 https://www.monitoring-plugins.org/doc/extra-opts.html\n\
181 for usage and examples.\n") 184 for usage and examples.\n")
182#else 185#else
183#define UT_EXTRA_OPTS " \b" 186# define UT_EXTRA_OPTS " \b"
184#endif 187#endif
185 188
186#define UT_THRESHOLDS_NOTES _("\ 189#define UT_THRESHOLDS_NOTES \
190 _("\
187 See:\n\ 191 See:\n\
188 https://www.monitoring-plugins.org/doc/guidelines.html#THRESHOLDFORMAT\n\ 192 https://www.monitoring-plugins.org/doc/guidelines.html#THRESHOLDFORMAT\n\
189 for THRESHOLD format and examples.\n") 193 for THRESHOLD format and examples.\n")
190 194
191#define UT_SUPPORT _("\n\ 195#define UT_SUPPORT \
196 _("\n\
192Send email to help@monitoring-plugins.org if you have questions regarding\n\ 197Send email to help@monitoring-plugins.org if you have questions regarding\n\
193use of this software. To submit patches or suggest improvements, send email\n\ 198use of this software. To submit patches or suggest improvements, send email\n\
194to devel@monitoring-plugins.org\n\n") 199to devel@monitoring-plugins.org\n\n")
195 200
196#define UT_NOWARRANTY _("\n\ 201#define UT_NOWARRANTY \
202 _("\n\
197The Monitoring Plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n\ 203The 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\ 204copies 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") 205For more information about these matters, see the file named COPYING.\n")
200 206
207#define UT_OUTPUT_FORMAT \
208 _("\
209 --output-format=OUTPUT_FORMAT\n\
210 Select output format. Valid values: \"multi-line\", \"mp-test-json\"\n")
211
201#endif /* NP_UTILS_H */ 212#endif /* NP_UTILS_H */
diff --git a/tap/tap.c b/tap/tap.c
index 97c20e96..fb40736f 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,8 @@ static void _cleanup(void);
65 * test_name -- the name of the test, may be NULL 65 * test_name -- the name of the test, may be NULL
66 * test_comment -- a comment to print afterwards, may be NULL 66 * test_comment -- a comment to print afterwards, may be NULL
67 */ 67 */
68unsigned int 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, 69 ...) {
70 char *test_name, ...)
71{
72 va_list ap; 70 va_list ap;
73 char *local_test_name = NULL; 71 char *local_test_name = NULL;
74 char *c; 72 char *c;
@@ -80,7 +78,7 @@ _gen_result(int ok, const char *func, char *file, unsigned int line,
80 78
81 /* Start by taking the test name and performing any printf() 79 /* Start by taking the test name and performing any printf()
82 expansions on it */ 80 expansions on it */
83 if(test_name != NULL) { 81 if (test_name != NULL) {
84 va_start(ap, test_name); 82 va_start(ap, test_name);
85 vasprintf(&local_test_name, test_name, ap); 83 vasprintf(&local_test_name, test_name, ap);
86 va_end(ap); 84 va_end(ap);
@@ -88,43 +86,46 @@ _gen_result(int ok, const char *func, char *file, unsigned int line,
88 /* Make sure the test name contains more than digits 86 /* Make sure the test name contains more than digits
89 and spaces. Emit an error message and exit if it 87 and spaces. Emit an error message and exit if it
90 does */ 88 does */
91 if(local_test_name) { 89 if (local_test_name) {
92 name_is_digits = 1; 90 name_is_digits = 1;
93 for(c = local_test_name; *c != '\0'; c++) { 91 for (c = local_test_name; *c != '\0'; c++) {
94 if(!isdigit(*c) && !isspace(*c)) { 92 if (!isdigit(*c) && !isspace(*c)) {
95 name_is_digits = 0; 93 name_is_digits = 0;
96 break; 94 break;
97 } 95 }
98 } 96 }
99 97
100 if(name_is_digits) { 98 if (name_is_digits) {
101 diag(" You named your test '%s'. You shouldn't use numbers for your test names.", local_test_name); 99 diag(
100 " You named your test '%s'. You shouldn't use numbers for your test names.",
101 local_test_name);
102 diag(" Very confusing."); 102 diag(" Very confusing.");
103 } 103 }
104 } 104 }
105 } 105 }
106 106
107 if(!ok) { 107 if (!ok) {
108 printf("not "); 108 printf("not ");
109 failures++; 109 failures++;
110 } 110 }
111 111
112 printf("ok %d", test_count); 112 printf("ok %d", test_count);
113 113
114 if(test_name != NULL) { 114 if (test_name != NULL) {
115 printf(" - "); 115 printf(" - ");
116 116
117 /* Print the test name, escaping any '#' characters it 117 /* Print the test name, escaping any '#' characters it
118 might contain */ 118 might contain */
119 if(local_test_name != NULL) { 119 if (local_test_name != NULL) {
120 flockfile(stdout); 120 flockfile(stdout);
121 for(c = local_test_name; *c != '\0'; c++) { 121 for (c = local_test_name; *c != '\0'; c++) {
122 if(*c == '#') 122 if (*c == '#') {
123 fputc('\\', stdout); 123 fputc('\\', stdout);
124 }
124 fputc((int)*c, stdout); 125 fputc((int)*c, stdout);
125 } 126 }
126 funlockfile(stdout); 127 funlockfile(stdout);
127 } else { /* vasprintf() failed, use a fixed message */ 128 } else { /* vasprintf() failed, use a fixed message */
128 printf("%s", todo_msg_fixed); 129 printf("%s", todo_msg_fixed);
129 } 130 }
130 } 131 }
@@ -136,17 +137,18 @@ _gen_result(int ok, const char *func, char *file, unsigned int line,
136 137
137 This is not counted as a failure, so decrement the counter if 138 This is not counted as a failure, so decrement the counter if
138 the test failed. */ 139 the test failed. */
139 if(todo) { 140 if (todo) {
140 printf(" # TODO %s", todo_msg ? todo_msg : todo_msg_fixed); 141 printf(" # TODO %s", todo_msg ? todo_msg : todo_msg_fixed);
141 if(!ok) 142 if (!ok) {
142 failures--; 143 failures--;
144 }
143 } 145 }
144 146
145 printf("\n"); 147 printf("\n");
146 148
147 if(!ok) 149 if (!ok) {
148 diag(" Failed %stest (%s:%s() at line %d)", 150 diag(" Failed %stest (%s:%s() at line %d)", todo ? "(TODO) " : "", file, func, line);
149 todo ? "(TODO) " : "", file, func, line); 151 }
150 152
151 free(local_test_name); 153 free(local_test_name);
152 154
@@ -161,18 +163,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 163 * Initialise the TAP library. Will only do so once, however many times it's
162 * called. 164 * called.
163 */ 165 */
164void 166void _tap_init(void) {
165_tap_init(void)
166{
167 static int run_once = 0; 167 static int run_once = 0;
168 168
169 LOCK; 169 LOCK;
170 170
171 if(!run_once) { 171 if (!run_once) {
172 atexit(_cleanup); 172 atexit(_cleanup);
173 173
174 /* stdout needs to be unbuffered so that the output appears 174 /* stdout needs to be unbuffered so that the output appears
175 in the same place relative to stderr output as it does 175 in the same place relative to stderr output as it does
176 with Test::Harness */ 176 with Test::Harness */
177 setbuf(stdout, 0); 177 setbuf(stdout, 0);
178 run_once = 1; 178 run_once = 1;
@@ -184,15 +184,13 @@ _tap_init(void)
184/* 184/*
185 * Note that there's no plan. 185 * Note that there's no plan.
186 */ 186 */
187int 187int plan_no_plan(void) {
188plan_no_plan(void)
189{
190 188
191 LOCK; 189 LOCK;
192 190
193 _tap_init(); 191 _tap_init();
194 192
195 if(have_plan != 0) { 193 if (have_plan != 0) {
196 fprintf(stderr, "You tried to plan twice!\n"); 194 fprintf(stderr, "You tried to plan twice!\n");
197 test_died = 1; 195 test_died = 1;
198 UNLOCK; 196 UNLOCK;
@@ -210,9 +208,7 @@ plan_no_plan(void)
210/* 208/*
211 * Note that the plan is to skip all tests 209 * Note that the plan is to skip all tests
212 */ 210 */
213int 211int plan_skip_all(char *reason) {
214plan_skip_all(char *reason)
215{
216 212
217 LOCK; 213 LOCK;
218 214
@@ -222,8 +218,9 @@ plan_skip_all(char *reason)
222 218
223 printf("1..0"); 219 printf("1..0");
224 220
225 if(reason != NULL) 221 if (reason != NULL) {
226 printf(" # Skip %s", reason); 222 printf(" # Skip %s", reason);
223 }
227 224
228 printf("\n"); 225 printf("\n");
229 226
@@ -235,22 +232,20 @@ plan_skip_all(char *reason)
235/* 232/*
236 * Note the number of tests that will be run. 233 * Note the number of tests that will be run.
237 */ 234 */
238int 235int plan_tests(unsigned int tests) {
239plan_tests(unsigned int tests)
240{
241 236
242 LOCK; 237 LOCK;
243 238
244 _tap_init(); 239 _tap_init();
245 240
246 if(have_plan != 0) { 241 if (have_plan != 0) {
247 fprintf(stderr, "You tried to plan twice!\n"); 242 fprintf(stderr, "You tried to plan twice!\n");
248 test_died = 1; 243 test_died = 1;
249 UNLOCK; 244 UNLOCK;
250 exit(255); 245 exit(255);
251 } 246 }
252 247
253 if(tests == 0) { 248 if (tests == 0) {
254 fprintf(stderr, "You said to run 0 tests! You've got to run something.\n"); 249 fprintf(stderr, "You said to run 0 tests! You've got to run something.\n");
255 test_died = 1; 250 test_died = 1;
256 UNLOCK; 251 UNLOCK;
@@ -266,9 +261,7 @@ plan_tests(unsigned int tests)
266 return 0; 261 return 0;
267} 262}
268 263
269unsigned int 264unsigned int diag(char *fmt, ...) {
270diag(char *fmt, ...)
271{
272 va_list ap; 265 va_list ap;
273 266
274 LOCK; 267 LOCK;
@@ -286,9 +279,7 @@ diag(char *fmt, ...)
286 return 0; 279 return 0;
287} 280}
288 281
289void 282void _expected_tests(unsigned int tests) {
290_expected_tests(unsigned int tests)
291{
292 283
293 LOCK; 284 LOCK;
294 285
@@ -298,9 +289,7 @@ _expected_tests(unsigned int tests)
298 UNLOCK; 289 UNLOCK;
299} 290}
300 291
301int 292int skip(unsigned int n, char *fmt, ...) {
302skip(unsigned int n, char *fmt, ...)
303{
304 va_list ap; 293 va_list ap;
305 char *skip_msg; 294 char *skip_msg;
306 295
@@ -310,11 +299,10 @@ skip(unsigned int n, char *fmt, ...)
310 asprintf(&skip_msg, fmt, ap); 299 asprintf(&skip_msg, fmt, ap);
311 va_end(ap); 300 va_end(ap);
312 301
313 while(n-- > 0) { 302 while (n-- > 0) {
314 test_count++; 303 test_count++;
315 printf("ok %d # skip %s\n", test_count, 304 printf("ok %d # skip %s\n", test_count,
316 skip_msg != NULL ? 305 skip_msg != NULL ? skip_msg : "libtap():malloc() failed");
317 skip_msg : "libtap():malloc() failed");
318 } 306 }
319 307
320 free(skip_msg); 308 free(skip_msg);
@@ -324,9 +312,7 @@ skip(unsigned int n, char *fmt, ...)
324 return 1; 312 return 1;
325} 313}
326 314
327void 315void todo_start(char *fmt, ...) {
328todo_start(char *fmt, ...)
329{
330 va_list ap; 316 va_list ap;
331 317
332 LOCK; 318 LOCK;
@@ -340,9 +326,7 @@ todo_start(char *fmt, ...)
340 UNLOCK; 326 UNLOCK;
341} 327}
342 328
343void 329void todo_end(void) {
344todo_end(void)
345{
346 330
347 LOCK; 331 LOCK;
348 332
@@ -352,28 +336,26 @@ todo_end(void)
352 UNLOCK; 336 UNLOCK;
353} 337}
354 338
355int 339int exit_status(void) {
356exit_status(void)
357{
358 int r; 340 int r;
359 341
360 LOCK; 342 LOCK;
361 343
362 /* If there's no plan, just return the number of failures */ 344 /* If there's no plan, just return the number of failures */
363 if(no_plan || !have_plan) { 345 if (no_plan || !have_plan) {
364 UNLOCK; 346 UNLOCK;
365 return failures; 347 return failures;
366 } 348 }
367 349
368 /* Ran too many tests? Return the number of tests that were run 350 /* Ran too many tests? Return the number of tests that were run
369 that shouldn't have been */ 351 that shouldn't have been */
370 if(e_tests < test_count) { 352 if (e_tests < test_count) {
371 r = test_count - e_tests; 353 r = test_count - e_tests;
372 UNLOCK; 354 UNLOCK;
373 return r; 355 return r;
374 } 356 }
375 357
376 /* Return the number of tests that failed + the number of tests 358 /* Return the number of tests that failed + the number of tests
377 that weren't run */ 359 that weren't run */
378 r = failures + e_tests - test_count; 360 r = failures + e_tests - test_count;
379 UNLOCK; 361 UNLOCK;
@@ -385,51 +367,46 @@ exit_status(void)
385 * Cleanup at the end of the run, produce any final output that might be 367 * Cleanup at the end of the run, produce any final output that might be
386 * required. 368 * required.
387 */ 369 */
388void 370void _cleanup(void) {
389_cleanup(void)
390{
391 371
392 LOCK; 372 LOCK;
393 373
394 /* If plan_no_plan() wasn't called, and we don't have a plan, 374 /* If plan_no_plan() wasn't called, and we don't have a plan,
395 and we're not skipping everything, then something happened 375 and we're not skipping everything, then something happened
396 before we could produce any output */ 376 before we could produce any output */
397 if(!no_plan && !have_plan && !skip_all) { 377 if (!no_plan && !have_plan && !skip_all) {
398 diag("Looks like your test died before it could output anything."); 378 diag("Looks like your test died before it could output anything.");
399 UNLOCK; 379 UNLOCK;
400 return; 380 return;
401 } 381 }
402 382
403 if(test_died) { 383 if (test_died) {
404 diag("Looks like your test died just after %d.", test_count); 384 diag("Looks like your test died just after %d.", test_count);
405 UNLOCK; 385 UNLOCK;
406 return; 386 return;
407 } 387 }
408 388
409
410 /* No plan provided, but now we know how many tests were run, and can 389 /* No plan provided, but now we know how many tests were run, and can
411 print the header at the end */ 390 print the header at the end */
412 if(!skip_all && (no_plan || !have_plan)) { 391 if (!skip_all && (no_plan || !have_plan)) {
413 printf("1..%d\n", test_count); 392 printf("1..%d\n", test_count);
414 } 393 }
415 394
416 if((have_plan && !no_plan) && e_tests < test_count) { 395 if ((have_plan && !no_plan) && e_tests < test_count) {
417 diag("Looks like you planned %d tests but ran %d extra.", 396 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; 397 UNLOCK;
420 return; 398 return;
421 } 399 }
422 400
423 if((have_plan || !no_plan) && e_tests > test_count) { 401 if ((have_plan || !no_plan) && e_tests > test_count) {
424 diag("Looks like you planned %d tests but only ran %d.", 402 diag("Looks like you planned %d tests but only ran %d.", e_tests, test_count);
425 e_tests, test_count);
426 UNLOCK; 403 UNLOCK;
427 return; 404 return;
428 } 405 }
429 406
430 if(failures) 407 if (failures) {
431 diag("Looks like you failed %d tests of %d.", 408 diag("Looks like you failed %d tests of %d.", failures, test_count);
432 failures, test_count); 409 }
433 410
434 UNLOCK; 411 UNLOCK;
435} 412}
diff --git a/tap/tap.h b/tap/tap.h
index 8ee525c8..0c550bfd 100644
--- a/tap/tap.h
+++ b/tap/tap.h
@@ -28,52 +28,51 @@
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) \
38 _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : \ 36 ((e) ? _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) \
39 _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e)) 37 : _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e))
40 38
41# define pass(test, ...) ok(1, test, ## __VA_ARGS__); 39# define pass(test, ...) ok(1, test, ##__VA_ARGS__);
42# define fail(test, ...) ok(0, test, ## __VA_ARGS__); 40# define fail(test, ...) ok(0, test, ##__VA_ARGS__);
43 41
44# define skip_start(test, n, fmt, ...) \ 42# define skip_start(test, n, fmt, ...) \
45 do { \ 43 do { \
46 if((test)) { \ 44 if ((test)) { \
47 skip(n, fmt, ## __VA_ARGS__); \ 45 skip(n, fmt, ##__VA_ARGS__); \
48 continue; \ 46 continue; \
49 } 47 }
50#else /* __GNUC__ */ 48#else /* __GNUC__ */
51/* The original tap.h used to test if __STDC_VERSION__ >= 199901L here. This 49/* The original tap.h used to test if __STDC_VERSION__ >= 199901L here. This
52 * doesn't seem to work on HP-UX even though the code compile fine. I'm not 50 * doesn't seem to work on HP-UX even though the code compile fine. I'm not
53 * sure how to add an exception here for HP-UX so I just removed the check 51 * sure how to add an exception here for HP-UX so I just removed the check
54 * for now */ 52 * for now */
55# define ok(e, ...) ((e) ? \ 53# define ok(e, ...) \
56 _gen_result(1, __func__, __FILE__, __LINE__, \ 54 ((e) ? _gen_result(1, __func__, __FILE__, __LINE__, __VA_ARGS__) \
57 __VA_ARGS__) : \ 55 : _gen_result(0, __func__, __FILE__, __LINE__, __VA_ARGS__))
58 _gen_result(0, __func__, __FILE__, __LINE__, \
59 __VA_ARGS__))
60 56
61# define ok1(e) ((e) ? \ 57# define ok1(e) \
62 _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : \ 58 ((e) ? _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) \
63 _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e)) 59 : _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e))
64 60
65# define pass(...) ok(1, __VA_ARGS__); 61# define pass(...) ok(1, __VA_ARGS__);
66# define fail(...) ok(0, __VA_ARGS__); 62# define fail(...) ok(0, __VA_ARGS__);
67 63
68# define skip_start(test, n, ...) \ 64# define skip_start(test, n, ...) \
69 do { \ 65 do { \
70 if((test)) { \ 66 if ((test)) { \
71 skip(n, __VA_ARGS__); \ 67 skip(n, __VA_ARGS__); \
72 continue; \ 68 continue; \
73 } 69 }
74#endif /* __GNUC__ */ 70#endif /* __GNUC__ */
75 71
76# define skip_end } while(0); 72#define skip_end \
73 } \
74 while (0) \
75 ;
77 76
78unsigned int _gen_result(int, const char *, char *, unsigned int, char *, ...); 77unsigned int _gen_result(int, const char *, char *, unsigned int, char *, ...);
79 78
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/mini_epn.c b/tools/mini_epn.c
index 6f3c5d02..1b09f1c1 100644
--- a/tools/mini_epn.c
+++ b/tools/mini_epn.c
@@ -1,14 +1,14 @@
1/* 1/*
2 * 2 *
3 * MINI_EPN.C - Mini Embedded Perl Nagios 3 * MINI_EPN.C - Mini Embedded Perl Nagios
4 * Contributed by Stanley Hopcroft 4 * Contributed by Stanley Hopcroft
5 * Modified by Douglas Warner 5 * Modified by Douglas Warner
6 * Last Modified: 05/02/2002 6 * Last Modified: 05/02/2002
7 * 7 *
8 * This is a sample mini embedded Perl interpreter (hacked out checks.c and 8 * This is a sample mini embedded Perl interpreter (hacked out checks.c and
9 * perlembed) for use in testing Perl plugins. 9 * perlembed) for use in testing Perl plugins.
10 * 10 *
11 * It can be compiled with the following command (see 'man perlembed' for 11 * It can be compiled with the following command (see 'man perlembed' for
12 * more info): 12 * more info):
13 * 13 *
14 * gcc -omini_epn mini_epn.c `perl -MExtUtils::Embed -e ccopts -e ldopts` 14 * gcc -omini_epn mini_epn.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
@@ -21,7 +21,6 @@
21 * 21 *
22 */ 22 */
23 23
24
25#include <EXTERN.h> 24#include <EXTERN.h>
26#include <perl.h> 25#include <perl.h>
27#include <fcntl.h> 26#include <fcntl.h>
@@ -30,7 +29,7 @@
30/* include PERL xs_init code for module and C library support */ 29/* include PERL xs_init code for module and C library support */
31 30
32#if defined(__cplusplus) 31#if defined(__cplusplus)
33#define is_cplusplus 32# define is_cplusplus
34#endif 33#endif
35 34
36#ifdef is_cplusplus 35#ifdef is_cplusplus
@@ -42,22 +41,20 @@ extern "C" {
42 41
43#ifdef is_cplusplus 42#ifdef is_cplusplus
44} 43}
45# ifndef EXTERN_C 44# ifndef EXTERN_C
46# define EXTERN_C extern "C" 45# define EXTERN_C extern "C"
47# endif 46# endif
48#else 47#else
49# ifndef EXTERN_C 48# ifndef EXTERN_C
50# define EXTERN_C extern 49# define EXTERN_C extern
51# endif 50# endif
52#endif 51#endif
53
54 52
55EXTERN_C void xs_init _((void)); 53EXTERN_C void xs_init _((void));
56 54
57EXTERN_C void boot_DynaLoader _((CV* cv)); 55EXTERN_C void boot_DynaLoader _((CV * cv));
58 56
59EXTERN_C void xs_init(void) 57EXTERN_C void xs_init(void) {
60{
61 char *file = __FILE__; 58 char *file = __FILE__;
62 dXSUB_SYS; 59 dXSUB_SYS;
63 60
@@ -65,85 +62,80 @@ EXTERN_C void xs_init(void)
65 newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file); 62 newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
66} 63}
67 64
68
69static PerlInterpreter *perl = NULL; 65static PerlInterpreter *perl = NULL;
70 66
71 67int main(int argc, char **argv, char **env) {
72int main(int argc, char **argv, char **env) 68 char *embedding[] = {"", "p1.pl"};
73{
74 char *embedding[] = { "", "p1.pl" };
75 char plugin_output[1024]; 69 char plugin_output[1024];
76 char buffer[512]; 70 char buffer[512];
77 char tmpfname[32]; 71 char tmpfname[32];
78 char fname[32]; 72 char fname[32];
79 char *args[] = {"","0", "", "", NULL }; 73 char *args[] = {"", "0", "", "", NULL};
80 FILE *fp; 74 FILE *fp;
81 75
82 const int command_line_size = 160; 76 const int command_line_size = 160;
83 char command_line[command_line_size]; 77 char command_line[command_line_size];
84 char *ap ; 78 char *ap;
85 int exitstatus; 79 int exitstatus;
86 int pclose_result; 80 int pclose_result;
87#ifdef THREADEDPERL 81#ifdef THREADEDPERL
88 dTHX; 82 dTHX;
89#endif 83#endif
90 dSP; 84 dSP;
91 85
92 if ((perl=perl_alloc())==NULL) { 86 if ((perl = perl_alloc()) == NULL) {
93 snprintf(buffer,sizeof(buffer),"Error: Could not allocate memory for embedded Perl interpreter!\n"); 87 snprintf(buffer, sizeof(buffer),
94 buffer[sizeof(buffer)-1]='\x0'; 88 "Error: Could not allocate memory for embedded Perl interpreter!\n");
89 buffer[sizeof(buffer) - 1] = '\x0';
95 printf("%s\n", buffer); 90 printf("%s\n", buffer);
96 exit(1); 91 exit(1);
97 } 92 }
98 perl_construct(perl); 93 perl_construct(perl);
99 exitstatus=perl_parse(perl,xs_init,2,embedding,NULL); 94 exitstatus = perl_parse(perl, xs_init, 2, embedding, NULL);
100 if (!exitstatus) { 95 if (!exitstatus) {
101 96
102 exitstatus=perl_run(perl); 97 exitstatus = perl_run(perl);
103 98
104 while(printf("Enter file name: ") && fgets(command_line, command_line_size, stdin)) { 99 while (printf("Enter file name: ") && fgets(command_line, command_line_size, stdin)) {
105 100
106 /* call the subroutine, passing it the filename as an argument */ 101 /* call the subroutine, passing it the filename as an argument */
107 102
108 command_line[strlen(command_line) -1] = '\0'; 103 command_line[strlen(command_line) - 1] = '\0';
109 104
110 strncpy(fname,command_line,strcspn(command_line," ")); 105 strncpy(fname, command_line, strcspn(command_line, " "));
111 fname[strcspn(command_line," ")] = '\x0'; 106 fname[strcspn(command_line, " ")] = '\x0';
112 args[0] = fname ; 107 args[0] = fname;
113 args[3] = command_line + strlen(fname) + 1 ; 108 args[3] = command_line + strlen(fname) + 1;
114 109
115 /* generate a temporary filename to which stdout can be redirected. */ 110 /* generate a temporary filename to which stdout can be redirected. */
116 sprintf(tmpfname,"/tmp/embedded%d",getpid()); 111 sprintf(tmpfname, "/tmp/embedded%d", getpid());
117 args[2] = tmpfname; 112 args[2] = tmpfname;
118 113
119 /* call our perl interpreter to compile and optionally cache the command */ 114 /* call our perl interpreter to compile and optionally cache the command */
120 perl_call_argv("Embed::Persistent::eval_file", G_DISCARD | G_EVAL, args); 115 perl_call_argv("Embed::Persistent::eval_file", G_DISCARD | G_EVAL, args);
121 116
122 perl_call_argv("Embed::Persistent::run_package", G_DISCARD | G_EVAL, args); 117 perl_call_argv("Embed::Persistent::run_package", G_DISCARD | G_EVAL, args);
123 118
124 /* check return status */ 119 /* check return status */
125 if(SvTRUE(ERRSV)){ 120 if (SvTRUE(ERRSV)) {
126 pclose_result=-2; 121 pclose_result = -2;
127 printf("embedded perl ran %s with error %s\n",fname,SvPV(ERRSV,PL_na)); 122 printf("embedded perl ran %s with error %s\n", fname, SvPV(ERRSV, PL_na));
128 } 123 }
129 124
130 /* read back stdout from script */ 125 /* read back stdout from script */
131 fp=fopen(tmpfname, "r"); 126 fp = fopen(tmpfname, "r");
132 127
133 /* default return string in case nothing was returned */ 128 /* default return string in case nothing was returned */
134 strcpy(plugin_output,"(No output!)"); 129 strcpy(plugin_output, "(No output!)");
135
136 fgets(plugin_output,sizeof(plugin_output)-1,fp);
137 plugin_output[sizeof(plugin_output)-1]='\x0';
138 fclose(fp);
139 unlink(tmpfname);
140 printf("embedded perl plugin output was %d,%s\n",pclose_result, plugin_output);
141 130
131 fgets(plugin_output, sizeof(plugin_output) - 1, fp);
132 plugin_output[sizeof(plugin_output) - 1] = '\x0';
133 fclose(fp);
134 unlink(tmpfname);
135 printf("embedded perl plugin output was %d,%s\n", pclose_result, plugin_output);
142 } 136 }
143
144 } 137 }
145 138
146
147 PL_perl_destruct_level = 0; 139 PL_perl_destruct_level = 0;
148 perl_destruct(perl); 140 perl_destruct(perl);
149 perl_free(perl); 141 perl_free(perl);
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;