summaryrefslogtreecommitdiffstats
path: root/plugins/check_curl.c
diff options
context:
space:
mode:
authorinqrphl <32687873+inqrphl@users.noreply.github.com>2026-03-13 15:54:23 +0100
committerGitHub <noreply@github.com>2026-03-13 15:54:23 +0100
commitb9cd60ec3a2eaa8155286c6b2ee131030f7feec7 (patch)
tree8478cef56f4d3fa04bd727a21ede139ed20e5249 /plugins/check_curl.c
parenta793000948039afa1af9792dd776e2f9cda5b538 (diff)
downloadmonitoring-plugins-b9cd60ec3a2eaa8155286c6b2ee131030f7feec7.tar.gz
add proxy argument and improve dns cache usage (#2209)
* add proxy argument and improve dns cache usage add proxy argument that useing the -x and --proxy argument. add it to the static curl config struct, command usage and help outputs of the cli. parse these argument together with the environment variables like http_proxy before setting the CURLOPT_PROXY in the curl configuration option. this is required, as there is no easy way to ascertain/get what the CURLOPT_PROXY that libcurl will use. by the point it is set by libcurl, we have no control over it anymore, and need it for the other steps in the configuration. if the CURLOPT_PROXY is set, skip the DNS cache population which would set the CURLOPT_RESOLVE. this is currently not perfect however. if a proxy is set with socks4 or socks5 scheme, the host should be resolving the hostname. * codespell, clang-format and hints fixes * add curl version and ssl enabelement macro checks might fix rocky linux 8 compilation issues. * add proxy_resolves_hostname, determined by proxy scheme leave the functions that print out an curl_easyoption, but dont use it. organize the code slightly, print out the final CURLOPT_PROXY and proxy_resolves_hostname flag on verbose mode, add comments * remove unused handle_curl_easyoption and format_curl_easyoption functions * fix typo in the proxy argument * fix typo with proxy scheme socks5a->socks5h * improve proxy environment parsing add another argument: --no-proxy , which is used when setting CURL_NOPROXY additionally parse all_proxy, ALL_PROXY, no_proxy and NO_PROXY environment variables in the correct order. set the curlopt_proxy and curlopt_noproxy of libcurl, and additionally save them in check_curl_working_state. add function determine_hostname_resolver, uses the working state and static config. it can tokenize the no_proxy variable and check for exact matches, but cannot determine subnet matches for ip addresses yet. * document proxy cli arguments clarify and add more examples of proxy environment variables and their behavior when multiple are specified, overriden etc. add single wildcard '*' checking for no_proxy to determine_hostname_resolver, special case per curlopt_noproxy documentation * check curlopt_noproxy before accessing it * switch argument from --no-proxy to --noproxy like curl cli * check if host name is a subdomain of an noproxy item * use strdup where destination working_state.curlopt_proxy may be NULL * add disclaimer about uppercase HTTP_PROXY * add subdomain checks for each item in the no_proxy, if the target host is a subdomain proxy wont resolve it add function ip_addr_inside_cidr, use it for checking possible cidr ranges given in the no_proxy * wip tests that work on local perl http/https server * wip tests that work on the live debian image * fix subnet definition * make apache2 listen on [::1] for ipv6 tests * remove squid certificate * rewrite ip_addr_inside_cidr, split ipv4 and ipv6 parsing path and copy them to a shared buffer later on for prefix check * Adapt tests for the squid sever, disable checking return code for socks 4/5 proxies. Squid does not support it, and we do not install a capable proxy for these schemes. * specify localhost acl and allow it through the proxy. used in check_curl tests * typo in comment * move function comments to header * fix failing tests * handle case where proxy is set as empty string * removed duplicate tests, corrected wrong comments * corrected some annotations * move docker apache subdomain setup files to /tools/subdomain1 * add a newline before dying in handle_curl_option_return_code * fix the -ssl better, now does not segfault on empty --ssl argument as well. --------- Co-authored-by: Ahmet Oeztuerk <Ahmet.Oeztuerk@consol.de>
Diffstat (limited to 'plugins/check_curl.c')
-rw-r--r--plugins/check_curl.c91
1 files changed, 72 insertions, 19 deletions
diff --git a/plugins/check_curl.c b/plugins/check_curl.c
index d7d68de5..4a1fb647 100644
--- a/plugins/check_curl.c
+++ b/plugins/check_curl.c
@@ -874,7 +874,8 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
874 COOKIE_JAR, 874 COOKIE_JAR,
875 HAPROXY_PROTOCOL, 875 HAPROXY_PROTOCOL,
876 STATE_REGEX, 876 STATE_REGEX,
877 OUTPUT_FORMAT 877 OUTPUT_FORMAT,
878 NO_PROXY,
878 }; 879 };
879 880
880 static struct option longopts[] = { 881 static struct option longopts[] = {
@@ -889,6 +890,8 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
889 {"url", required_argument, 0, 'u'}, 890 {"url", required_argument, 0, 'u'},
890 {"port", required_argument, 0, 'p'}, 891 {"port", required_argument, 0, 'p'},
891 {"authorization", required_argument, 0, 'a'}, 892 {"authorization", required_argument, 0, 'a'},
893 {"proxy", required_argument, 0, 'x'},
894 {"noproxy", required_argument, 0, NO_PROXY},
892 {"proxy-authorization", required_argument, 0, 'b'}, 895 {"proxy-authorization", required_argument, 0, 'b'},
893 {"header-string", required_argument, 0, 'd'}, 896 {"header-string", required_argument, 0, 'd'},
894 {"string", required_argument, 0, 's'}, 897 {"string", required_argument, 0, 's'},
@@ -961,7 +964,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
961 964
962 while (true) { 965 while (true) {
963 int option_index = getopt_long( 966 int option_index = getopt_long(
964 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", 967 argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:x:b:d:e:p:s:R:r:u:f:C:J:K:DnlLS::m:M:NEB",
965 longopts, &option); 968 longopts, &option);
966 if (option_index == -1 || option_index == EOF || option_index == 1) { 969 if (option_index == -1 || option_index == EOF || option_index == 1) {
967 break; 970 break;
@@ -1049,6 +1052,10 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
1049 strncpy(result.config.curl_config.user_auth, optarg, MAX_INPUT_BUFFER - 1); 1052 strncpy(result.config.curl_config.user_auth, optarg, MAX_INPUT_BUFFER - 1);
1050 result.config.curl_config.user_auth[MAX_INPUT_BUFFER - 1] = 0; 1053 result.config.curl_config.user_auth[MAX_INPUT_BUFFER - 1] = 0;
1051 break; 1054 break;
1055 case 'x': /* proxy info */
1056 strncpy(result.config.curl_config.proxy, optarg, DEFAULT_BUFFER_SIZE - 1);
1057 result.config.curl_config.proxy[DEFAULT_BUFFER_SIZE - 1] = 0;
1058 break;
1052 case 'b': /* proxy-authorization info */ 1059 case 'b': /* proxy-authorization info */
1053 strncpy(result.config.curl_config.proxy_auth, optarg, MAX_INPUT_BUFFER - 1); 1060 strncpy(result.config.curl_config.proxy_auth, optarg, MAX_INPUT_BUFFER - 1);
1054 result.config.curl_config.proxy_auth[MAX_INPUT_BUFFER - 1] = 0; 1061 result.config.curl_config.proxy_auth[MAX_INPUT_BUFFER - 1] = 0;
@@ -1344,6 +1351,10 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
1344 case HAPROXY_PROTOCOL: 1351 case HAPROXY_PROTOCOL:
1345 result.config.curl_config.haproxy_protocol = true; 1352 result.config.curl_config.haproxy_protocol = true;
1346 break; 1353 break;
1354 case NO_PROXY:
1355 strncpy(result.config.curl_config.no_proxy, optarg, DEFAULT_BUFFER_SIZE - 1);
1356 result.config.curl_config.no_proxy[DEFAULT_BUFFER_SIZE - 1] = 0;
1357 break;
1347 case '?': 1358 case '?':
1348 /* print short usage statement if args not parsable */ 1359 /* print short usage statement if args not parsable */
1349 usage5(); 1360 usage5();
@@ -1371,35 +1382,35 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
1371 * parameters, like -S and -C combinations */ 1382 * parameters, like -S and -C combinations */
1372 result.config.curl_config.ssl_version = CURL_SSLVERSION_DEFAULT; 1383 result.config.curl_config.ssl_version = CURL_SSLVERSION_DEFAULT;
1373 if (tls_option_optarg != NULL) { 1384 if (tls_option_optarg != NULL) {
1374 char *plus_ptr = strchr(optarg, '+'); 1385 char *plus_ptr = strchr(tls_option_optarg, '+');
1375 if (plus_ptr) { 1386 if (plus_ptr) {
1376 got_plus = true; 1387 got_plus = true;
1377 *plus_ptr = '\0'; 1388 *plus_ptr = '\0';
1378 } 1389 }
1379 1390
1380 if (optarg[0] == '2') { 1391 if (tls_option_optarg[0] == '2') {
1381 result.config.curl_config.ssl_version = CURL_SSLVERSION_SSLv2; 1392 result.config.curl_config.ssl_version = CURL_SSLVERSION_SSLv2;
1382 } else if (optarg[0] == '3') { 1393 } else if (tls_option_optarg[0] == '3') {
1383 result.config.curl_config.ssl_version = CURL_SSLVERSION_SSLv3; 1394 result.config.curl_config.ssl_version = CURL_SSLVERSION_SSLv3;
1384 } else if (!strcmp(optarg, "1") || !strcmp(optarg, "1.0")) { 1395 } else if (!strcmp(tls_option_optarg, "1") || !strcmp(tls_option_optarg, "1.0")) {
1385#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1396#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1386 result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_0; 1397 result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_0;
1387#else 1398#else
1388 result.config.ssl_version = CURL_SSLVERSION_DEFAULT; 1399 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1389#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1400#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1390 } else if (!strcmp(optarg, "1.1")) { 1401 } else if (!strcmp(tls_option_optarg, "1.1")) {
1391#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1402#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1392 result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_1; 1403 result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_1;
1393#else 1404#else
1394 result.config.ssl_version = CURL_SSLVERSION_DEFAULT; 1405 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1395#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1406#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1396 } else if (!strcmp(optarg, "1.2")) { 1407 } else if (!strcmp(tls_option_optarg, "1.2")) {
1397#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1408#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1398 result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_2; 1409 result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_2;
1399#else 1410#else
1400 result.config.ssl_version = CURL_SSLVERSION_DEFAULT; 1411 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1401#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1412#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1402 } else if (!strcmp(optarg, "1.3")) { 1413 } else if (!strcmp(tls_option_optarg, "1.3")) {
1403#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) 1414#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0)
1404 result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_3; 1415 result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_3;
1405#else 1416#else
@@ -1522,8 +1533,8 @@ void print_help(void) {
1522 printf(" %s\n", "-I, --IP-address=ADDRESS"); 1533 printf(" %s\n", "-I, --IP-address=ADDRESS");
1523 printf(" %s\n", 1534 printf(" %s\n",
1524 "IP address or name (use numeric address if possible to bypass DNS lookup)."); 1535 "IP address or name (use numeric address if possible to bypass DNS lookup).");
1525 printf(" %s\n", "This overwrites the network address of the target while leaving everything " 1536 printf(" %s\n",
1526 "else (HTTP headers) as they are"); 1537 "This overwrites the network address of the target while leaving everything else (HTTP headers) as they are");
1527 printf(" %s\n", "-p, --port=INTEGER"); 1538 printf(" %s\n", "-p, --port=INTEGER");
1528 printf(" %s", _("Port number (default: ")); 1539 printf(" %s", _("Port number (default: "));
1529 printf("%d)\n", HTTP_PORT); 1540 printf("%d)\n", HTTP_PORT);
@@ -1587,8 +1598,7 @@ void print_help(void) {
1587 printf(" %s\n", _("String to expect in the content")); 1598 printf(" %s\n", _("String to expect in the content"));
1588 printf(" %s\n", "-u, --url=PATH"); 1599 printf(" %s\n", "-u, --url=PATH");
1589 printf(" %s\n", _("URL to GET or POST (default: /)")); 1600 printf(" %s\n", _("URL to GET or POST (default: /)"));
1590 printf(" %s\n", _("This is the part after the address in a URL, so for " 1601 printf(" %s\n", _("This is the part after the address in a URL, so for \"https://example.com/index.html\" it would be '-u /index.html'"));
1591 "\"https://example.com/index.html\" it would be '-u /index.html'"));
1592 printf(" %s\n", "-P, --post=STRING"); 1602 printf(" %s\n", "-P, --post=STRING");
1593 printf(" %s\n", _("URL decoded http POST data")); 1603 printf(" %s\n", _("URL decoded http POST data"));
1594 printf(" %s\n", 1604 printf(" %s\n",
@@ -1614,6 +1624,18 @@ void print_help(void) {
1614 printf(" %s\n", "--state-regex=STATE"); 1624 printf(" %s\n", "--state-regex=STATE");
1615 printf(" %s\n", _("Return STATE if regex is found, OK if not. STATE can be one of " 1625 printf(" %s\n", _("Return STATE if regex is found, OK if not. STATE can be one of "
1616 "\"critical\",\"warning\"")); 1626 "\"critical\",\"warning\""));
1627 printf(" %s\n", "-x, --proxy=PROXY_SERVER");
1628 printf(" %s\n", _("Specify the proxy in form of <scheme>://<host(name)>:<port>"));
1629 printf(" %s\n", _("Available schemes are http, https, socks4, socks4a, socks5, socks5h"));
1630 printf(" %s\n", _("If port is not specified, libcurl defaults to 1080"));
1631 printf(" %s\n", _("This value will be set as CURLOPT_PROXY"));
1632 printf(" %s\n", "--noproxy=COMMA_SEPARATED_LIST");
1633 printf(" %s\n", _("Specify hostnames, addresses and subnets where proxy should not be used"));
1634 printf(" %s\n", _("Example usage: \"example.com,::1,1.1.1.1,localhost,192.168.0.0/16\""));
1635 printf(" %s\n", _("Do not use brackets when specifying IPv6 addresses"));
1636 printf(" %s\n", _("Special case when an item is '*' : matches all hosts/addresses "
1637 "and effectively disables proxy."));
1638 printf(" %s\n", _("This value will be set as CURLOPT_NOPROXY"));
1617 printf(" %s\n", "-a, --authorization=AUTH_PAIR"); 1639 printf(" %s\n", "-a, --authorization=AUTH_PAIR");
1618 printf(" %s\n", _("Username:password on sites with basic authentication")); 1640 printf(" %s\n", _("Username:password on sites with basic authentication"));
1619 printf(" %s\n", "-b, --proxy-authorization=AUTH_PAIR"); 1641 printf(" %s\n", "-b, --proxy-authorization=AUTH_PAIR");
@@ -1722,10 +1744,39 @@ void print_help(void) {
1722#endif 1744#endif
1723 1745
1724 printf("\n %s\n", "CHECK WEBSERVER CONTENT VIA PROXY:"); 1746 printf("\n %s\n", "CHECK WEBSERVER CONTENT VIA PROXY:");
1725 printf(" %s\n", _("It is recommended to use an environment proxy like:")); 1747 printf(" %s\n", _("Proxies are specified or disabled for certain hosts/addresses using environment variables"
1726 printf(" %s\n", 1748 " or -x/--proxy and --noproxy arguments:"));
1727 _("http_proxy=http://192.168.100.35:3128 ./check_curl -H www.monitoring-plugins.org")); 1749 printf(" %s\n", _("Checked environment variables: all_proxy, http_proxy, https_proxy, no_proxy"));
1728 printf(" %s\n", _("legacy proxy requests in check_http style still work:")); 1750 printf(" %s\n", _("Environment variables can also be given in uppercase, but the lowercase ones will "
1751 "take predence if both are defined."));
1752 printf(" %s\n", _("The environment variables are overwritten by -x/--proxy and --noproxy arguments:"));
1753 printf(" %s\n", _("all_proxy/ALL_PROXY environment variables are read first, but protocol "
1754 "specific environment variables override them."));
1755 printf(" %s\n", _("If SSL is enabled and used, https_proxy/HTTPS_PROXY will be checked and overwrite "
1756 "http_proxy/HTTPS_PROXY."));
1757 printf(" %s\n", _("Curl accepts proxies using http, https, socks4, socks4a, socks5 and socks5h schemes."));
1758 printf(" %s\n", _("http_proxy=http://192.168.100.35:3128 ./check_curl -H www.monitoring-plugins.org"));
1759 printf(" %s\n", _("http_proxy=http://used.proxy.com HTTP_PROXY=http://ignored.proxy.com ./check_curl -H www.monitoring-plugins.org"));
1760 printf(" %s\n", _(" Lowercase http_proxy takes predence over uppercase HTTP_PROXY"));
1761 printf(" %s\n", _("./check_curl -H www.monitoring-plugins.org -x http://192.168.100.35:3128"));
1762 printf(" %s\n", _("http_proxy=http://unused.proxy1.com HTTP_PROXY=http://unused.proxy2.com ./check_curl "
1763 "-H www.monitoring-plugins.org --proxy http://used.proxy"));
1764 printf(" %s\n", _(" Proxy specified by --proxy overrides any proxy specified by environment variable."));
1765 printf(" %s\n", _(" Curl uses port 1080 by default as port is not specified"));
1766 printf(" %s\n", _("HTTPS_PROXY=http://192.168.100.35:3128 ./check_curl -H www.monitoring-plugins.org --ssl"));
1767 printf(" %s\n", _(" HTTPS_PROXY is read as --ssl is toggled"));
1768 printf(" %s\n", _("./check_curl -H www.monitoring-plugins.org --proxy socks5h://192.168.122.21"));
1769 printf(" %s\n", _("./check_curl -H www.monitoring-plugins.org -x http://unused.proxy.com --noproxy '*'"));
1770 printf(" %s\n", _(" Disabled proxy for all hosts by using '*' in no_proxy ."));
1771 printf(" %s\n", _("NO_PROXY=www.monitoring-plugins.org ./check_curl -H www.monitoring-plugins.org -x http://unused.proxy.com"));
1772 printf(" %s\n", _(" Exact matches with the hostname/address work."));
1773 printf(" %s\n", _("no_proxy=192.168.178.0/24 ./check_curl -I 192.168.178.10 -x http://proxy.acme.org"));
1774 printf(" %s\n", _("no_proxy=acme.org ./check_curl -H nonpublic.internalwebapp.acme.org -x http://proxy.acme.org"));
1775 printf(" %s\n", _(" Do not use proxy when accessing internal domains/addresses, but use a default proxy when accessing public web."));
1776 printf(" %s\n", _(" IMPORTANT: Check_curl can not always determine whether itself or the proxy will "
1777 "resolve a hostname before sending a request and getting an answer."
1778 "This can lead to DNS resolvation issues if hostname is only resolvable over proxy."));
1779 printf(" %s\n", _("Legacy proxy requests in check_http style still work:"));
1729 printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u http://www.monitoring-plugins.org/ " 1780 printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u http://www.monitoring-plugins.org/ "
1730 "-H www.monitoring-plugins.org")); 1781 "-H www.monitoring-plugins.org"));
1731 1782
@@ -1756,13 +1807,15 @@ void print_usage(void) {
1756 printf(" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n", progname); 1807 printf(" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n", progname);
1757 printf(" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate " 1808 printf(" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate "
1758 "file>] [-D]\n"); 1809 "file>] [-D]\n");
1759 printf(" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n"); 1810 printf(" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-x <proxy>]\n");
1760 printf(" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport|curl>]\n"); 1811 printf(" [-a auth] [-b proxy_auth] [-f "
1812 "<ok|warning|critical|follow|sticky|stickyport|curl>]\n");
1761 printf(" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive " 1813 printf(" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive "
1762 "regex>]\n"); 1814 "regex>]\n");
1763 printf(" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n"); 1815 printf(" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
1764 printf(" [-A string] [-k string] [-S <version>] [--sni] [--haproxy-protocol]\n"); 1816 printf(" [-A string] [-k string] [-S <version>] [--sni] [--haproxy-protocol]\n");
1765 printf(" [-T <content-type>] [-j method]\n"); 1817 printf(" [-T <content-type>] [-j method]\n");
1818 printf(" [--noproxy=<comma separated list of hosts, IP addresses, IP CIDR subnets>\n");
1766 printf(" [--http-version=<version>] [--enable-automatic-decompression]\n"); 1819 printf(" [--http-version=<version>] [--enable-automatic-decompression]\n");
1767 printf(" [--cookie-jar=<cookie jar file>\n"); 1820 printf(" [--cookie-jar=<cookie jar file>\n");
1768 printf(" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n", progname); 1821 printf(" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n", progname);