master-service.h revision 541f258d86b2db26efd5670883966183b4fb6323
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina#ifndef MASTER_SERVICE_H
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina#define MASTER_SERVICE_H
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina#include "net.h"
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina#include <unistd.h> /* for getopt() opt* variables */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina#include <stdio.h> /* for getopt() opt* variables in Solaris */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinaenum master_service_flags {
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* stdin/stdout already contains a client which we want to serve */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina MASTER_SERVICE_FLAG_STD_CLIENT = 0x01,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* this process is currently running standalone without a master */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina MASTER_SERVICE_FLAG_STANDALONE = 0x02,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* Log to configured log file instead of stderr. By default when
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina _FLAG_STANDALONE is set, logging is done to stderr. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina MASTER_SERVICE_FLAG_DONT_LOG_TO_STDERR = 0x04,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* Service is going to do multiple configuration lookups,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina keep the connection to config service open. Also opens the config
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina socket before dropping privileges. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina MASTER_SERVICE_FLAG_KEEP_CONFIG_OPEN = 0x08,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* Don't read settings, but use whatever is in environment */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS = 0x10,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* Use MASTER_LOGIN_NOTIFY_FD to track login overflow state */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina MASTER_SERVICE_FLAG_TRACK_LOGIN_STATE = 0x40,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* If master sends SIGINT, don't die even if we don't have clients */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina MASTER_SERVICE_FLAG_NO_IDLE_DIE = 0x80,
e880949305cee3aca79441fe6113a9d79e7c98f2Jakub Hrozek /* Show number of connections in process title
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina (only if verbose_proctitle setting is enabled) */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina MASTER_SERVICE_FLAG_UPDATE_PROCTITLE = 0x100,
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac /* SSL settings are always looked up when we have ssl listeners.
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina This flag enables looking up SSL settings even without ssl
769347ad4d35d43488eb98f980143495b0db415dStef Walter listeners (i.e. the service does STARTTLS). */
769347ad4d35d43488eb98f980143495b0db415dStef Walter MASTER_SERVICE_FLAG_USE_SSL_SETTINGS = 0x200,
769347ad4d35d43488eb98f980143495b0db415dStef Walter /* Don't initialize SSL context automatically. */
769347ad4d35d43488eb98f980143495b0db415dStef Walter MASTER_SERVICE_FLAG_NO_SSL_INIT = 0x400,
769347ad4d35d43488eb98f980143495b0db415dStef Walter /* Don't create a data stack frame between master_service_init() and
769347ad4d35d43488eb98f980143495b0db415dStef Walter master_service_init_finish(). By default this is done to make sure
769347ad4d35d43488eb98f980143495b0db415dStef Walter initialization doesn't unnecessarily use up memory in data stack. */
769347ad4d35d43488eb98f980143495b0db415dStef Walter MASTER_SERVICE_FLAG_NO_INIT_DATASTACK_FRAME = 0x800
b76419cf8830440b46c20a15585562343c7b1924Jakub Hrozek};
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinastruct master_service_connection {
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* fd of the new connection. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina int fd;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* fd of the socket listener. Same as fd for a FIFO. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina int listen_fd;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* listener name as in configuration file, or "" if unnamed. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina const char *name;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* Original client/server IP/port. Both of these may have been changed
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina by the haproxy protocol. */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov struct ip_addr remote_ip, local_ip;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina in_port_t remote_port, local_port;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
83a79d93035c2d75a1941f3b54426119174044a0Pavel Březina /* The real client/server IP/port, unchanged by haproxy protocol. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina struct ip_addr real_remote_ip, real_local_ip;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina in_port_t real_remote_port, real_local_port;
65976ea5e9767bfaced81dfb97dc87d59f50b57eSimo Sorce
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* This is a FIFO fd. Only a single "connection" is ever received from
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina a FIFO after the first writer sends something to it. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina bool fifo:1;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* Perform immediate SSL handshake for this connection. Currently this
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina needs to be performed explicitly by each service. */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov bool ssl:1;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* Internal: master_service_client_connection_accept() has been
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina called for this connection. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina bool accepted:1;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina};
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinatypedef void
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březinamaster_service_connection_callback_t(struct master_service_connection *conn);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinaextern struct master_service *master_service;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinaconst char *master_service_getopt_string(void);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina/* Start service initialization. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinastruct master_service *
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březinamaster_service_init(const char *name, enum master_service_flags flags,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina int *argc, char **argv[], const char *getopt_str);
8bccd95e275fae760a991da394235e4e70e57bbdMichal Zidek/* Call getopt() and handle internal parameters. Return values are the same as
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina getopt()'s. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinaint master_getopt(struct master_service *service);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina/* Returns TRUE if str is a valid getopt_str. Currently this only checks for
07e941c1bbdc752142bbd3b838c540bc7ecd0ed7Stef Walter duplicate args so they aren't accidentally added. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinabool master_getopt_str_is_valid(const char *str);
04e870d99e72aa3160bdb6ab05d986fb4005c3edPavel Březina/* Parser command line option. Returns TRUE if processed. */
4f3a9d837a55b49448eca3c713c85a406207e523Simo Sorcebool master_service_parse_option(struct master_service *service,
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina int opt, const char *arg);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina/* Finish service initialization. The caller should drop privileges
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov before calling this. This also notifies the master that the service was
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina successfully started and there shouldn't be any service throttling even if
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina it crashes afterwards, so this should be called after all of the
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina initialization code is finished. */
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březinavoid master_service_init_finish(struct master_service *service);
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov/* Clean environment from everything except the ones listed in
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina DOVECOT_PRESERVE_ENVS environment. */
6f8ae17869f4f8a1496e3f171ae6b5c11af1845cPavel Březinavoid master_service_env_clean(void);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina/* Initialize logging. */
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březinavoid master_service_init_log(struct master_service *service,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina const char *prefix);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
e3bb7b3fda4697fa9c6f80107cd01dd04a20c85fPetr Cech/* If set, die immediately when connection to master is lost.
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac Normally all existing clients are handled first. */
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkacvoid master_service_set_die_with_master(struct master_service *service,
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac bool set);
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac/* Call the given when master connection dies and die_with_master is TRUE.
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac The callback is expected to shut down the service somewhat soon or it's
2a25713afc6beefb11a799903a43f695c5d7a4f9Adam Tkac done forcibly. If NULL, the service is stopped immediately. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinavoid master_service_set_die_callback(struct master_service *service,
3bea01f01d76e1e95a8239c0d3f67073992136a1Jan Zeleny void (*callback)(void));
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina/* "idle callback" is called when master thinks we're idling and asks us to
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina die. We'll do it only if the idle callback returns TRUE. This callback isn't
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina even called if the master service code knows that we're handling clients. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinavoid master_service_set_idle_die_callback(struct master_service *service,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina bool (*callback)(void));
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov/* Call the given callback when there are no available connections and master
6f8ae17869f4f8a1496e3f171ae6b5c11af1845cPavel Březina has indicated that it can't create any more processes to handle requests.
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina The callback could decide to kill one of the existing connections. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinavoid master_service_set_avail_overflow_callback(struct master_service *service,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina void (*callback)(void));
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina/* Set maximum number of clients we can handle. Default is given by master. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinavoid master_service_set_client_limit(struct master_service *service,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina unsigned int client_limit);
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina/* Returns the maximum number of clients we can handle. */
3bea01f01d76e1e95a8239c0d3f67073992136a1Jan Zelenyunsigned int master_service_get_client_limit(struct master_service *service);
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina/* Returns how many processes of this type can be created before reaching the
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina limit. */
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březinaunsigned int master_service_get_process_limit(struct master_service *service);
52e3ee5c5ff2c5a4341041826a803ad42d2b2de7Pavel Březina/* Returns service { process_min_avail } */
52e3ee5c5ff2c5a4341041826a803ad42d2b2de7Pavel Březinaunsigned int master_service_get_process_min_avail(struct master_service *service);
52e3ee5c5ff2c5a4341041826a803ad42d2b2de7Pavel Březina/* Returns the service's idle_kill timeout in seconds. Normally master handles
52e3ee5c5ff2c5a4341041826a803ad42d2b2de7Pavel Březina sending the kill request when the process has no clients, but some services
52e3ee5c5ff2c5a4341041826a803ad42d2b2de7Pavel Březina with permanent client connections may need to handle this themselves. */
52e3ee5c5ff2c5a4341041826a803ad42d2b2de7Pavel Březinaunsigned int master_service_get_idle_kill_secs(struct master_service *service);
52e3ee5c5ff2c5a4341041826a803ad42d2b2de7Pavel Březina
52e3ee5c5ff2c5a4341041826a803ad42d2b2de7Pavel Březina/* Set maximum number of client connections we will handle before shutting
52e3ee5c5ff2c5a4341041826a803ad42d2b2de7Pavel Březina down. */
52e3ee5c5ff2c5a4341041826a803ad42d2b2de7Pavel Březinavoid master_service_set_service_count(struct master_service *service,
52e3ee5c5ff2c5a4341041826a803ad42d2b2de7Pavel Březina unsigned int count);
a5f300adf19ec9c3087c62bd93a5175db799687aPavel Březina/* Returns the number of client connections we will handle before shutting
a5f300adf19ec9c3087c62bd93a5175db799687aPavel Březina down. The value is decreased only after connection has been closed. */
a5f300adf19ec9c3087c62bd93a5175db799687aPavel Březinaunsigned int master_service_get_service_count(struct master_service *service);
a5f300adf19ec9c3087c62bd93a5175db799687aPavel Březina/* Return the number of listener sockets. */
a5f300adf19ec9c3087c62bd93a5175db799687aPavel Březinaunsigned int master_service_get_socket_count(struct master_service *service);
a5f300adf19ec9c3087c62bd93a5175db799687aPavel Březina/* Returns the name of the listener socket, or "" if none is specified. */
a5f300adf19ec9c3087c62bd93a5175db799687aPavel Březinaconst char *master_service_get_socket_name(struct master_service *service,
a5f300adf19ec9c3087c62bd93a5175db799687aPavel Březina int listen_fd);
a5f300adf19ec9c3087c62bd93a5175db799687aPavel Březina
a5f300adf19ec9c3087c62bd93a5175db799687aPavel Březina/* Returns configuration file path. */
a5f300adf19ec9c3087c62bd93a5175db799687aPavel Březinaconst char *master_service_get_config_path(struct master_service *service);
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina/* Returns PACKAGE_VERSION or NULL if version_ignore=yes. This function is
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov useful mostly as parameter to module_dir_load(). */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashovconst char *master_service_get_version_string(struct master_service *service);
6f8ae17869f4f8a1496e3f171ae6b5c11af1845cPavel Březina/* Returns name of the service, as given in name parameter to _init(). */
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březinaconst char *master_service_get_name(struct master_service *service);
c9aab1c04c399ca2d1abef74f6df22ced34983dcPavel Březina
0528fdec17d0031996e919fcd852459e86592c35Jakub Hrozek/* Start the service. Blocks until finished */
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bosevoid master_service_run(struct master_service *service,
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov master_service_connection_callback_t *callback)
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose ATTR_NULL(2);
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bose/* Stop a running service. */
909a86af4eb99f5d311d7136cab78dca535ae304Sumit Bosevoid master_service_stop(struct master_service *service);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov/* Stop once we're done serving existing new connections, but don't accept
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina any new ones. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinavoid master_service_stop_new_connections(struct master_service *service);
6f8ae17869f4f8a1496e3f171ae6b5c11af1845cPavel Březina/* Returns TRUE if we've received a SIGINT/SIGTERM and we've decided to stop. */
6f8ae17869f4f8a1496e3f171ae6b5c11af1845cPavel Březinabool master_service_is_killed(struct master_service *service);
7c9fe57ad82747a32721ca0a08c5569282f3e0c4Pavel Březina/* Returns TRUE if our master process is already stopped. This process may or
6f8ae17869f4f8a1496e3f171ae6b5c11af1845cPavel Březina may not be dying itself. Returns FALSE always if the process was started
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina standalone. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinabool master_service_is_master_stopped(struct master_service *service);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina/* Send command to anvil process, if we have fd to it. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinavoid master_service_anvil_send(struct master_service *service, const char *cmd);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina/* Call to accept the client connection. Otherwise the connection is closed. */
cb75b275d15beedd1fdecc1f8ced657fba282218Lukas Slebodnikvoid master_service_client_connection_accept(struct master_service_connection *conn);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina/* Used to create "extra client connections" outside the common accept()
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina method. */
ac40d2f2b2b2fc35c95389f5e28febd580bd2b7aJakub Hrozekvoid master_service_client_connection_created(struct master_service *service);
ac40d2f2b2b2fc35c95389f5e28febd580bd2b7aJakub Hrozek/* Call whenever a client connection is destroyed. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinavoid master_service_client_connection_destroyed(struct master_service *service);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina/* Deinitialize the service. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinavoid master_service_deinit(struct master_service **service);
cb75b275d15beedd1fdecc1f8ced657fba282218Lukas Slebodnik
ac40d2f2b2b2fc35c95389f5e28febd580bd2b7aJakub Hrozek/* Returns TRUE if line contains compatible service name and major version.
f37e795cd16310759dc9741c1ab1323b287a9101Fabiano Fidêncio The line is expected to be in format:
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina VERSION <tab> service_name <tab> major version <tab> minor version */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinabool version_string_verify(const char *line, const char *service_name,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina unsigned major_version);
677a31351c80453d9ce006481364399a96312052René Genz/* Same as version_string_verify(), but return the minor version. */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březinabool version_string_verify_full(const char *line, const char *service_name,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina unsigned major_version,
458f5245dd5130d12666cce6faf8ef1ec7f80169Pavel Reichl unsigned int *minor_version_r);
458f5245dd5130d12666cce6faf8ef1ec7f80169Pavel Reichl
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina#endif
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina