#define USE_THE_REPOSITORY_VARIABLE
#include "git-compat-util.h"
#include "abspath.h"
#include "config.h"
#include "environment.h"
#include "gettext.h"
#include "path.h"
#include "pkt-line.h"
#include "protocol.h"
#include "run-command.h"
#include "setup.h"
#include "strbuf.h"
#include "string-list.h"
#ifdef NO_INITGROUPS
#define initgroups …
#endif
static enum log_destination { … } log_destination = …;
static int verbose;
static int reuseaddr;
static int informative_errors;
static const char daemon_usage[] = …;
static const char **ok_paths;
static int strict_paths;
static int export_all_trees;
static const char *base_path;
static const char *interpolated_path;
static int base_path_relaxed;
static const char *user_path;
static unsigned int timeout;
static unsigned int init_timeout;
struct hostinfo { … };
#define HOSTINFO_INIT …
static void lookup_hostname(struct hostinfo *hi);
static const char *get_canon_hostname(struct hostinfo *hi)
{ … }
static const char *get_ip_address(struct hostinfo *hi)
{ … }
static void logreport(int priority, const char *err, va_list params)
{ … }
__attribute__((format (printf, 1, 2)))
static void logerror(const char *err, ...)
{ … }
__attribute__((format (printf, 1, 2)))
static void loginfo(const char *err, ...)
{ … }
static void NORETURN daemon_die(const char *err, va_list params)
{ … }
static const char *path_ok(const char *directory, struct hostinfo *hi)
{ … }
daemon_service_fn;
struct daemon_service { … };
static int daemon_error(const char *dir, const char *msg)
{ … }
static const char *access_hook;
static int run_access_hook(struct daemon_service *service, const char *dir,
const char *path, struct hostinfo *hi)
{ … }
static int run_service(const char *dir, struct daemon_service *service,
struct hostinfo *hi, const struct strvec *env)
{ … }
static void copy_to_log(int fd)
{ … }
static int run_service_command(struct child_process *cld)
{ … }
static int upload_pack(const struct strvec *env)
{ … }
static int upload_archive(const struct strvec *env)
{ … }
static int receive_pack(const struct strvec *env)
{ … }
static struct daemon_service daemon_service[] = …;
static void enable_service(const char *name, int ena)
{ … }
static void make_service_overridable(const char *name, int ena)
{ … }
static void parse_host_and_port(char *hostport, char **host,
char **port)
{ … }
static void sanitize_client(struct strbuf *out, const char *in)
{ … }
static void canonicalize_client(struct strbuf *out, const char *in)
{ … }
static char *parse_host_arg(struct hostinfo *hi, char *extra_args, int buflen)
{ … }
static void parse_extra_args(struct hostinfo *hi, struct strvec *env,
char *extra_args, int buflen)
{ … }
static void lookup_hostname(struct hostinfo *hi)
{ … }
static void hostinfo_clear(struct hostinfo *hi)
{ … }
static void set_keep_alive(int sockfd)
{ … }
static int execute(void)
{ … }
static int addrcmp(const struct sockaddr_storage *s1,
const struct sockaddr_storage *s2)
{ … }
static int max_connections = …;
static unsigned int live_children;
static struct child { … } *firstborn;
static void add_child(struct child_process *cld, struct sockaddr *addr, socklen_t addrlen)
{ … }
static void kill_some_child(void)
{ … }
static void check_dead_children(void)
{ … }
static struct strvec cld_argv = …;
static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
{ … }
static void child_handler(int signo UNUSED)
{ … }
static int set_reuse_addr(int sockfd)
{ … }
struct socketlist { … };
static const char *ip2str(int family, struct sockaddr *sin, socklen_t len)
{ … }
#ifndef NO_IPV6
static int setup_named_sock(char *listen_addr, int listen_port, struct socketlist *socklist)
{ … }
#else
static int setup_named_sock(char *listen_addr, int listen_port, struct socketlist *socklist)
{
struct sockaddr_in sin;
int sockfd;
long flags;
memset(&sin, 0, sizeof sin);
sin.sin_family = AF_INET;
sin.sin_port = htons(listen_port);
if (listen_addr) {
if (inet_pton(AF_INET, listen_addr, &sin.sin_addr.s_addr) <= 0)
return 0;
} else {
sin.sin_addr.s_addr = htonl(INADDR_ANY);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
return 0;
if (set_reuse_addr(sockfd)) {
logerror("Could not set SO_REUSEADDR: %s", strerror(errno));
close(sockfd);
return 0;
}
set_keep_alive(sockfd);
if ( bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0 ) {
logerror("Could not bind to %s: %s",
ip2str(AF_INET, (struct sockaddr *)&sin, sizeof(sin)),
strerror(errno));
close(sockfd);
return 0;
}
if (listen(sockfd, 5) < 0) {
logerror("Could not listen to %s: %s",
ip2str(AF_INET, (struct sockaddr *)&sin, sizeof(sin)),
strerror(errno));
close(sockfd);
return 0;
}
flags = fcntl(sockfd, F_GETFD, 0);
if (flags >= 0)
fcntl(sockfd, F_SETFD, flags | FD_CLOEXEC);
ALLOC_GROW(socklist->list, socklist->nr + 1, socklist->alloc);
socklist->list[socklist->nr++] = sockfd;
return 1;
}
#endif
static void socksetup(struct string_list *listen_addr, int listen_port, struct socketlist *socklist)
{ … }
static int service_loop(struct socketlist *socklist)
{ … }
#ifdef NO_POSIX_GOODIES
struct credentials;
static void drop_privileges(struct credentials *cred UNUSED)
{
}
static struct credentials *prepare_credentials(const char *user_name UNUSED,
const char *group_name UNUSED)
{
die("--user not supported on this platform");
}
#else
struct credentials { … };
static void drop_privileges(struct credentials *cred)
{ … }
static struct credentials *prepare_credentials(const char *user_name,
const char *group_name)
{ … }
#endif
static int serve(struct string_list *listen_addr, int listen_port,
struct credentials *cred)
{ … }
int cmd_main(int argc, const char **argv)
{ … }